目次
概要
Python標準ライブラリの imaplib を使用して、IMAPサーバーからメールを受信・取得する方法を解説します。
単にデータを受信するだけでなく、email モジュールと連携して、件名や本文、送信元アドレスを扱いやすいオブジェクト(EmailMessage型)として解析するまでの手順を網羅します。
仕様(入出力)
- 入力:
- IMAPサーバー情報(ホスト、ポート)
- アカウント情報(メールアドレス、パスワード)
- 検索条件(件名、未読、全件など)
- 出力:
- メールオブジェクト(
EmailMessage) - 件名、本文、差出人などの抽出データ
- メールオブジェクト(
- 前提:
- Python標準ライブラリ(
imaplib,email)のみを使用。 - Gmail等の場合、アプリパスワードの生成が必要な場合があります。
- Python標準ライブラリ(
基本の使い方
IMAPサーバーに接続し、受信トレイ(INBOX)から最新のメールを1件取得して解析する基本的なフローです。
import imaplib
from email import message_from_bytes, policy
# 1. サーバー接続とログイン
imap = imaplib.IMAP4_SSL("imap.example.com", 993)
imap.login("user@example.com", "password")
# 2. メールボックス選択と検索
imap.select("INBOX")
stat, data = imap.search(None, "ALL")
# 3. 最新メールのIDを取得
latest_email_id = data[0].split()[-1]
# 4. データの取得と解析
stat, msg_data = imap.fetch(latest_email_id, "(RFC822)")
raw_email = msg_data[0][1]
msg = message_from_bytes(raw_email, policy=policy.default)
print(f"件名: {msg['Subject']}")
imap.logout()
コード全文
「特定の件名」を含むメールを検索し、その本文(テキストまたはHTML)を表示する実用的なコードレシピです。
import imaplib
from email import message_from_bytes, policy
import chardet # 文字コード判定用(なくても動作は可能ですがあると便利)
def receive_email_imap():
"""
IMAP4を使用してメールを受信し、内容を表示するデモ関数。
"""
# 接続設定 (Gmailの例)
imap_server = "imap.gmail.com"
imap_port = 993
username = "your_email@gmail.com"
password = "your_app_password" # アプリパスワード推奨
try:
# 1. SSL接続の確立
print("サーバーに接続中...")
imap = imaplib.IMAP4_SSL(imap_server, imap_port)
# 2. ログイン
imap.login(username, password)
print("ログイン成功")
# 3. メールボックスの選択 ('INBOX' は受信トレイ)
imap.select("INBOX")
# 4. メールの検索
# 第1引数は文字セット(Noneまたは"UTF-8")
# 第2引数は検索条件 ("ALL", "UNSEEN", '(SUBJECT "Test")' など)
print("メールを検索中...")
# 例: 件名に "Test" を含むメールを検索
search_criteria = '(SUBJECT "Test")'
# search_criteria = "ALL" # 全件の場合
status, messages = imap.search("UTF-8", search_criteria)
email_ids = messages[0].split()
if not email_ids:
print("該当するメールが見つかりませんでした。")
return
# 最新のメール1件だけを処理(IDリストの最後)
latest_id = email_ids[-1]
print(f"メールID {latest_id.decode()} を取得します...")
# 5. メール実データの取得 (RFC822形式 = ヘッダー+本文の全て)
status, msg_data = imap.fetch(latest_id, "(RFC822)")
# 6. 生データからEmailMessageオブジェクトへ変換
# msg_data[0] は (b'シーケンス番号 (RFC822 {サイズ}', b'メール本体') のタプル
raw_email = msg_data[0][1]
# policy.defaultを指定することで、件名のデコード等を自動化
msg = message_from_bytes(raw_email, policy=policy.default)
# 7. 内容の表示
print("-" * 30)
print(f"From : {msg['From']}")
print(f"To : {msg['To']}")
print(f"Subject : {msg['Subject']}")
print("-" * 30)
# 本文の取得(マルチパート対応)
body = ""
if msg.is_multipart():
for part in msg.walk():
content_type = part.get_content_type()
content_disposition = str(part.get("Content-Disposition"))
# 添付ファイルを除外し、テキスト/HTMLを取得
if "attachment" not in content_disposition:
if content_type == "text/plain":
try:
body = part.get_content()
except:
pass # デコードエラー等はスキップ
else:
# シングルパートの場合
body = msg.get_content()
print("--- 本文 (抜粋) ---")
print(body[:200] + "..." if len(body) > 200 else body)
except Exception as e:
print(f"エラーが発生しました: {e}")
finally:
# 8. ログアウトと切断
try:
imap.close() # 選択したメールボックスを閉じる
imap.logout() # サーバーから切断
print("ログアウトしました")
except:
pass
if __name__ == "__main__":
receive_email_imap()
カスタムポイント
主要メソッドと役割
imaplib.IMAP4_SSL オブジェクトの主要な操作一覧です。
| メソッド | 引数例 | 処理・意味 |
imaplib.IMAP4_SSL | (host, port) | SSL暗号化通信でIMAPサーバーインスタンスを生成します。 |
login | (user, password) | ユーザー名とパスワードでサーバーに認証を行います。 |
select | ("INBOX") | 操作対象のメールボックス(フォルダ)を選択します。 |
search | (None, "ALL") | 条件に一致するメールIDのリストを取得します。 第1引数は文字コード、第2引数は検索クエリです。 |
fetch | (id, "(RFC822)") | 指定したIDのメールデータを取得します。RFC822を指定するとメール全体を取得できます。 |
logout | なし | サーバーとの接続を終了します。 |
検索条件の指定 (search)
search メソッドは強力ですが、クエリの書き方に注意が必要です。
- 全件取得:
imap.search(None, "ALL") - 未読のみ:
imap.search(None, "UNSEEN") - 件名検索:
imap.search("UTF-8", '(SUBJECT "検索ワード")')- 日本語検索の場合は第1引数に
"UTF-8"を指定します。
- 日本語検索の場合は第1引数に
EmailMessageへの変換
imap.fetch で取得できるのは「バイト列」です。これを Python で扱いやすくするために email モジュールを使います。
message_from_bytes(raw, policy=policy.default):- これを推奨します。
policy.defaultを指定することで、MIMEヘッダー(=?utf-8?B?...?=形式の文字列)が自動的にデコードされ、msg['Subject']でそのまま日本語文字列として取得できるようになります。
- これを推奨します。
注意点
- 既読・未読の扱い
fetchで(RFC822)を指定してデータを取得すると、サーバー側でそのメールは自動的に「既読(SEEN)」になります。- 既読にしたくない場合は、
(BODY.PEEK[])を使用してデータを取得します。
- セキュリティ
- Gmailなどの主要プロバイダは、通常のログインパスワードでのIMAP接続を禁止している場合があります。その場合、2段階認証を有効にし、「アプリパスワード」を発行して使用してください。
- メールボックス名
- 日本語環境のOutlookなどでは、
INBOX以外のフォルダ名が日本語(例:"送信済みアイテム")の場合があります。その際はUTF-7 (&Tgtm+DBN-) 形式などにエンコードが必要な場合があります。
- 日本語環境のOutlookなどでは、
応用
メールに添付ファイルがある場合、それを保存する応用例です。
import os
# (imap接続、msg取得まではコード全文と同様)
def save_attachments(msg, download_folder="downloads"):
os.makedirs(download_folder, exist_ok=True)
for part in msg.walk():
# content_dispositionに "attachment" が含まれていれば添付ファイル
if part.get_content_maintype() == 'multipart':
continue
if part.get('Content-Disposition') is None:
continue
filename = part.get_filename()
if filename:
filepath = os.path.join(download_folder, filename)
with open(filepath, 'wb') as f:
f.write(part.get_payload(decode=True))
print(f"添付ファイルを保存しました: {filepath}")
まとめ
Pythonでメールを受信する際は、imaplib で通信を行い、email モジュールでデータを解析するという役割分担を理解することが重要です。
特に policy.default を使用したパースを行うことで、複雑な文字コード処理を自動化し、シンプルなコードでメール操作を実現できます。
