import base64
import email
import poplib
import ssl
from email.header import decode_header, make_header
# https://docs.python.jp/3/library/poplib.html
"""
(1) POP3クライアントインスタンスを作成する
* Yahoo!メールの場合
host: "pop.mail.yahoo.co.jp"
nego_combo: ("ssl", 995)
(2021年1月のYahooメールのセキュリティ強化につき110ポートが廃止)
* Gmailの場合
host: "pop.gmail.com"
nego_combo: ("ssl", 995)
"""
host = "pop.gmail.com"
nego_combo = ("ssl", 995) # ("通信方式", port番号)
if nego_combo[0] == "no-encrypt":
popclient = poplib.POP3(host, nego_combo[1], timeout=10)
elif nego_combo[0] == "starttls":
context = ssl.create_default_context()
popclient = poplib.POP3(host, nego_combo[1], timeout=10)
popclient.stls(context)
elif nego_combo[0] == "ssl":
context = ssl.create_default_context()
# context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) うまくいかない場合はこちらも。
popclient = poplib.POP3_SSL(host, nego_combo[1], timeout=10, context=context)
popclient.set_debuglevel(2) # サーバとの通信のやりとりを出力してくれる
"""
(2) POP3サーバにログインする
"""
username = "username@gmail.com"
password = "password"
auth_method = "user"
if auth_method == "user":
popclient.user(username)
popclient.pass_(password)
elif auth_method == "apop":
# Gmailはnot supported
# yahooはnot supported
popclient.apop(username, password)
elif auth_method == "rpop":
# Gmailはできない
# yahooはできない
popclient.rpop(username)
popclient.pass_(password)
"""
(3) メール受信(MIMEメッセージを受信)
"""
download_num = 3 # ダウンロードしたい数
msg_list = [] # 取得したMIMEメッセージを格納するリスト
msg_num = popclient.stat()[0] # POP3サーバに存在するメールの数を取得
if msg_num <= download_num:
download_num = msg_num
for i in range(download_num):
msg_bytes = b""
for line in popclient.retr(i+1)[1]: # i+1から始まる(参考:https://docs.python.org/ja/3/library/poplib.html#:~:text=for%20j%20in%20M.retr(i%2B1)%5B1%5D%3A)
msg_bytes += line + b"\n"
msg_list.append(email.message_from_bytes(msg_bytes))
popclient.quit()
"""
受信したメール(MIMEメッセージ)の確認
"""
for msg in msg_list:
print(msg)
print()
"""
各ヘッダや本文を取得する
"""
for msg in msg_list:
# 各ヘッダはディクショナリのようにアクセスできる
from_addr = str(make_header(decode_header(msg["From"])))
subject = str(make_header(decode_header(msg["Subject"])))
print("From:{}".format(from_addr))
print("Subject:{}".format(subject))
# 本文(payload)を取得する
if msg.is_multipart() is False:
# SinglePartのとき
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:
# 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")
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がない不親切なメールがたまにあるので注意。
気合でデコードするしかないが、今回のサンプルコードはそのようなメールは考慮していない。
"""