5
5

More than 3 years have passed since last update.

Pythonでメールを受信する

Last updated at Posted at 2021-01-24

プログラムで自動でメールを処理したい時があったので、その時のメモ。
以下では全て、動作環境は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文内で判別させるしかなさそうです。

参考

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5