我的知识记录

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:]

Python读取未读邮件 imaplib UNSEEN搜索教程

标签:

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

上一篇:Python定时检查新邮件并提醒 schedule实战

下一篇:Python使用QQ邮箱SMTP发送邮件 详细教程