先确认imap是否开启且密码正确,gmail需应用专用密码,qq邮箱用授权码,outlook启用imap并用outlook.office365.com;筛选退信看x-failed-recipients头,垃圾邮件查junk标签;操作全程用uid避免序号错位;设socket超时并分批处理。

用 imaplib 连不上邮箱?先确认 IMAP 是否开启且密码正确
绝大多数“连接失败”不是代码问题,而是邮箱服务端限制。Gmail、Outlook、QQ 邮箱默认关闭 IMAP 或要求应用专用密码。
常见错误信息如 [AUTHENTICATIONFAILED]、socket.timeout 或 NO Login failed,基本都指向这个环节。
实操建议:
- Gmail 必须在「Google 账户 → 安全 → 两步验证 → 应用专用密码」里生成 16 位密码,不能用账号密码
- QQ 邮箱需在「设置 → 账户 → IMAP/SMTP 服务」手动开启,并获取授权码(不是登录密码)
- Outlook(Hotmail)需在「账户设置 → 隐私与安全 → 邮件应用权限」中启用 IMAP,并注意其服务器是
outlook.office365.com,不是imap-mail.outlook.com - 连接时强制使用 SSL:
imaplib.IMAP4_SSL(host, port=993),别试非加密的 143 端口
怎么精准筛选退信和广告邮件?别只靠关键词匹配
单纯用 subject 或 body 里搜 “退订”、“促销”、“发票” 很容易误删或漏删——退信往往没有正文,广告可能伪装成通知。更可靠的方式是结合 RFC 标准字段和服务器标记。
实操建议:
- 退信(bounce)优先查
Content-Type: multipart/report或X-Failed-Recipients头字段,IMAP 可用SEARCH HEADER "X-Failed-Recipients" "*" - 垃圾邮件通常被服务商自动打上
Junk或Spam标签(不是文件夹名),可用SEARCH X-GM-LABELS "spam"(Gmail)或SEARCH KEYWORD "$Junk"(支持 RFC 822.2 的服务器) - 广告类可组合条件:
SEARCH SINCE "15-Jan-2024" FROM "noreply@" OR FROM "alert@" UNSEEN,再人工抽检前 5 封确认发件域是否真实 - 避免用
SEARCH BODY "免费"—— 编码不一致会导致匹配失败,改用UTF8扩展(需服务器支持)或先FETCH再本地解码判断
IMAP4.uid() 和 IMAP4.search() 混用会丢邮件
UID 是服务器分配的永久 ID,而 MSGNO(消息序号)会随删除动态变化。一旦你先 search() 拿到一串序号 [1,2,3],再逐条 uid() 转换,中间若有其他客户端同步删除了第 1 封,后续序号全部错位,uid(2) 可能返回原第 3 封甚至报错 NONEXISTENT。
实操建议:
- 全程用 UID 模式:
mail.select('INBOX', readonly=False)后立刻mail.uid('SEARCH', None, 'SINCE "1-Jan-2024"') - 删除前务必加
mail.uid('STORE', uid_set, '+FLAGS', '(\Deleted)'),再执行mail.expunge();跳过STORE直接expunge()无效 - 批量操作时,UID 字符串必须用逗号拼接且无空格:
b'123,456,789',不是列表或 Python 元组 - 每次
FETCH后检查响应状态,忽略None响应体——某些服务器对空邮件返回空内容,直接解包会抛ValueError
定时清理脚本跑着跑着就卡住?得处理连接超时和重试边界
IMAP 连接不是 HTTP,没有自动重连机制。网络抖动、邮箱服务限流(如 Gmail 每分钟最多 10 次 SEARCH)、甚至后台自动归档都会导致 SELECT 或 SEARCH 卡死或返回不完整结果。
实操建议:
- 所有 socket 操作设超时:
imaplib.IMAP4_SSL(host, port=993, timeout=30),并在外层用try/except (socket.timeout, imaplib.IMAP4.abort)包裹 - 单次最多处理 100 封(
SEARCH返回 UID 数超限时拆成多批),避免服务器中断响应 - 不要依赖
mail.list()获取文件夹列表——有些邮箱(如 QQ)返回编码异常,直接硬编码目标文件夹名更稳 - 日志必须记录实际执行的 UID 范围和删除数,比如
"Deleted 42 messages in INBOX (UIDs 12001–12042)",否则出问题根本没法回溯
真正麻烦的从来不是“怎么删”,而是删完发现某封重要通知被规则误杀,或者因为没关掉调试日志,三个月后磁盘被 imaplib 的原始响应塞爆。留个 dry_run=True 开关,比写十行过滤逻辑都重要。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











