Gmail APIでメール本文のインライン画像が表示されない?
Gmail APIの users.messages.get でメールを取得し、本文をWebアプリ上に表示する。
一見シンプルに思えるこの処理で、多くの開発者が同じ壁にぶつかる。
本文中に貼り付けられた画像が表示されない。
HTMLソースを確認すると、画像の src 属性に cid:image001.png@01D... のような見慣れない値が入っている。これはメール特有の画像参照方式で、ブラウザ上ではそのままでは解決できない。結果として画像は壊れた状態で表示されるか、[cid:xxx...] という文字列がそのまま本文に現れることになる。
この問題を正しく解決するには、Gmail APIが返すメールデータの構造そのものを理解する必要がある。

Gmail API のリソース MIMEパート構造でインライン画像がどうなっているかを理解する
Gmail APIは、メールのMIME構造を payload.parts としてネストされたツリー構造で返す。
どこに本文や添付画像、インライン画像の情報が入っているかは、メールの構成によって変わる。

主にメールのヘッダーやHTTPレスポンスヘッダーに付与され、ブラウザやメールソフトに対して「そのファイルがどのようなデータ(テキスト、画像、動画など)であるか」を正確に伝える役割を持っています。
| メールの種類 | mimeType |
|---|---|
| テキストだけのシンプルなメール あまりユースケースでないですね、、メールクライアントツールを使用しない場合と考えてよさそう システム通知やCLIツールからの送信に多い、最もシンプルな構造。 payload.body.data に直接本文が入っている。 | payload mimeType: “text/plain” body.data: “本文(base64url)” |
| 一般的なメール(HTML対応) Outlook、Gmail、Thunderbirdなど、ほとんどのメールクライアントから送信されるメールはこの構造になる。 multipart/alternative の中に、プレーンテキスト版とHTML版が並列で格納されている。受信側のクライアントがどちらか読める方を選んで表示する仕組みだが、今どきのクライアントは基本的にHTML版を使う | payload mimeType: “multipart/alternative” parts: [0] mimeType: “text/plain”, body.data: “プレーンテキスト版” [1] mimeType: “text/html”, body.data: “HTML版” |
| 添付ファイル付きメール ファイルを添付すると、 multipart/mixed で全体が包まれ、その中に本文パート(multipart/alternative)と添付ファイルパートが並ぶ。本文は1階層深くなる。 | payload mimeType: “multipart/mixed” parts: [0] mimeType: “multipart/alternative” parts: [0] mimeType: “text/plain”, body.data: “プレーンテキスト版” [1] mimeType: “text/html”, body.data: “HTML版” [1] mimeType: “application/pdf”, filename: “資料.pdf” |
| インライン画像付きメール 本文中に画像を貼り付けたメール、または署名にロゴ画像を含むメールがこの構造になる。 multipart/related がインライン画像と本文をグループ化し、HTML本文は cid: で画像を参照する | payload mimeType: “multipart/related” parts: [0] mimeType: “multipart/alternative” parts: [0] mimeType: “text/plain”, body.data: “プレーンテキスト版” [1] mimeType: “text/html”, body.data: “HTML版(<img src=’cid:xxx’>)” [1] mimeType: “image/png”, filename: “image.png” |
| インライン画像+通常添付ファイル 最も深いネストになるパターン。署名にロゴが入った状態でPDFを添付して送信するような、業務メールでは日常的に発生する構造。本文のHTMLは3階層下に位置する | payload mimeType: “multipart/mixed” parts: [0] mimeType: “multipart/related” parts: [0] mimeType: “multipart/alternative” parts: [0] mimeType: “text/plain” [1] mimeType: “text/html” ← 3階層下 [1] mimeType: “image/png”, filename: “logo.png” [1] mimeType: “application/pdf”, filename: “見積書.pdf” |
text/html パートの探索は再帰的に確認する必要がある
最上位の parts だけを見る実装では、添付ファイル付きやインライン画像付きのメールで本文が取得できない。mimeType が text/html のパートが見つかるまで再帰的に parts を掘る実装が必要になる。

(余談)Content-Type: text/plain と text/html とは
メールの本文がどういう形式のデータかを受信側に伝えるための宣言。
HTTPのContent-Typeと同じ仕組みで、MIME(Multipurpose Internet Mail Extensions)という規格で定義されている。
text/plainは「装飾なしの生テキスト」。
受信側のメールクライアントはそのまま等幅フォントなどで表示する。
太字、色、リンクのクリック、画像の埋め込みなどは一切できない。text/htmlは「HTMLマークアップされたテキスト」。
受信側はブラウザと同じようにHTMLをレンダリングする。<b>,<a href>,<img>,<table>などが使える。現代のメールクライアント(Gmail, Outlook, Apple Mailなど)はほぼすべてHTML表示に対応している。
プレーンテキスト(text/plain)とは何か
プレーンテキストとは、装飾情報を一切持たない純粋な文字列データのこと。
太字もリンクもフォント指定もない。あるのは文字と、制御文字(改行・タブなど)だけ。
制御文字とは、
画面上に「文字」として直接表示されるのではなく、テキストの配置や区切りをコンピューターに指示するための特殊なデータのことです。
改行(Enter)、タブ(Tab)など
cid参照の仕組み
cid は Content-ID の略で、メールのMIME仕様(RFC 2392)で定義された、メール内の添付リソースを参照するためのURIスキーム。
Webでの https:// と同じように、メールの世界では cid: が添付ファイルへのリンクとして機能する。
インライン画像を含むメールのHTML本文には、以下のような記述がある。
<img src="cid:image.png@01DA2B3C.4E5F6A70">
一方、同じメールの添付パートには Content-Id ヘッダーが設定されている。
Content-Type: image/png
Content-Id: <image.png@01DA2B3C.4E5F6A70>
Content-Disposition: inlineメールクライアント(GmailやOutlookなど)はこの cid: と Content-Id を突き合わせて、添付された画像データを本文中に描画する。
ブラウザはこの cid: スキームを解釈できないため、Webアプリ上で表示する場合は開発者が自前で解決する必要がある。
インライン画像をWebアプリ上で表示する方法
基本的なアプローチは、HTML本文中の cid: 参照を data: URI(base64エンコードされた画像データ)に置換することになる。
処理の流れ
- 添付ファイル一覧から
isInline === trueかつcontentTypeがimage/*のものを特定する - 各インライン画像の
contentIdとcontentBytes(base64データ)を取得する - HTML本文中の
src="cid:xxx"をsrc="data:image/png;base64,..."に文字列置換する
const resolveInlineImages = (html: string, attachments: Attachment[]) => {
let resolved = html
attachments
.filter(a => a.isInline && a.contentId && a.contentBytes
&& a.contentType?.startsWith('image/'))
.forEach(a => {
const cid = a.contentId.replace(/^<|>$/g, '')
resolved = resolved.replace(
new RegExp(`src=["']cid:${cid}["']`, 'gi'),
`src="data:${a.contentType};base64,${a.contentBytes}"`
)
})
return resolved
}
Microsoft Graph APIとの違い
同じ「メールの本文と添付ファイルを取得する」という処理でも、Gmail APIとMicrosoft Graph APIではアプローチが大きく異なる。

| Gmail API | Microsoft Graph API | |
|---|---|---|
| 本文の取得 | MIMEパート構造を自前で解析 | body.content に展開済みで格納 |
| 本文の場所 | パターンにより異なる(最大3階層下) | 常に body.content |
| 本文プレビュー | snippet(約200文字) | bodyPreview(約255文字) |
| インライン判定 | パートの headers から自前で判定 | isInline フラグがそのまま使える |
| 画像データ取得 | attachmentId で別途API呼び出し | contentBytes が一覧と一緒に返る |
| cid参照 | text/html パートの body.data 内(base64urlデコード後) | body.content 内にそのまま存在 |
Gmail APIと違い、
Microsoft Graph APIは、MIME構造の解析をAPI側で処理した上でフラットなレスポンスを返す設計になっている。
Microsoftのメールのインライン画像のファイル名について
cidとは
メール本文のHTMLには <img src="cid:image001.png"> のような画像参照が含まれています。これはメール内部でしか通用する識別子で、「このメールに添付されている画像ファイルを参照する」という意味です。ブラウザには解決できないURLなので、画像が表示できず破損アイコンになります。
「メール本文中のインライン画像はCIDというID で参照されており、現状そのIDが未解決のため画像が表示できていません。APIから該当の画像データを別途取得し、表示処理に組み込むことで対応可能です。」
画像キー(
String)から画像データ(BlobSource)へのマッピングを含む JavaScript オブジェクト。これは、htmlBodyパラメータが使用され、これらの画像への参照が<img src="cid:imageKey" />形式で含まれていることを前提としています。
https://developers.google.com/apps-script/reference/gmail/gmail-message?hl=ja
画像をメール本文に直接埋め込むには、HTML 属性の content-ID (CID) を使用します。
https://learn.microsoft.com/ja-jp/azure/communication-services/concepts/email/email-attachment-inline