SMTPで送信するメールの形式

「SMTPによるメール送信の仕組み」ではメールを送信するためのプロトコル(SMTP)の話をしましたが、 そこではDATAコマンドで送信するメールの形式については言及しませんでした。 今回は、メールの形式について説明します。

7ビット

基本的にSMTPは7ビットのプロトコルです。 それでやり取りされるメールも7ビットのコードを使用します。 この7ビットであることが、様々な制約を生みメールの形式を複雑にしています。

ヘッダと本文

メールは大きくヘッダと本文に分けられます。
ヘッダは、ヘッダ名と値の対になっておりコロン:で区切られます。

Date: Fri, 29 Sep 2017 14:32:15 +0900

SMTPの1行は1000オクテット(≒バイト)なので、無制限に長くすることはできません。 そのために複数行で表現できるようになっています。 実際には1000オクテットまで伸ばさずに78オクテット程度までで改行します。 複数行のヘッダは、2行目以降は行頭に空白文字を入れることになっています。 (空白文字は、いくつ入れてもかまいません。)

Content-Type: multipart/mixed;
          boundary="94eb2c076a6af4de10055a4bf6e4"

このような形で必要な情報を並べて記述します。

Date: Fri, 29 Sep 2017 14:32:15 +0900
Mime-Version: 1.0
Content-Type: multipart/mixed;
          boundary="94eb2c076a6af4de10055a4bf6e4"
Subject: This is a sample.
From: Mr.From <from@example.com>
To: Who <who@example.com>

ヘッダの最後に改行だけの空行を入れ、それが本文との区切りになります。

Date: Fri, 29 Sep 2017 14:32:15 +0900
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Subject: This is a sample.
From: Mr.From <from@example.com>
To: Who <who@example.com>

ここからが本文

MIMEエンコード

前にメールの形式は7ビットだと述べましたが、ヘッダにはもう1つ制約があります。
ヘッダは表示可能な文字しか使えません。 7ビットでもコントロールコードは使えないのです。 この制約は英語圏の人々には何の影響もありませんが、日本語では大きな問題となります。 日本語でメールをやり取りする場合、7ビットで表現できるISO-2022-JP文字コード(通称JISコード)が長らく使われてきました。 メール本文はISO-2022-JPで記述できますが、ヘッダには記述できないのです。
ISO-2022-JPは英数字と日本語を切り替えるときにコントロールコードであるESC (1B)を使います。 そのために、Subject(件名)に日本語を使うことができません。
はい、そこの人。使っているよ、と思いましたね。
Subjectに日本語を使うことはできます。 そのためにMIMEエンコードと呼ばれる形式で記述します。

Subject: =?ISO-2022-JP?B?GyRCN29MPiRHJDkhIxsoQg==?=

MIMEエンコードは=?に始まり?=に終わります。 途中?で3つのフィールドに分かれます。
1つ目は、文字コード名を表します。 この例ではISO-2022-JPです。
2つ目は、エンコード方法です。 この例ではB (Base64)です。 この他にQ (Quoted Printable)があります。
3つ目がヘッダの情報です。 この例のGyRCN29MPiRHJDkhIxsoQg==をBase64でデコードするとISO-2022-JPで「件名です。」になります。

MIME形式

MIMEエンコードのヘッダについて述べましたが、このMIMEとはMultipurpose Internet Mail Exceptionの略で「多目的インターネットメール拡張」と訳されます。 MIMEエンコードのヘッダも、この拡張の一部です。
MIMEを使用するにはメールヘッダに宣言が必要です。

MIME-Version: 1.0

この1.0はMIMEのバージョンですが1.0しかありません。
MIMEを使うと、本文がどんな形式で記述されているかを明示することができます。

Content-Type: text/plain; charset=UTF-8

この例ではUTF-8コードで本文が記述されています。 UTF-8は8ビットのコードですから、そのままSMTPで送ることができません。 このためにBase64やQuoted Printableで7ビットにエンコードする必要があります。 どのようにエンコードしたかもヘッダに記述します。

Content-Transfer-Encoding: base64

このようにして、1つのメールが完成します。

Date: Fri, 29 Sep 2017 14:32:15 +0900
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64
Subject: =?UTF-8?B?44KC44GQ44KC44GQ?=
From: =?UTF-8?B?44GP44KN44KE44GO?= <black@example.com>
To: =?UTF-8?B?44GX44KN44KE44GO?= <white@example.com>

44GV44Gj44GN44Gu44GK5omL57SZ44CB44GU55So5LqL44Gq44GB44Gr77yf

文字コード

多くの場合に日本語のメールにはISO-2022-JPの文字コードが使われています。 この文字コードは7ビットなのでSMTPに乗せやすいのですが、古いので使用できる文字に制限があります。 機種依存文字と呼ばれる記号①や半角カナ、絵文字👍などは扱えません。 またSMTPに乗せやすいと言っても、Subject(件名)などのヘッダにそのまま記述できません。 ヘッダに記述するためにはMIMEが必要です。
みなさん普段は意識せずにSubjectやFrom、Toに日本語を使っているのではないでしょうか? それはメーラーがMIME形式にして送受信しています。
今時MIMEに対応していないメーラーなんてありません。 OSはユニコードに対応していてUTF-8を扱えない環境もありません。
そこで、日本語のメールはUTF-8にすることを推奨します。
UTF-8にするとISO-2022-JPでは扱えなかった機種依存文字と呼ばれる記号①や半角カナ、絵文字👍などを扱えます。 また、ISO-2022-JPでは英数字と日本語しか扱えませんが、UTF-8では多言語で表現できます。

こんにちは😊
Hello😊
สวัสดี😊

Customer Mail CloudのEmail Sending APIでは標準でUTF-8のメールを送信します。 (ISO-2022-JP も指定できます。)

HTMLメール

先の例のContent-Typeはtext/plainでした。 これは通常の文字だけのメールです。 表現力が欲しい場合にはHTMLで記述します。 この場合のContent-Typeはtext/htmlになります。 HTMLメールは、文字だけの文面と併用することが多くあります。 このために代替可能なマルチパート形式で両方を記述します。

Content-Type: multipart/alternative; boundary="3fieoiur3omcqiw"

--3fieoiur3omcqiw
Content-Type: text/plain

平文の文面
--3fieoiur3omcqiw
Content-Type: text/html

<html><body>
HTMLの文面
</body></html>
--3fieoiur3omcqiw--

代替可能なマルチパート形式は、Content-Typeがmultipart/alternativeになります。 その後に各パートの区切り文字を指定します。 この例では3fieoiur3omcqiwです。 各パートは、この区切り文字の前に--を追加して区切ります。 最後は更に後ろにも--を追加します。

添付ファイル

添付ファイルもマルチパート形式で表現します。 ただし、HTMLメールと異なりパート間で代替の関係では無いのでContent-Typeはmultipart/mixedになります。
添付ファイルは通常Base64でエンコードします。

Content-Type: multipart/mixed; boundary="3fieoiur3omcqiw"

--3fieoiur3omcqiw
Content-Type: text/plain

平文の文面
--3fieoiur3omcqiw
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-disposition: attachment; filename="attached.data"

ThisIsABase64EncodedData
--3fieoiur3omcqiw--

HTML+添付ファイル

HTMLメールも添付ファイルもマルチパート形式を使用しました。 それでは、HTMLメールに添付ファイルを付けるとどうなるのでしょうか? Content-Typeが異なるので、そのまま並べることはできません。
ダメな形式

Content-Type: multipart/unknown; boundary="3fieoiur3omcqiw"

--3fieoiur3omcqiw
Content-Type: text/plain

平文の文面
--3fieoiur3omcqiw
Content-Type: text/html

<html><body>
HTMLの文面
</body></html>
--3fieoiur3omcqiw
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-disposition: attachment; filename="attached.data"

ThisIsABase64EncodedData
--3fieoiur3omcqiw--

それでは、どのようにするかと言うとマルチパートを重ねます。 まず、multipart/mixedで文面と添付ファイルの形にします。 その文面のパートをmultipart/alternativeにして平文とHTMLを共存させます。
正しい形式

Content-Type: multipart/mixed; boundary="3fieoiur3omcqiw"

--3fieoiur3omcqiw
Content-Type: multipart/alternative; boundary="5uifoesjfoewjof"

--5uifoesjfoewjof
Content-Type: text/plain

平文の文面
--5uifoesjfoewjof
Content-Type: text/html

<html><body>
HTMLの文面
</body></html>
--5uifoesjfoewjof--
--3fieoiur3omcqiw
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-disposition: attachment; filename="attached.data"

ThisIsABase64EncodedData
--3fieoiur3omcqiw--

今回は「SMTPによるメール送信の仕組み」で別の機会にと言ったメール本文のフォーマットの話をお送りしました。

Customer Mail CloudのEmail Sending APIでは、このように入り組んだ構造のメールをAPI 1回で送信することができます。 ぜひ活用をご検討ください。