用imaplib连接邮箱需先开启IMAP权限并使用专用密码(如Gmail的16位应用密码),再通过IMAP4_SSL('服务器',993)建立SSL连接,调用login('完整邮箱','密码')认证;常见失败主因是未开IMAP或密码类型错误。

怎样用 imaplib 连上邮箱并认证成功
大多数失败都卡在第一步:连不上服务器或认证被拒。不是密码错了,而是没开 IMAP 权限,或用了应用专用密码(比如 Gmail 启用两步验证后,password 字段必须填 16 位应用专用密码,不能填账户登录密码)。
常见错误现象:socket.error: [Errno 111] Connection refused —— 检查服务器地址和端口是否匹配;imaplib.error: AUTHENTICATIONFAILED —— 确认是否启用了 IMAP,Gmail 需在「设置 → 转发和 POP/IMAP」中启用 IMAP;Outlook/Hotmail 则需在账户安全设置里开启「允许较不安全的应用」或生成应用密码。
实操建议:
- 使用标准端口:
imap.gmail.com:993、outlook.office365.com:993,强制走 SSL - 连接时必须用
imaplib.IMAP4_SSL(),别用IMAP4()(明文不被现代邮箱接受) - 登录前加一句
mail.login(email, password),其中email必须是完整邮箱地址(如"user@gmail.com"),不能只写用户名
怎样用 SEARCH 命令精准筛选发件人
SEARCH 是核心,但语法容易写错。很多人直接拼字符串,结果返回空或全量邮件——因为 FROM 不支持模糊匹配,且对大小写不敏感但对引号和空格敏感。
立即学习“Python免费学习笔记(深入)”;
正确写法必须用双引号包裹发件人地址,且推荐用 UTF-8 编码处理中文名(如“张三
示例命令:
mail.search(None, 'FROM "notify@github.com"')
注意:None 表示默认字符集(通常是 US-ASCII),如果发件人含中文名,应改用:
mail.search('UTF-8', 'FROM "张三"')
常见陷阱:
- 多个发件人用
OR,但括号必须转义:mail.search(None, 'OR FROM "a@x.com" FROM "b@y.com"') -
FROM匹配的是From:头字段原始值,不是解析后的邮箱地址,所以"admin" <admin></admin>不能只搜"admin@site.com",得搜完整字符串或用正则后续提取 - 某些企业邮箱(如 Zimbra)对
FROM支持有限,可退而求其次用HEADER FROM
怎样安全读取邮件正文并提取结构化数据
拿到邮件 ID 后,FETCH 返回的是 RFC 2822 格式原始内容,不是纯文本。直接 .decode() 很可能报 UnicodeDecodeError,尤其含附件或多部分 MIME 的邮件。
必须用 email.parser.Parser().parsestr() 解析,再递归遍历 message.walk() 找 text/plain 或 text/html 部分。别跳过 is_multipart() 判断,否则会漏掉正文或把附件当正文。
提取特定数据(如订单号、金额)建议:
- 先用
get_content_type()过滤出文本部分,再用get_payload(decode=True)解码(注意 decode=True 才能处理 base64) - 正则提取时,用
re.search(r'订单号[::]\s*(\w+)', text)比硬编码更鲁棒,中文冒号要兼容全角 - 避免用
.replace('\r\n', '\n').strip()粗暴清洗,有些邮件正文自带缩进格式,清洗后反而破坏关键换行(比如表格型通知)
怎样避免被邮箱服务限流或封禁
高频拉取(比如每 10 秒连一次)极易触发风控。Gmail 明确限制每分钟最多 10 次 FETCH,每小时最多 10000 次 API 调用;Outlook 也有类似速率限制。
实操中真正容易被忽略的点是:没调用 mail.close() 和 mail.logout()。连接不显式关闭,服务器会维持 idle 状态,积累到一定数量就拒绝新连接。
稳妥做法:
- 每次操作完立刻
mail.close()(关闭当前文件夹)、mail.logout()(断开连接) - 加
time.sleep(30)控制轮询间隔,生产环境建议用IDLE模式监听新邮件,而不是轮询 - 记录最后处理的邮件 UID(不是消息序号),下次从该 UID 之后开始拉取,避免重复处理;UID 是永久的,而消息序号会随删除/移动变动
复杂点在于:不同邮箱对 UIDVALIDITY 的处理不一致,切换文件夹时要校验 UIDVALIDITY 是否变化,否则用旧 UID 拉取会返回空——这点几乎没人提,但线上故障多源于此。


















