これは Postfix Advent Calendar 2014 の6日目の記事です。
その昔、電子メールは 7bit データでした。
日本語は ASCII の範囲におさまらないのですが、ISO-2022-JP*1にエンコードすることで 7bit になるので、日本語でメールする人たちはそのようにしてました。今でも日本語を扱うメールアプリのデフォルトのエンコーディングは ISO-2022-JP になってることが多いと思います。
ただしヘッダの From や To フィールドには規格上 ISO-2022-JP は書けないので、メールアドレスの表示名には日本語は使えませんでした。
余談ですが、メール本文の冒頭で自分の名前を名乗る日本の風習は From に日本語で名前が書けなかったためじゃないかと、個人的に妄想してます。
バイナリデータは uuencode 等でテキストに変換して、メール本文に貼り付けて送ったものでした。
その後 MIME という規格ができて、メールヘッダにも ASCII 以外の文字列を記述できたり、メールにファイルを添付することができるようになり、便利に使えるようになりました。*2
MIME では本文中の 8bit 文字を ISO-2022-JP のような 7bit に変換しなくてもそのまま記述できます。ただし、ヘッダに Content-Transfer-Encoding: 8bit
の記述が必要です。*3
UTF-8 のテキストをそのまま埋め込んだメールデータは次のようになります。あいかわらずヘッダ中では 8bit 文字は書けないので、Subject はエンコーディングしています(この例では「テスト」)。
Subject: =?utf-8?b?44OG44K544OI?= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit 本日は晴天なり
8bit メールは新しい規格なので(と言っても20年くらい前ですが)、相手がちゃんと処理できるかどうかわかりません。
SMTP の EHLO 命令に対する応答に 8BITMIME が含まれてれば対応しています。Postfix は対応しています。
EHLO hoge 250-x220 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-ENHANCEDSTATUSCODES 250-8BITMIME ★ 250 DSN
Postfix が 8bit メールを配送する時に相手が対応していない場合はどのようになるのか試してみます。
master.cf を次のようにします。
smtp inet n - - - - smtpd -o content_filter=smtp:localhost:10025 10025 inet n - - - - smtpd -o smtpd_discard_ehlo_keywords=8BITMIME
25番ポートでうけつけたメールを 10025番ポートに中継しますが、10025番ポートの Postfix は EHLO に 8BITMIME を返しません。
この状態で 25番ポートに先ほどのメールを送信すると、最終的に届いた内容は次のようになりました。
Subject: =?utf-8?b?44OG44K544OI?= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable ★ =E6=9C=AC=E6=97=A5=E3=81=AF=E6=99=B4=E5=A4=A9=E3=81=AA=E3=82=8A ★
10025番ポートで動いている MTA が 8BITMIME を返さなかったので、25番ポートの Postfix が本文部のエンコーディングを 8bit から quoted-printable に変換して送信しました。
テキストを添付した次のメールを送ると、
Subject: txt attached Content-Type: multipart/mixed; boundary=123456789 --123456789 Content-Type: text/plain Content-Transfer-Encoding: 7bit ASCII BODY --123456789 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit 本日は晴天なり --123456789--
該当パートだけ quoted-printable になります。
Subject: txt attached Content-Type: multipart/mixed; boundary=123456789 --123456789 Content-Type: text/plain Content-Transfer-Encoding: 7bit ASCII BODY --123456789 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable ★ =E6=9C=AC=E6=97=A5=E3=81=AF=E6=99=B4=E5=A4=A9=E3=81=AA=E3=82=8A ★ --123456789--
メールを添付した次のメールを送ると、
Subject: eml attached Content-Type: multipart/mixed; boundary=123456789 --123456789 Content-Type: text/plain Content-Transfer-Encoding: 7bit ASCII BODY --123456789 Content-Type: message/rfc822 Content-Transfer-Encoding: 8bit Subject: =?utf-8?b?44OG44K544OI?= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit 本日は晴天なり --123456789--
添付パートの Content-Transport-Type と、添付されたメールの本文が変換されます。
Subject: eml attached Content-Type: multipart/mixed; boundary=123456789 --123456789 Content-Type: text/plain Content-Transfer-Encoding: 7bit ASCII BODY --123456789 Content-Type: message/rfc822 Content-Transfer-Encoding: 7bit ★ Subject: =?utf-8?b?44OG44K544OI?= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable ★ =E6=9C=AC=E6=97=A5=E3=81=AF=E6=99=B4=E5=A4=A9=E3=81=AA=E3=82=8A ★ --123456789--
添付されたメールを丸ごと quoted-printable にしないのは、Content-Type: message/rfc822
に指定できる Content-Transfer-Encoding
は 7bit, 8bit,binary のいずれかだと決められているためです。
このように Postfix は配送先が 8bit メールを受け取れるかどうかによってメールの中身を変換することがありますが、main.cf に disable_mime_output_conversion = yes
を設定するとこの 8bit → quoted-printable 変換を行いません。
相手が EHLO に 8BITMIME を返さなくても無理やり 8bit のまま送りつけます。
また、メールを受け取るときに Content-Transfer-Encoding: 8bit
がないのに 8bit 文字が入っていた時にエラーにすることもできます。mian.cf に strict_8bitmime_body = yes
を設定します。
この場合、DATA 命令の応答として次のようなエラーを返します。
550 5.6.0 improper use of 8-bit data in message body
この時ログには次のように記録されます。
postfix/cleanup[5085]: 7F3813A6: reject: mime-error improper use of 8-bit data in message body: ????????????????????? from localhost[127.0.0.1]; from=<sender@example.com> to=<rcpt@example.com>