メール本文のデコード処理の流れ
受信したメールのメッセージには、Content-Transfer-EncodingヘッダとContent-typeヘッダが記載されています。
デコード処理の流れとしては、まずContent-Transfer-Encodingヘッダを見てデコードし、次にContent-typeヘッダのcharsetを見て更にデコードします。
Content-Transfer-Encodingの種類
- base64
- quoted-printable
- その他(7bit, 8bit, binary)
早い話、base64とquoted-printableの場合のみそれぞれの方式でデコードし、その他の場合は何もしなくて良いです。
charsetの種類
- iso-2022-jp
- utf-8
- その他
iso-2022-jpとutf-8の場合はそれぞれの方式でデコードします。その他と書きましたが、例えば中国のフリーメールとか使うとISO-8859-1とかあります。
charsetが無い場合もあるようです。その場合、メール body部に使用されている文字コードを推測して変換するなどの対応が必要です。
以下の例ではその他を適当にasciiでデコードしています。
コード例
以上の流れをpythonで書くと、次のようになります。
def decode_msg(msg, cte, charset):
""" メール本文をデコードする
* msg
- メール本文(バイナリ形式)
* cte(Content-Transfer-Encoding)
- "base64"
- "quoted-printable"
- それ以外は、そのまま
* charset(文字コード)
- "utf-8"
- "iso-2022-jp"
- それ以外は、"ascii"とみなす
"""
import quopri
import base64
if cte == "base64":
b = base64.b64decode(msg)
elif cte == "quoted-printable":
b = quopri.decodestring(msg, header=False)
else:
b = msg
if charset == "iso-2022-jp":
return b.decode("iso-2022-jp", "ignore")
elif charset == "utf-8":
return b.decode("utf-8", "ignore")
else:
return b.decode("ascii", "ignore")
SubjectヘッダやFromヘッダのデコード処理の流れ
Subjectヘッダ(件名)やFromヘッダ(送信元)は本文とは別でエンコーディングされています。どのような形で送られてくるかというと、
?[文字コード]?[Content-Transfer-Encoding]?[メッセージ]
という形になっています(基本は)。
結構ややこしく、例を以下に列挙します。
文字コードがUTF-8で、Base64変換されている場合
b"From: =?UTF-8?B?44CQQVdTIOOCp...?="
文字コードがiso-2022-jpで、Base64変換されている場合
b"From: =?iso-2022-jp?B?GyRCMlRG...?="
文字コードがUTF-8で、quoted-printable変換されている場合
b"Subject: =?UTF-8?Q?=E3=80=90=E3=83=A4=E3=..."
ただのバイナリ(ascii)
b"From: "tanaka@example.com" <yamada@example.com>"
文字コードがiso-2022-jpで、Base64変換されているが、2つ目の送信元はただのバイナリ
b"From: =?iso-2022-jp?B?GyRCPF...==?= <tanaka@example.com>"
複数行に跨っている(folding)
b"From: =?iso-2022-jp?B?GyRCQmdOUxsGyhCTktFGyRCM3Q8MDJxGyhC...?=
=?iso-2022-jp?B?GyRCPFIhQg...==?= <tanaka@example.com>"
全てに対応させるには気合が必要です。
と思ったら、Linuxコマンドで一撃でデコードできるっぽいです。
https://qiita.com/sheepland/items/2065ffcc7ec8c03145cc
備考
日本ではiso-2022-jp(JIS)がいまだに根強く使われています(大手新聞社やIT企業のメールでも使われています)。調べた感じ、ガラケーがまだ現役だからが主な理由のようです。
果たして自分がメールを送信するときにiso-2022-jpを選ぶかUTF-8を選ぶか悩みどころですが、ガラケーを気にしないのであればUTF-8で良いと思います。