プログラムで自動でメールを処理したい時があったので、その時のメモ。
以下では全て、動作環境はWindows10とPython3.9、メールはGmailで行っています。
準備(Gmailのみ)
以下はGmailに限った話であって、デフォルトでIMAPを使う設定のメールを使う場合は関係ありません。
現在のGmailでは、デフォルトではIMAPでメール受信は出来なくなっています。
またアカウントのパスワードではメールを使えないので、アプリパスワードを発行して利用します。
プログラム
以下ではメールサーバへ接続、メッセージを検索、取得、それをprintするプログラムです。
メールサーバへ接接続
メールサーバにログインした後、INBOX(受信トレイ)を選択。
import email
import imaplib
from email.header import decode_header, make_header
# メールサーバにログイン
imap = imaplib.IMAP4_SSL("imap.gmail.com", "993")
imap.login("YourMailAddress","ApplicationPassword")
imap.select("INBOX")
さらにメールの送信者がfoo@example.com
のものを選びます。
# 受信トレイからメールアドレスで絞り込み
search_str = 'FROM "foo@example.com"'
head, data = imap.search(None, search_str)
上で選んだものをMIMEメッセージのリストに収めます。
datas = data[0].split()
msg_list = [] # 取得したMIMEメッセージを格納するリスト
for num in datas:
head, data = self.imap.fetch(num, '(RFC822)')
msg = email.message_from_bytes(data[0][1])
msg_list.append(msg)
取り出したMIMEメッセージをデコードして読める形にして、辞書リストに収めます。
decode_msg_list = [] # デコードしたメッセージのリスト
for msg in msg_list:
subject = str(make_header(decode_header(msg["Subject"]))) # タイトル
payload = ""
# シングルパートとマルチパートの振り分け
if msg.is_multipart():
# マルチパート
for part in msg.walk():
payload = part.get_payload(decode=True)
if payload is None:
continue
charset = part.get_content_charset()
if charset is not None:
payload = payload.decode(charset, "ignore")
else:
# シングルパート
payload = msg.get_payload(decode=True)
charset = msg.get_content_charset()
if charset is not None:
payload = payload.decode(charset, "ignore")
decode_msg = {'subject': subject, 'body': payload}
decode_msg_list.append(decode_msg)
for msg in decode_msg_list:
print(msg['subject'])
print(msg['body'])
print文を変えたり、以下の複数検索条件を組み合わせたり、decode_header部分を変えたりすると、検索や他の項目が出力できます。
複数検索条件
AND検索にはなりますが、以下のように複数の条件も可能です。
以下はfoo@example.com
から2021年1月16日に送られたメールを検索する例です。
search_str = 'FROM "foo@example.com" SENTON "16-Jan-2021"'
表示項目を増やす
上ではメールはタイトルと本文しかメールから取得していませんが、それ以外にもメールヘッダの項目は取得できます。
例えば作成日時は以下のように取得できます。
date = str(make_header(decode_header(msg["Date"]))) # メール作成日時
課題
以下のことをやりたいと思っても出来ていないので、現在の課題です。
日本語タイトルでの検索
タイトルで日本語で検索したいけどエラーになります。
search_str = 'HEADER Subject "日本語" FROM "foo@example.com"'
以下のように英語で検索はできます。
search_str = 'HEADER Subject "japanese" FROM "foo@example.com"'
時間指定での検索
以下のようにやるとエラーになります。
search_str = 'FROM "foo@example.com" SINCE "16-Jan-2021 15:00:00"'
時間まで含めた検索が出来ないのは、IMAPの仕様らしいです(RFC幾つだか忘れましたが)。
もしやる時はメールヘッダのDateからfor文内で判別させるしかなさそうです。