17
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Pythonでメール受信; imaplibのサンプルコード

Posted at

関連リンク

処理の流れ

  1. IMAP4クライアントインスタンスを作成する
  2. IMAP4サーバにログインする
  3. メール受信(MIMEメッセージを受信)

サンプルコード

import email
import ssl
import imaplib
from email.header import decode_header, make_header
# https://docs.python.jp/3/library/imaplib.html
# [参考]https://qiita.com/ekzemplaro/items/a35e15865d57372f1d2b
# https://docs.python.jp/3.6/library/email.message.html
# https://docs.python.org/ja/3.7/library/email.compat32-message.html#module-email.message
# https://docs.python.jp/3.6/library/email.parser.html


"""
(1) IMAP4クライアントインスタンスを作成する
* Gmail, Yahoo!メールともに nego_combo = ("ssl", 993)
  - 143ポートが暗号化なし
  - 暗号化なしとSTARTTLSは動作確認できるサーバがなかった(コードが正しいかも不明)
"""
host = "imap.mail.yahoo.co.jp"
nego_combo = ("ssl", 993) # ("通信方式", port番号)

if nego_combo[0] == "no-encrypt":
	imapclient = imaplib.IMAP4(host, nego_combo[1])
elif nego_combo[0] == "starttls":
	context = ssl.create_default_context()
	imapclient = imaplib.IMAP4(host, nego_combo[1])
	imapclient.starttls(ssl_context=context)
elif nego_combo[0] == "ssl":
	context = ssl.create_default_context()
	imapclient = imaplib.IMAP4_SSL(host, nego_combo[1], ssl_context=context)
imapclient.debug = 3  # 各命令をトレースする

"""
(2) IMAP4サーバにログインする
"""
username = "username@yahoo.co.jp"
password = "password"
imapclient.login(username, password)


"""
(3) メール受信(MIMEメッセージを受信)
"""
imapclient.select() # メールボックスの選択
typ, data = imapclient.search(None, "ALL")  # data = [b"1 2 3 4 ..."]
datas = data[0].split()
fetch_num = 5  # 取得したいメッセージの数
if (len(datas)-fetch_num) < 0:
    fetch_num = len(datas)
msg_list = []  # 取得したMIMEメッセージを格納するリスト
for num in datas[len(datas)-fetch_num::]:
    typ, data = imapclient.fetch(num, '(RFC822)')
    msg = email.message_from_bytes(data[0][1])
    msg_list.append(msg)
imapclient.close()
imapclient.logout()


"""
受信したメール(MIMEメッセージ)の確認
"""
for msg in msg_list:
    print(msg)


"""
各ヘッダや本文を取得する
"""
for msg in msg_list:
    # 各ヘッダ情報はディクショナリのようにアクセスできる
    from_addr = str(make_header(decode_header(msg["From"])))
    subject = str(make_header(decode_header(msg["Subject"])))

    # 本文(payload)を取得する
    if msg.is_multipart() is False:
        # シングルパートのとき
        payload = msg.get_payload(decode=True) # 備考の※1
        charset = msg.get_content_charset()    # 備考の※2
        if charset is not None:
            payload = payload.decode(charset, "ignore")
        print(payload)
        print()
    else:
        # マルチパートのとき
        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")
            print(payload)
            print()



"""備考
※1 get_payload(decode=True)について
    cte = msg["Content-Transfer-Encoding"]や
    cte = part["Content-Transfer-Encoding"]
    でContent-Transfer-Encodingヘッダを取得してデコード方式を決定しても良いが、
    get_payload()のdecode引数をTrueにすると、
    Content-Transfer-Encodingヘッダに従って勝手にデコードしてくれる。
    ただしデコードしてくれるのはquoted-printable または base64のときのみで、
    それ以外の場合(別のエンコード方式や、ヘッダがない場合、ペイロード部が
    bogus dataを持っている場合 (i.e. bogus base64 or uuencoded data))のときはそのまま返す。
    * bogus dataって何だ?
      - MAILER-DAEMON@yahoo.co.jpのメールがデコードしきれずにpayloadがバイト列になったので、
        そういうのを指すのかもしれない。

※2 get_content_charset()について
    charsetがない不親切なメールがたまにあるので注意。
    気合でデコードするしかないが、今回のサンプルコードはそのようなメールは考慮していない。
"""
17
31
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
17
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?