Thunderbirdに届いたメールを処理する

Thunderbirdで受け取ったメールは mbox 形式という標準的なファイル形式で保存されていて、pythonの基本ライブラリだけでメールの内容を読み取って処理することが出来ます。その基本的な手順を記します。

Thudirbirdのプロファイルフォルダの確認

まず、Thundirbirdのメールのファイルがどこに保存されているのかを調べます。Windows系だと次のフォルダ以下に保存されています。

%APPDATA%\Thunderbird\Profiles\

(%APPDATA%はWindowsのユーザ名毎の環境変数)このフォルダの下に通常は、”ランダム文字列.default”というフォルダが有ります。さらに、その下に
Mail\"メールサーバ名”\"Thunderbird上のフォルダ名"
という名前のファイルが有り、それがメールメッセージを収めたmbox形式のファイルです。「受信フォルダ」の場合ファイル名は”Inbox”になります。拡張子がある”フォルダ名.msf”というファイルも有りますが、これはおそらく各mboxへのインデックスファイルで、メール本体ではありません。Thunderbird内でサブフォルダがある場合は、*.sbd という拡張子がついた名前のサブフォルダがあり、メールデータは
Mail\"メールサーバ名”\"Thunderbird上のフォルダ名".sbd\"サブフォフォルダ名"
というパスのファイルになります。

メールデータ読み出し手順

 ざっくりというと

  1. mailboxパッケージを使ってmboxファイルをオープン
  2. mbox内から取り出したいメッセージを探す
  3. メッセージのヘッダやメッセージ本体を取り出す
  4. 取り出したヘッダやメッセージをデコードし、内容に応じて所望の処理をする。

となります。以下順を追って説明します。ここでは、簡単のために受信フォルダ(Inbox)のメールを処理してみます。

mboxファイルをオープンする。

mailboxパッケージのmbox関数を受信フォルダのmboxファイルを指定して実行し、Mailboxクラスオブジェクトを得ます。

import mailbox
mail_box = mailbox.mbox("プロファイルフォルダ名/Mail/メールサーバ名/Inbox")

各メッセージ毎にループする

Mailboxクラスのkeys()関数を呼び出してメッセージのキーのリストを受け取り、ループ。

for key in mail_box.keys():

キーを使って、ヘッダやメッセージにアクセス

a_msg = mail_box.get(key)

mboxの各メールの先頭にあるFrom文字列を取り出す

from_str = a_msg.get_from()

From行文字列とは、”- %a %b %d %H:%M:%S %Y”形式の文字列。メールの送信元を表す文字列ではない。この文字列でメーラがメールを取り込んだ時間が分かる。

メッセージのヘッダをデコードする

SubjectヘッダのMIME文字列をデコードする時には、email.header::decode_header関数をつかう。このとき、各メールヘッダの情報はリストで返る。おそらく複数行になった場合に複数要素のリストとして返ってくる。

from email.header import decode_header
for bstr,enc in decode_header(a_msg['Subject']) :
if enc == None:
  usbj += bstr.decode("ascii", "ignore")
else:
  usbj += bstr.decode(enc, "ignore")
 

メッセージの本文をデコードする

電子メールのデータは、メール本文や添付ファイルなど複数のメディアで構成されていて、それが各メディア毎にMIME方式でエンコードされています。メール本文を処理したいなら異本文部分だけを取り出し、デコードしなくてはなりません。具体的には、マルチパート形式のメッセージの中からtextパートを探し、get_content_charset関数でそのパートの文字エンコードを確認してpython文字列の標準エンコードのunicodeにデコードします。少し苦労したのは、メール自身がshift_jisだと宣言するメッセージは、get_content_charset関数では文字エンコードを確認出来無いことが有り、そのフォローを入れたのとその際、メール本文には正式なshift_jisだけでなくMS拡張の文字が含まれることが有るので強制的にcp932としてデコードしないと、知らない文字がある!とpython がエラーとすることがあります。

for aa_msg in a_msg.walk():
  if not 'text' in aa_msg.get_content_type():
   continue #"text"パートでなかったら次のパートへ
  if aa_msg.get_content_charset() :
    a_text = aa_msg.get_payload(decode=True).decode(aa_msg.get_content_charset(), "ignore")
  else:
   if "charset=shift_jis" in str(aa_msg.get_payload(decode=True)):
    #ひとまず シフトJISだけ特別対応。
    a_text = aa_msg.get_payload(decode=True).decode("cp932", "ignore")
   else:
    print ("** Cannot decode.Cannot specify charset ***"+msg.get("From"))
    continue

終わりに

電子メールのデータはいろんなパターンがあって、結構苦労しました。でも、メールボックスファイルのフォーマットや、デコードなどの手続きのほとんどをpythonの標準ライブラリがやってくれたので非常に楽しく作業できました。上記のコードをつなげて、Inboxにあるメッセージを順番に読み取りFrom文字列、サブジェクト、メール本文テキスト部を主力するコードを下記に載っけておきます。