Python でメールを取得 (IMAP)

Python を使って IMAP サーバからメールを取得する方法です。

サンプルコード

以下のリンクのとおりです。

IMAP4 の使用例 から転載

import getpass, imaplib

M = imaplib.IMAP4()
M.login(getpass.getuser(), getpass.getpass())
M.select()
typ, data = M.search(None, 'ALL')
for num in data[0].split():
    typ, data = M.fetch(num, '(RFC822)')
    print('Message %s\n%s\n' % (num, data[0][1]))
M.close()
M.logout()

imaplib search の補足

IMAP4.search(charset, criterion[, ...])

criterion にセットするのは、RFC3501 section 6.4.4に記載の search keys と思われます。

search が返すのは、(‘OK’, [b'1303 1302 1301 1300 1298 1297 1296’]) のようなデータです。そのため、data[0].split() のようにしてメッセージ番号をリストにしています。

imaplib sort

sort というメソッドもあり、search 結果を並べかえてくれます。

IMAP4.sort(sort_criteria, charset, search_criterion[, ...])

となっていますが、「sort_criteria のリストを丸括弧で囲ったもの」です。sort_criterial は、RFC5256 3.Additional Commands に記載のものと思われます。

例えば、’(REVERSE DATE)’ などを指定します。

imaplib fetch の補足

IMAP4.fetch(message_set, message_parts)

となっています。第2引数はFETCH Commandに記載されています。

fetch すると、既読に変わります。

未読のままにしたければ、上の例だと、M.fetch の後ろに

M.store (num, '-FLAGS', '\\Seen')

とすると、未読に戻ります。

M.store の引数も RFC を見ないとわかりません。

imaplib fetch で取れるメッセージ

('OK', [(b'1303 (FLAGS (\\Seen NonJunk) RFC822 {3714}', b'メールの中身', b')'])

のような感じで返ってきます。

そのため、data[0][1]のようにして本文にアクセスしています。

from を取りたければ、

import email
:
中略
:
msg = email.message_from_bytes(data[0][1])

として変数に代入したなら、

msg['From']

でアクセスできます。

From や Subject など、=?UTF-8?B?〜?= のような形式なっていることがあり、以下のような関数を作って元に戻しました。

def decode_header(raw_header):
        ret = []
        for h, enc in email.header.decode_header(raw_header):
                if enc is None:
                        if isinstance(h, str): # str で返ってくることもある?よくわからん。
                                ret.append(h)
                        else:
                                ret.append(h.decode('ascii'))
                else:
                        ret.append(h.decode('utf-8'))
        return ' '.join(ret)

日付は、

import email.utils
:
中略
:
dt = email.utils.parsedate_to_datetime(msg['Date'])

のようにしてやれば、datetime オブジェクトとして取得できます。

応用

定期的にループして、Unseen メールを取得し、前回チェックした時以降のものであれば、slack の #general チャンネルに post する、などとすれば、新規メールを slack で通知できるでしょう。(そういう slack アプリはあるので、自分でやるのは、単なる勉強の意味合いしかありませんが)

1969年生まれ。大学卒業後から15年以上にわたり、通信、カードリーダ、セキュリティ業界においてソフトウェア開発に従事。その後、2012年5月に当社を設立。電力、交通、車載向けの組み込み系システム、旅行業界向けの WEB システム開発、音声合成システム、消防向けのシステム開発等に参画。
低コストかつシンプルで安定稼働するシステムの実現を目指し、アーキテクチャ設計に取り組んでいます。
会社情報と代表者守屋のプロフィール詳細