Python读取未读邮件 imaplib UNSEEN搜索教程
用imaplib的UNSEEN条件只抓未读邮件,配合BODY.PEEK读取不污染已读状态,适合做新邮件提醒和每日未读摘要,附完整可运行代码。
场景痛点
上班先打开邮箱,未读邮件标着小红点,但要一封封点开才知道说了什么。把未读邮件的发件人、主题、正文摘要自动抓出来列在终端或桌面,扫一眼就知道哪些要马上回、哪些是广告,省得一直挂着网页邮箱。
用到的库
imaplib、email都是Python标准库,无需pip安装。
# 无需安装,Python3自带
完整代码
# -*- coding: utf-8 -*-
import imaplib
import email
from email.header import decode_header, make_header
IMAP_SERVER = "imap.qq.com"
IMAP_PORT = 993
ACCOUNT = "your_account@qq.com"
PASSWORD = "your_imap_auth_code"
def decode_str(s):
if not s:
return ""
return str(make_header(decode_header(s)))
def get_text_body(msg):
"""提取邮件纯文本正文前200字当摘要"""
body = ""
for part in msg.walk():
if part.get_content_type() == "text/plain":
charset = part.get_content_charset() or "utf-8"
try:
body = part.get_payload(decode=True).decode(charset, errors="ignore")
except LookupError:
body = part.get_payload(decode=True).decode("utf-8", errors="ignore")
break
return body.strip().replace("\r", "").replace("\n", " ")[:200]
def read_unread():
mail = imaplib.IMAP4_SSL(IMAP_SERVER, IMAP_PORT)
mail.login(ACCOUNT, PASSWORD)
mail.select("INBOX")
# 关键:只搜未读邮件
status, messages = mail.search(None, "UNSEEN")
if status != "OK" or not messages[0]:
print("没有未读邮件")
mail.logout()
return
id_list = messages[0].split()
print(f"未读邮件共 {len(id_list)} 封:\n")
for msg_id in id_list:
# 用BODY.PEEK:只读取,不自动标记为已读
status, msg_data = mail.fetch(msg_id, "(BODY.PEEK[])")
msg = email.message_from_bytes(msg_data[0][1])
subject = decode_str(msg.get("Subject"))
sender = decode_str(msg.get("From"))
date = msg.get("Date", "")
snippet = get_text_body(msg)
print(f"时间:{date}")
print(f"发件人:{sender}")
print(f"主题:{subject}")
print(f"摘要:{snippet}...\n")
mail.logout()
if __name__ == "__main__":
read_unread()
代码讲解
mail.search(None, "UNSEEN"):IMAP内置搜索条件,服务器只返回还没读过的邮件。已读邮件不会混进来。BODY.PEEK[]:这一步非常关键。普通的RFC822抓取会让服务器自动把邮件标记为已读,你脚本看一眼就把未读红点消了。加PEEK就是"只看不读",原邮件状态保持未读。text/plain:一封邮件常有纯文本和HTML两个版本,这里只挑纯文本版本做摘要,HTML版留给以后解析。get_content_charset():邮件正文可能用gbk、utf-8等编码,先取邮件自己声明的字符集,失败再兜底utf-8,避免中文乱码。- 摘要截前200字:正文动辄几屏,终端看不完,截一段足够判断是不是要马上处理。
运行结果
运行后终端列出所有未读邮件的时间、发件人、主题、正文前200字。如果没有未读,打印"没有未读邮件"。原邮箱里这些邮件仍然是未读状态,不会被脚本悄悄标成已读。
注意事项
- 想用脚本读未读又不想动原邮件状态,必须用
BODY.PEEK[],这是最容易踩的坑。 - 有些邮件是纯HTML没有纯文本版本,
get_text_body会返回空字符串,这是正常现象,不是脚本坏了。 - UNSEEN是按邮件的
\Seen标志判断,网页邮箱里点开过就算已读。 - 想读完顺便标记已读,把fetch换成
(RFC822)就行,或者下一篇里用+FLAGS \Seen主动加。 - 未读太多时建议只处理最近50封,
id_list = messages[0].split()[-50:]。

更新时间:2026-09-14 21:07:12