摘要

  • UIDPLUS 把目标邮箱的 UIDVALIDITY 和新 UID 放进 APPEND、COPY 的成功结果,使离线客户端能够把刚刚执行的动作与服务器新建的引用精确对应。
  • 这张“回执”只在一个邮箱世代和一次命令内有效:权限与 UIDNOTSTICKY 可以让服务器省略它,COPYUID 不是跨客户端的全局身份,而 UID EXPUNGE 只删除既在指定 UID 集合中、又已标记 \Deleted 的邮件。

成功与找到成功的结果是两回事

IMAP 的服务器负责给邮箱中的邮件分配 UID。客户端执行 APPEND 时,知道自己送入了什么,却不能预先决定服务器会给它什么编号。传统的 OK 可以证明命令完成,却未必告诉客户端以后应当用哪个稳定引用找到结果。

这对持续在线的简单界面也许只是一次额外读取,对离线同步却是账本问题。本地队列里有一个“待上传”对象,远端已经多出一封邮件;如果二者不能可靠合并,重试可能制造重复,不重试又可能遗留无法追踪的状态。

1998 年的 RFC 2359 以离线客户端为重要背景引入 UIDPLUS。2005 年 RFC 4315 取代前者,修正集合规则,补入隐私与非持久存储的例外。它没有发明新的事务层,只是让已有的成功边界携带足够的结果身份。

APPENDUID 把新名字写进回复

APPEND 成功时,服务器可在带标签的 OK 中返回 APPENDUID。它先给出目标邮箱的 UIDVALIDITY,再给出刚分配的 UID。客户端因此可以把本地动作与远端引用直接合并,而不必重新扫描邮箱猜测哪一封是刚才的结果。

UIDVALIDITY 不能省略。单独的 3955 只是一串数字;它必须和服务器、邮箱名、UIDVALIDITY 一起才构成可用引用。如果邮箱无法继续维护旧 UID 的含义,UIDVALIDITY 会改变,旧配对也必须失效。回执之所以可信,不只是因为它给了编号,还因为它给了编号所属的世代。

当一次 APPEND 加入多封邮件时,APPENDUID 可以返回 UID 集合。集合的顺序与输入邮件一致,不能包含无关 UID,也不能用 * 表示开放终点。客户端知道自己提交了几项,因而可以检验回复的形状,而不是被一个模糊范围蒙混过去。

COPYUID 记录的不是“同号”,而是“改名”

邮件从一个邮箱复制到另一个邮箱时,源 UID 不会作为全局号码随内容搬迁。目标邮箱会分配自己的 UID。COPYUID 返回目标 UIDVALIDITY、源 UID 集合与目标 UID 集合;两个集合必须等长,位置定义对应关系。

这使 304,319:320 与 3956:3958 之类的列表可以逐项配对。值不需要相同,也不需要有相同间隔。证据来自执行 COPY 的服务器回复,而非客户端事后根据主题、大小或排列顺序猜测。

可见序号尤其不适合承担这项工作。另一会话在 COPY 期间执行删除,EXPUNGE 会让后续邮件的序号整体移动。UIDPLUS 把映射建立在 UID 上,并禁止回复夹带本次命令之外的 UID,因此视图重排不会改变命令的对象集合。

但这仍不是普遍身份。RFC 8474 明确指出:收到 COPYUID 的客户端知道这次复制的映射,另一个没有看到回复的客户端不能仅凭两个邮箱里的普通 UID 推断相同关系。后来的 ObjectID 扩展处理的是更大的问题;UIDPLUS 处理的是命令执行者如何核对刚才的结果。

UID EXPUNGE 为删除再加一道条件

普通 EXPUNGE 会永久移除当前邮箱中所有带 \Deleted 标记的邮件。在共享邮箱里,这些标记可能来自不同人、不同设备和不同时间。一台离线设备重新上线,只想完成自己的删除,却可能把别人尚未准备提交的标记一并兑现。

UID EXPUNGE 要求两项条件同时成立:邮件带有 \Deleted,且它的 UID 位于命令指定的集合。只有编号而没有标记,不删;只有标记而不在集合,也不删。这个交集把“允许删除”与“现在由我提交删除”分开。

不支持 UIDPLUS 的服务器需要更笨重的兼容步骤:暂时清除希望保留邮件的删除标记,执行 EXPUNGE,再恢复标记。它可能得到同样结果,却必须改动更大范围的共享状态。UID EXPUNGE 把不可逆意图直接缩到一个稳定集合。

有时不返回编号才是正确行为

权限模型可能允许用户向某个邮箱 APPEND 或 COPY,却不允许 SELECT 或 EXAMINE 它。如果服务器仍返回 UIDVALIDITY 与新 UID,就等于通过成功回复泄露了用户本不应查看的邮箱信息。RFC 4315 因此要求这种情况下不应发送 APPENDUID 或 COPYUID。

目标邮箱若标记 UIDNOTSTICKY,服务器也可以省略回执。这表示 UID 无法保证跨会话持久。标准不鼓励新建此类存储,但承认旧系统可能存在。此时给出一个看似耐久的编号,比明确不承诺更危险。

没有回执不等于命令失败。若客户端随后有查看权限,可以选择目标邮箱,用 FETCH 或 SEARCH 寻找自己预置的独特标记。这条退路成本更高,却维持了三个边界:写入是否成功、用户是否有权查看、引用是否会持久。

MOVE 说明证据到达的次序也重要

MOVE 同时在目标端建立新邮件、在源端移除旧邮件。UIDPLUS 服务器可为 UID MOVE 返回 COPYUID。问题在于,如果 EXPUNGE 回复先到,源邮箱的可见序号已经变化,客户端才收到映射,处理难度会无端增大。

RFC 6851 建议在删除通知之前,以无标签 OK 先给出 COPYUID。RFC 9051 把这项秩序纳入 IMAP4rev2。单独看都正确的三条信息——新 UID、旧邮件消失、命令完成——仍需要按照可解释的顺序出现。

一张有辖区的回执

UIDPLUS 的历史价值,在于它没有把局部证据夸大。APPENDUID 只回答一次写入产生了什么目标引用;COPYUID 只回答一次复制怎样把一组源引用对应到一组目标引用;UID EXPUNGE 只让一次清理锁定客户端明确指定、且已具删除标记的对象。

服务器返回了“新名字”,也同时返回这个名字的管辖范围。权限例外、UIDNOTSTICKY 和 UIDVALIDITY 都在提醒客户端:可验证并不等于无限有效。精确的协议证据不是声称知道一切,而是让每一项结论都停在证据真正覆盖的边界上。

来源与边界

最初的定义见 RFC 2359,现行扩展规范为取代它的 RFC 4315。IMAP4rev1 背景来自 RFC 3501,MOVE 交互见 RFC 6851,跨客户端身份限制见 RFC 8474,IMAP4rev2 的整合规则见 RFC 9051。IANA IMAP 能力注册表仍列有 UIDPLUS。这些来源不提供部署率,也不把 UID 映射变成密码学证明或邮件投递回执。