Pythonを使ってメールファイルを読み込みたい!
このような方に向けて、拡張子.eml
ファイルの読み込み方をご紹介します。
eml ファイルとは、電子メールのメッセージを保存するためのファイル形式です。
ファイルの中には以下のような情報が含まれています。
- 送信者情報
- 受信者情報
- 件名
- 本文
- 添付ファイル
Python には email という標準ライブラリが用意されていて、これを使えば eml ファイルを読み込むことができます。
eml ファイルを読み込む方法
「eml ファイルを読み込む」ということを分解すると、次のようなステップに分けられます。
- eml ファイル全体を読み込む
- 送信者情報、件名などの要素を取得する
- 本文を取得する
それぞれ順番に解説していきます。
1. eml ファイル全体を読み込む
まずは eml ファイルを、Python で扱えるオブジェクトとして読み込みます。
from email import policy
from email.parser import BytesParser
def read_email(eml_file_path):
"""
emlファイルを読み込む
"""
with open(eml_file_path, mode="rb") as f:
msg = BytesParser(policy=policy.default).parse(f)
return msg
この read_email() 関数の引数として、拡張子が .eml のファイルパスを渡してあげればパースできます。
戻り値の msg は、Message オブジェクトです。
アノテーションをつけるなら、以下のような書き方になります。
from email import policy
from email.message import Message
from email.parser import BytesParser
def read_email(eml_file_path: str) -> Message:
"""
emlファイルを読み込む
"""
with open(eml_file_path, mode="rb") as f:
msg = BytesParser(policy=policy.default).parse(f)
return msg
2. 送信者情報、件名などの要素を取得する
1. で取得した Message オブジェクトから、以下の情報を取得していきます。
- 送信者メールアドレス
- 受信者メールアドレス
- 件名
- CC
- 送信日時
- メールごとに振られたユニークな識別子
Message オブジェクトは辞書のような方法でアクセスできます。
取得例は以下の通り。
# 送信者メールアドレス
from_ = msg.get("From", None)
# 受信者メールアドレス
to = msg.get("To", None)
# 件名
subject = msg.get("Subject", None)
# CC
cc = msg,get("CC", None)
# 送信日時
date = msg.get("Date", None)
# メールごとに振られたユニークな識別子
message_id = msg.get("Message-ID", None)
もちろん通常の辞書と同様msg["From"]
のような形でも取り出せますが、上記では取得できなかったときのためにget()
メソッドにNone
を明示しておくことで、安全にアクセスできるようにしました。
なお、メールアドレスはname<sample@name.com>の形式になることがあります。
これを「名前部分」と「純粋なメールアドレス部分」を分けて取得したい場合にはparseaddr()メソッドを使って分離しましょう。
def divide_name_and_mailaddress(mailaddress):
"""
フルメールアドレス, 純粋なメールアドレス部分を分ける
"""
try:
return [parseaddr(mailaddress)[0], parseaddr(mailaddress)[1]]
except Exception:
return None
3. 本文を取得する
本文の取得には、一工夫が必要です。
大前提として、メールファイルには次の2種類があります。
- シングルパート
- マルチパート
それぞれ簡単に説明します。
まずシングルパートは、ただのテキストだけからなるシンプルな構成のものです。
一方のマルチパートは、テキストとHTMLが混在していたり、テキストの他に添付ファイルを含む場合にあたります。
つまり色々なコンテンツがある場合にはマルチパート、単一のコンテンツのメールならシングルパートということになります。
メール本文を読み込むには、マルチパートかシングルパートかを場合分けして処理する必要があるので、以下のように条件分岐を組んで取り出します。
def get_email_body(msg: Message) -> str:
"""
メール本文を取得する
"""
if msg.is_multipart():
# マルチパートメールの場合
# つまり、添付ありやHTML形式のメールの場合
for part in msg.walk():
# コンテントタイプを取得
content_type = part.get_content_type()
# Content-Dispositionヘッダの内容を取得する
content_disposition = str(part.get("Content-Disposition"))
if content_type == "text/plain" and "attachment" not in content_disposition:
payload = part.get_payload(decode=True)
detected = chardet.detect(payload)
encoding = (
detected["encoding"]
if detected["encoding"] is not None
else "utf-8"
)
# エラーの場合は文字化けしてでも文字列を出力
return payload.decode(encoding, errors="replace")
else:
# メールの内容を取得
payload = msg.get_payload(decode=True)
# エンコード方式を確認
detected = chardet.detect(payload)
# 得られたエンコード方式がnoneならutf-8を、そうでなければ得られたものを採用
encoding = detected["encoding"] if detected["encoding"] is not None else "utf-8"
# エラーの場合は文字化けしてでも文字列を出力
return payload.decode(encoding, errors="replace")
まとめ
emlファイルから情報取得する流れは以下の通りです。
- emlファイルをMessageオブジェクトとして取得する
- 欲しい情報を辞書のような形で取り出す
- 本文はマルチパート、シングルパート別に処理を変える
この流れをおさえた上で本記事の内容を参考にしていただければ、メールデータを簡単に取り出せるはずです。
ご不明な点などありましたら、コメント欄にメッセージいただければご回答させていただきます。
コメント