稼働中

(v_08)Python MIME形式のメール件名

MIME

Pythonでいろいろやって見たことを記載しています。※開発環境はThonnyを使用しています。
MIMEエンコードされたメール件名(Subject)のデータをデコードして見ようと思います。

記事(v07)でpopLibを使って受信メールのデータを得ることはできましたが、可読できない部分がありました。
ここでは、MIMEエンコードされたメール件名(subject)を可読できるようにデコードしたいと思います。

MIMEエンコードは
=?<文字コード>?<エンコード方式>?<エンコードされた内容>?=
の形式で記載されています。
そのため「内容(データ)」を「エンコードの方式」でデコードして、「文字コード」でデコードすれば可読できる文字列になりそうです。

文字列の分離

MIMEエンコードの例文として以下を使います。
b’Subject: =?utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F?=’


s='Subject: =?utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F?='

たぶん、もっと良い方法があると思いますが..。
[文字コード, エンコード方式, エンコードされた内容] になるように分離して行きます。


空白文字で分離 | split(' ')
['Subject:', '=?utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F?=']

'?='のある項だけにする | '?=' in
['=?utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F?=']

'?='を消去 | replace('?=','')
'=?utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F'

#'=?'を消去 | replace('=?','')
'utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F'

'?'で分離 | split('?')
['utf-8', 'B', '44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F']

これで、[文字コード, エンコード方式, エンコードされた内容]になりました。

文字列のデコード

エンコード方式’B’ならbase64、’Q’ならquoted-printableだそうです。
可読できる文字列に変換する手順は「エンコードされた内容」を「エンコード方式」でデコード、その値を「文字コード」でデコードします。
msg=’44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F’としてThonnyのShellで確認してみます。

エンコード方式’B’ならbase64なのでbase64モジュールをインポートします。


>>> import base64
>>> msg='44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F'
>>> s=base64.b64decode(msg)
>>> s                               # base64デコードした値
b'\xe3\x82\xa4\xe3\x82\xaa\xe3\x83\xb3\xe3\x82\xb7\xe3\x83\x8d\xe3\x83\x9e
\xe7\x89\xb9\xe5\x88\xa5\xe9\x91\x91\xe8\xb3\x9e\xe5\x84\xaa\xe5\xbe\x85'
>>> s.decode('utf-8')
'イオンシネマ特別鑑賞優待'
>>> 

’44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F’の文字列は’イオンシネマ特別鑑賞優待’になりました。

スクリプト

以下のスクリプトはエンコード方式が’Q’のquoted-printableの場合も加えて一連の処理を記載しています。


mime_subject_01b.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import base64
import quopri

# 例文
bytes_msg=b'Subject: =?utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F?='
s=bytes_msg.decode()  #bytes->moji
sp=s.split(' ')       #'_'で分離 正当なやり方だろうと思う リスト化 

bun=''                #変換した文字列
n=len(sp)             #分離した数
ss=[]         #MIME [moji-code, encode, moji-data]
for i in sp:
    if '?=' in i:     #'?='がある項だけのリストにする
        ss.append(i)
    else:
        bun=bun + i   # subject:など'?='がない文字列

dat=[]
for j in ss:
    j=j.replace('?=','')  #'?='を消去
    j=j.replace('=?','')  #'=?'を消去 ==?はあり得るようなので'?='削除後に削除
    j=j.split('?')        #'?'で分離
    dat.append(j)         #[[moji-code, encode, moji-data],[ b'data-- ]]の形式になる

k=len(dat)
for i in range(k):
    #charset(文字コード)
    chset=dat[i][0]      # charset utf-8, iso-2022-jp, ascii
    #Content-Transfer-Encoding
    ctenc=dat[i][1]      # moji-encode  base64, quoted-printable non 

    msg=dat[i][2]        # massage bytes-moji-data

    if 'B' in ctenc.upper():
        cte='base64'
        b = base64.b64decode(msg)    #b bytedata       
    elif 'Q' in ctenc.upper():    
        cte='quoted-printable'
        b = quopri.decodestring(msg)        
    else:
        cte='non'
        b = msg
   
    line=b.decode(chset, "ignore")
    bun=bun + line   # つなぐ
print(bun)

実行結果

実行した結果例です。※Thonnyのshellに表示されます。
b’Subject: =?utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F?=’は
「Subject:イオンシネマ特別鑑賞優待」になりました。


>>> %Run mime_subject_01b.py
Subject:イオンシネマ特別鑑賞優待
>>> 

まとめ

MIMEエンコードされたメール件名(Subject)をデコードして可読することができました。