※注意
- 最新版のPythonだと解消されているようですので3.4以前をご利用のかた向けです。
- 以前の記事の補足です。
- 取得、エンコードをしているソースコードは以前の記事をどうぞ
現象
Pythonの標準ライブラリ"email"を使って日本語が含まれているメールの差出人名(From)を取得した際に、「たまにだけ」デコードできない状態で取得される。
例:
”日本語名 <xxxx@test.com>” という差出人名の場合
正常の場合 | データ | 文字コード |
---|---|---|
名前部分 | ?ISO-2022-JP?B?Re5LEJeS……QKI=?= | iso-2022-jp |
アドレス部分 | <xxxx@test.com> | - |
たまにエラー | データ | 文字コード |
---|---|---|
名前部分 | ?ISO-2022……QK<txxxx@test.com>I=?= | - |
正常の場合は名前部分を文字コードにしたがってエンコードすれば日本語名を取得できます。
たまに起こるのが、エンコードされた文字列がそのままメールアドレスとひっついてbyte型(デコードできない)で取得されてしまう現象です。
原因と対処
メールのヘッダ部分(差出人や件名)の部分を判定して取得する機能はemailライブラリを構成するheader.pyにあります。
この中で差出人部分がエンコードされた文字であるかが判定され、データを分解して取得しています。
そこの判定部分がこちら
# Match encoded-word strings in the form =?charset?q?Hello_World?=
ecre = re.compile(r'''
=\? # literal =?
(?P<charset>[^?]*?) # non-greedy up to the next ? is the charset
\? # literal ?
(?P<encoding>[qb]) # either a "q" or a "b", case insensitive
\? # literal ?
(?P<encoded>.*?) # non-greedy up to the next ?= is the encoded string
\?= # literal ?=
(?=[ \t]|$) # whitespace or the end of the string
''', re.VERBOSE | re.IGNORECASE | re.MULTILINE)
コメントの通り、=?charset?q?・・・?= の形になっているかを判定するための正規表現です。こうなっていたら何かしらエンコードされている文字列です。
上記の現象が起きる原因は文字の最後(?=[ \t]|$
)を判定している部分でした。殆どの場合はこれでよいのですが、一番最後に改行コードが混ざるメールがたまにあり、その場合、エンコードされていると判定されませんでした。
なので、
(?=[ \t\r\n]|$) # whitespace or the end of the string
としておくと対処できます。