Twilio SendGridのトランザクションメールにファイルを添付する方法

はじめに
Gmailなどのメールクライアントでは画面操作で簡単にファイルを添付できますが、Twilio SendGridのWeb APIやSMTPでファイルを添付する場合、ソースコードやコマンドは正しいはずなのに、「ファイルが文字化けしてしまう」「ファイルが破損して開けない」「本文内に画像が表示されない」といった問題にぶつかりがちです。
本記事では、添付ファイルの基礎知識を解説したうえで、Twilio SendGridにおける具体的なファイルの添付方法をご紹介します。トラブルシューティングなどにお役立てください。
添付ファイルの基礎知識
メールで非ASCII文字を扱うための仕組み
登場当時のSMTPでは、ASCII文字(英数字や記号を7bitの数値で表現する文字コード)しか送信できませんでした。これを拡張して、日本語などの非ASCII文字や添付ファイルなど様々なデータを扱えるようにしたのがMIMEです。
MIMEは下図のようなマルチパート構造を持っています。境界線でパートを区切りながらコンテンツを指定すると、異なる種類のデータを一緒に送信できます。

MIMEの各パートには以下のようなヘッダ情報が含まれます。
- Content-Type:データの種類(「text/html」「application/pdf」など)
- charset:文字コード(「UTF-8」「ISO-2022-JP」など)
- 添付ファイルのエンコード方式(「Base64」「Quoted-printable」など)
これらのヘッダ情報は、宛先側で受け取ったデータを正しく解釈するために使われます。
添付ファイルのエンコード
画像や音声などのコンテンツは、0と1の2進数で構成された8bitのバイナリデータです。もともとメールの世界では7bitのデータのみを扱っていたため、8bitのデータはそのままでは正しく解釈できず、ファイルが破損することがあります。そこで、バイナリデータをBase64でエンコードし、メールサーバで扱いやすいASCII文字列に変換したうえで送信します。
他のエンコード方式としてquoted-printableもありますが、これは主に非ASCII文字のテキストのエンコードに利用されます。添付ファイルの場合はBase64を使いましょう。
添付ファイルの表示方法
添付ファイルの表示方法には「attachment(下図左)」と「inline(下図右)」があります。受信側でattachmentのファイルを表示するには、ダウンロードする、ファイルを開くといった何らかのアクションが必要です。一方、inlineのファイルは自動的に本文内に表示されます。本文内に画像を埋め込む場合などに使われます。

SendGridで添付ファイルを送信する方法
添付ファイルの基礎知識を得たところで、実際にSendGridで試してみましょう。
ファイルをBase64エンコードする
事前準備として、添付したいファイルをBase64エンコードします。以下のように、OSの標準機能を利用して簡単にエンコードできます。
<Windowsの場合>
コマンドプロンプトでcertutilコマンドを実行してエンコードします。
certutil -encode 入力ファイル名 出力ファイル名
<macOSやLinuxの場合>
ターミナルでbase64コマンドやopensslコマンドを実行してエンコードします。
base64 -i 入力ファイル名 > 出力ファイル名
openssl base64 -in 入力ファイル名 -out 出力ファイル名
「入力ファイル名」には、PDFファイルや画像など、エンコードしたいファイル名を指定します。「出力ファイル名」には「output.txt」など任意のテキストファイル名を指定します。コマンドを実行すると、エンコード結果の文字列が出力されます。これをコピーしてメール送信で利用します。
SendGridで添付ファイルを送信する
初めてSendGridを使う方は、APIキーの作成(Mail SendのFull Access権限があれば問題ありません)や送信元ドメインでのDomain Authenticationの設定を行ってください。準備ができたら、以下を参考に「PDFファイルを添付し、画像をインライン表示するメール」を送信してみましょう。
<Web APIの場合>
Mail Send APIのリクエストボディで、以下のようなJSON文字列を指定します。
{
"personalizations": [
{
"to": [
{ "email": "to@example.com" }
],
"subject": "添付ファイルのテスト"
}
],
"from": { "email": "from@example.com" },
"content": [
{
"type": "text/html",
"value": "添付ファイルのテストです。<br /> <img src='cid:image01' /><br />株式会社構造計画研究所 SendGridサポートチーム"
}
],
"attachments": [
{
"type": "application/pdf",
"filename": "test.pdf",
"disposition": "attachment",
"content": "PDFファイルをBase64エンコードした文字列"
},
{
"type": "image/png",
"filename": "test.png",
"disposition": "inline",
"content_id":"image01",
"content": "PNGファイルをBase64エンコードした文字列"
}
]
}
attachments配列の要素として、PDFファイルとPNGファイルを指定します。contentパラメータでは、先ほどBase64エンコードした文字列を指定します。PNGファイルで指定したcontent_idはコンテンツの識別子で、本文内にそのコンテンツをインライン表示する位置を決めるために使います。上の例では、HTMLパートの<img src='cid:image01' />の部分に画像が表示されます。
<SMTPの場合>
以下のようなtelnetコマンドを実行します。「>」で始まる行はご自身で入力してください。その他の行はサーバからの応答です。
telnet smtp.sendgrid.net 587 > EHLO example.com 250-smtp.sendgrid.net 250-8BITMIME 250-PIPELINING 250-SIZE 31457280 250-SMTPUTF8 250-STARTTLS 250-AUTH PLAIN LOGIN 250 AUTH=PLAIN LOGIN > auth login 334 VXNlcm5hbWU6 > “apikey”をBase64エンコードした文字列 334 UGFzc3dvcmQ6 > APIキーをBase64エンコードした文字列 235 Authentication successful > mail from: from@example.com 250 Sender address accepted > rcpt to: to@example.com 250 Recipient address accepted data 354 Continue From: from@example.com To: to@example.com Subject: =?UTF-8?B?件名をMIMEエンコードした文字列 Content-Type: multipart/related; boundary=b123456789 --b123456789 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: base64 本文のHTMLをBase64エンコードした文字列 --b123456789 Content-Type: application/pdf; name="test.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="test.pdf" PDFファイルをBase64エンコードした文字列 --b123456789 Content-Type: image/png; name="test.png" Content-Transfer-Encoding: base64 Content-Disposition: inline; filename="test.png" Content-ID: <image01> PNGファイルをBase64エンコードした文字列 . 250 Ok: queued as xxxxx
境界線(バウンダリ、上の例では「b123456789」)でMIMEのパートを区切りながら、本文・PDFファイル・PNGファイルのパートを指定します。メールの件名や本文、ファイル名に非ASCII文字を含む場合はエンコードが必要です。
<届いたメールを確認する>
届いたメールを確認してみましょう。以下のように本文内にPNGファイルが表示され、PDFファイルが添付されていることを確認できました。

添付ファイルの制限事項
宛先サーバによって制限事項は異なりますが、一般的なメッセージサイズの上限(ヘッダ+ボディ+添付ファイル)は20MBです。SMTPでメール送信する場合は、この上限を超えないようにしましょう。Web APIでメール送信する場合、リクエスト可能なメッセージサイズの上限は30MBです。詳しい制限事項はこちらをご覧ください。
サイズが大きいファイルを添付したい場合は、外部のストレージにファイルをアップロードし、メール本文にそのリンクを記載する方法がお勧めです。
まとめ
本記事では、SendGridのトランザクションメールにファイルを添付するために必要な、MIMEやエンコードといった基礎知識から、Web APIとSMTPを使った具体的な送信方法までを解説しました。
トランザクションメールにファイルを添付できるようになると、書類の自動送付や、インライン画像を使った動的なデザインといった様々なユースケースに対応できます。ただし、添付ファイルそのものが迷惑メール判定のリスクにもなり得ますので、適切な内容やサイズのコンテンツを送るように心がけましょう。


