RFC 9051: IMAP4rev2
为什么存在这个协议
IMAP4rev1(RFC 3501,发布于 2003 年)在近二十年间是多设备电子邮件的骨干。但它积累了数十个扩展 RFC、模糊的边界情况和每个真实服务器实现方式都不同的功能。RFC 9051 — IMAP4rev2 — 是一次干净的修订,它:
- 整合必要的扩展。CONDSTORE(条件存储)、NAMESPACE、ESEARCH、LIST-EXTENDED、LITERAL- 和 MOVE 等功能现在是基础协议的一部分,而不是可选附加项。
-
移除已弃用的功能。旧的
\Recent标志已消失。同时消失的还有围绕同时邮箱访问的模糊行为。 - 澄清同步语义。UIDVALIDITY、MODSEQ 和变更跟踪的精确规则使构建可靠的离线功能客户端成为可能。
如果你正在构建新的电子邮件客户端或集成,请针对 IMAP4rev2。如果服务器仅支持 IMAP4rev1,命令集几乎相同 — 只需单独协商扩展。
工作原理
连接和身份验证
IMAP 使用端口 143(STARTTLS)或端口 993(隐式 TLS,推荐)。连接后,客户端进行身份验证:
-- 连接到端口 993 (IMAPS) -- * OK [CAPABILITY IMAP4rev2 AUTH=PLAIN] 服务器就绪 a1 LOGIN alice@example.com s3cretP@ss a1 OK [CAPABILITY IMAP4rev2 MOVE CONDSTORE] 已登录
每个客户端命令前缀带有一个标签(如 a1)。服务器用相同的标签响应,允许管道命令。无标签响应(前缀为 *)携带消息计数和功能列表等数据。
选择邮箱
a2 SELECT INBOX * 42 EXISTS ← 收件箱中有 42 条消息 * OK [UIDVALIDITY 1609459200] ← UID 纪元;如果更改,重新同步 * OK [UIDNEXT 1053] ← 下一个要分配的 UID * OK [HIGHESTMODSEQ 7834] ← 用于增量同步(CONDSTORE) * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) a2 OK [READ-WRITE] SELECT 已完成
获取消息
-- 获取消息 1:5 的信封和标志 -- a3 FETCH 1:5 (FLAGS ENVELOPE) * 1 FETCH (FLAGS (\Seen) ENVELOPE ("Wed, 12 Mar 2025 ..." ...)) * 2 FETCH (FLAGS () ENVELOPE (...)) ... a3 OK FETCH 已完成 -- 获取消息 UID 1050 的完整正文 -- a4 UID FETCH 1050 (BODY[]) * 41 FETCH (UID 1050 BODY[] {4523} (完整 RFC 5322 消息...) ) a4 OK UID FETCH 已完成
服务器端搜索
a5 SEARCH UNSEEN FROM "bob@example.com" SINCE 1-Mar-2025 * SEARCH 38 41 42 a5 OK SEARCH 已完成
关键技术细节
UID 和序列号
每条消息有两个标识符:序列号(其在邮箱中的位置,删除消息时会改变)和 UID(永久分配的号码,仅递增)。健壮的客户端始终通过 UID FETCH、UID SEARCH 等使用 UID。UIDVALIDITY 值告诉客户端其缓存的 UID 是否仍然有效;如果它改变,客户端必须从头重新同步。
标志
IMAP4rev2 定义这些系统标志:
| 标志 | 含义 |
|---|---|
\Seen |
消息已被读取 |
\Answered |
消息已被回复 |
\Flagged |
标记为重要/星标 |
\Deleted |
标记为删除(EXPUNGE 时移除) |
\Draft |
消息是草稿 |
IMAP4rev1 中的 \Recent 标志在 rev2 中已移除。服务器也可能支持自定义关键字(例如 $Forwarded、$Junk)。
CONDSTORE 和 QRESYNC
CONDSTORE 为每个标志变更分配一个 MODSEQ 值。知道最后看到的 MODSEQ 的客户端可以询问:"自 MODSEQ 7834 以来发生了什么变化?"并仅获取增量。QRESYNC(快速重新同步)扩展此功能以有效处理已清除的消息。它们一起使 IMAP 在全面重新同步太昂贵的移动网络上可行。
MOVE 命令
在 IMAP4rev1 中,移动消息需要 COPY + STORE \Deleted + EXPUNGE — 三个带有竞态条件的命令。IMAP4rev2 将 MOVE 包含为原生原子操作:
a6 UID MOVE 1050 "Archive" * OK [COPYUID 1609459200 1050 287] * 41 EXPUNGE a6 OK MOVE 已完成
常见错误
- 使用序列号作为持久引用。删除消息时序列号会改变。始终对任何缓存或跨会话引用使用 UID。
- 忽视 UIDVALIDITY 变更。如果 UIDVALIDITY 在会话间发生变化,所有缓存的 UID 都无效。你必须丢弃本地缓存并重新同步。
-
轮询而不是使用 IDLE。
IDLE命令让服务器推送新消息通知。每 30 秒轮询一次会浪费带宽和电量。使用 IDLE 获得实时更新。 -
需要 BODY.PEEK[] 时获取 BODY[]。
FETCH BODY[]隐含设置\Seen标志。使用BODY.PEEK[]读取而不标记为已读。 - 不支持 CONDSTORE。没有 CONDSTORE,每次重新连接都需要完整邮箱重新同步。现代 IMAP 客户端应始终协商 CONDSTORE。
- 在端口 143 上运行 IMAP 而不使用 TLS。根据 RFC 8314 使用带隐式 TLS 的端口 993。
可递送性影响
- IMAP 是检索协议,不是发送协议。与 POP3 一样,它不直接影响出站可递送性。它决定收件人如何体验你发送的邮件。
- 基于标志的参与信号。主要提供商(Gmail、Outlook)观察 IMAP 标志变更 — 将消息标记为 \Seen、移动到文件夹、加星标 — 作为参与信号。正面参与可以随着时间推移改善你的发件人信誉。
- 垃圾邮件文件夹交互。当收件人通过 IMAP 将你的消息移出"垃圾邮件"时,提供商通常将其视为"不是垃圾邮件"信号。相反,IMAP 移动到垃圾邮件会对你不利。
- 退件邮箱处理。IMAP 比 POP3 更适合退件处理,因为你可以服务器端 SEARCH DSN 消息、处理它们,并 MOVE 它们到档案库 — 无需下载每条消息。