2. Protocol Overview (协议概述)
2.1. Link Level (链路层)
IMAP4rev1 协议假设有一个可靠的数据流, 例如 TCP 提供的数据流. 当使用 TCP 时, IMAP4rev1 服务器监听端口 143.
2.2. Commands and Responses (命令和响应)
IMAP4rev1 连接由以下部分组成: 建立客户端/服务器网络连接, 服务器发送初始问候 (Greeting), 以及客户端/服务器交互. 这些客户端/服务器交互由客户端命令 (Client Command), 服务器数据 (Server Data) 和服务器完成结果响应 (Server Completion Result Response) 组成.
客户端和服务器传输的所有交互都采用行 (Lines) 的形式, 即以 CRLF 结尾的字符串. IMAP4rev1 客户端或服务器的协议接收器要么正在读取一行, 要么正在读取已知数量的八位字节序列后跟一行.
2.2.1. Client Protocol Sender and Server Protocol Receiver (客户端协议发送者和服务器协议接收者)
客户端命令开始一个操作. 每个客户端命令都以一个标识符 (Identifier) 为前缀, 称为 "标签 (Tag)" (通常是一个短的字母数字字符串, 例如 A0001, A0002 等). 客户端为每个命令生成不同的标签.
客户端必须 (MUST) 严格遵循本规范中概述的语法. 发送缺少或多余空格或参数的命令是语法错误.
有两种情况下, 来自客户端的一行不代表完整的命令. 一种情况是, 命令参数使用八位字节计数引用 (参见数据格式下字符串中字面量的描述), 另一种情况是, 命令参数需要服务器反馈 (参见 AUTHENTICATE 命令). 在任何一种情况下, 如果服务器准备好接收八位字节 (如果适用) 和命令的其余部分, 则服务器发送命令继续请求响应 (Command Continuation Request Response). 此响应以标记 + 为前缀.
注意: 如果服务器检测到命令中的错误, 它会发送带有与命令匹配的标签的 BAD 完成响应 (如下所述) 以拒绝命令并阻止客户端发送命令的更多内容.
服务器也可能为其他某些命令 (如果多个命令正在进行中) 发送完成响应, 或发送未标记数据 (Untagged Data). 在任何一种情况下, 命令继续请求仍然挂起, 客户端对响应采取适当的操作, 并从服务器读取另一个响应. 在所有情况下, 客户端必须 (MUST) 在启动新命令之前发送完整的命令 (包括接收该命令的所有命令继续请求响应和命令继续).
IMAP4rev1 服务器的协议接收器从客户端读取命令行, 解析命令及其参数, 并传输服务器数据和服务器命令完成结果响应.
2.2.2. Server Protocol Sender and Client Protocol Receiver (服务器协议发送者和客户端协议接收者)
服务器传输给客户端的数据和不表示命令完成的状态响应以标记 * 为前缀, 称为未标记响应 (Untagged Responses).
服务器数据可以 (MAY) 作为客户端命令的结果发送, 也可以 (MAY) 由服务器单方面发送. 由特定命令产生的服务器数据与单方面发送的服务器数据之间没有语法差异.
服务器完成结果响应表示操作的成功或失败. 它使用与开始操作的客户端命令相同的标签进行标记. 因此, 如果有多个命令正在进行中, 服务器完成响应中的标签标识响应适用的命令. 有三种可能的服务器完成响应:
- OK (表示成功)
- NO (表示失败)
- BAD (表示协议错误, 例如无法识别的命令或命令语法错误)
服务器应该 (SHOULD) 严格执行本规范中概述的语法. 任何具有协议语法错误的客户端命令, 包括 (但不限于) 缺少或多余的空格或参数, 都应该 (SHOULD) 被拒绝, 并向客户端返回 BAD 服务器完成响应.
IMAP4rev1 客户端的协议接收器从服务器读取响应行. 然后根据响应的第一个标记 (可以是标签, * 或 +) 对响应采取操作.
客户端必须 (MUST) 准备好随时接受任何服务器响应. 这包括未请求的服务器数据. 服务器数据应该 (SHOULD) 被记录, 以便客户端可以引用其记录的副本, 而不是向服务器发送命令来请求数据. 对于某些服务器数据, 数据必须 (MUST) 被记录.
此主题在服务器响应章节中有更详细的讨论.
2.3. Message Attributes (消息属性)
除了消息文本外, 每条消息都有几个关联的属性. 这些属性可以单独检索, 也可以与其他属性或消息文本一起检索.
2.3.1. Message Numbers (消息编号)
IMAP4rev1 中的消息通过两个编号之一访问: 唯一标识符 (Unique Identifier) 或消息序列号 (Message Sequence Number).
2.3.1.1. Unique Identifier (UID) Message Attribute (唯一标识符消息属性)
分配给每条消息的 32 位值, 当与唯一标识符有效性值 (Unique Identifier Validity Value, 见下文) 一起使用时, 形成 64 位值, 该值禁止 (MUST NOT) 永久引用邮箱或任何具有相同名称的后续邮箱中的任何其他消息. 唯一标识符在邮箱中以严格升序方式分配, 当每条消息添加到邮箱时, 它被分配的 UID 高于先前添加的消息. 与消息序列号不同, 唯一标识符不一定是连续的.
消息的唯一标识符在会话期间禁止 (MUST NOT) 更改, 并且在会话之间不应该 (SHOULD NOT) 更改. 会话之间的唯一标识符的任何更改必须 (MUST) 使用下面讨论的 UIDVALIDITY 机制可检测. 客户端需要持久唯一标识符才能将其状态从先前会话与服务器重新同步 (例如, 断开连接或离线访问客户端), [IMAP-DISC] 中进一步讨论了这一点.
与每个邮箱关联的有两个值, 它们有助于唯一标识符处理: 下一个唯一标识符值 (Next Unique Identifier Value) 和唯一标识符有效性值 (Unique Identifier Validity Value).
下一个唯一标识符值是将分配给邮箱中新消息的预测值. 除非唯一标识符有效性也发生变化 (见下文), 否则下一个唯一标识符值必须 (MUST) 具有以下两个特征. 首先, 除非将新消息添加到邮箱, 否则下一个唯一标识符值禁止 (MUST NOT) 更改, 其次, 每当将新消息添加到邮箱时, 下一个唯一标识符值必须 (MUST) 更改, 即使这些新消息随后被删除 (Expunged).
注意: 下一个唯一标识符值旨在为客户端提供一种方法来确定自上次检查此值以来是否有任何消息传递到邮箱. 它并不旨在保证任何消息将具有此唯一标识符. 客户端只能假设, 在获得下一个唯一标识符值时, 在那之后到达的消息将具有大于或等于该值的 UID.
唯一标识符有效性值在邮箱选择时的 OK 未标记响应中以 UIDVALIDITY 响应代码发送. 如果来自早期会话的唯一标识符在本会话中无法持久保留, 则唯一标识符有效性值必须 (MUST) 大于早期会话中使用的值.
注意: 理想情况下, 唯一标识符应该 (SHOULD) 始终持久保留. 尽管本规范认识到在某些服务器环境中无法持久保留可能是不可避免的, 但它强烈鼓励 (STRONGLY ENCOURAGES) 避免此问题的消息存储实现技术. 例如:
-
唯一标识符在邮箱中必须 (MUST) 始终严格升序. 如果物理消息存储被非 IMAP 代理重新排序, 这要求重新生成邮箱中的唯一标识符, 因为重新排序的结果是以前的唯一标识符不再严格升序.
-
如果消息存储没有存储唯一标识符的机制, 它必须在每个会话重新生成唯一标识符, 并且每个会话必须具有唯一的 UIDVALIDITY 值.
-
如果邮箱被删除并且稍后创建具有相同名称的新邮箱, 则服务器必须跟踪邮箱先前实例的唯一标识符, 或者必须为邮箱的新实例分配新的 UIDVALIDITY 值. 在这种情况下使用的良好 UIDVALIDITY 值是邮箱创建日期/时间的 32 位表示. 可以使用诸如 1 之类的常量, 但仅当保证唯一标识符永远不会被重用时才可以, 即使在邮箱被删除 (或重命名) 并且在将来某个时间创建具有相同名称的新邮箱的情况下也是如此.
-
邮箱名称, UIDVALIDITY 和 UID 的组合必须 (MUST) 永久引用该服务器上的单个不可变消息. 特别是, 内部日期 (Internal Date), [RFC-2822] 大小, 信封 (Envelope), 正文结构 (Body Structure) 和消息文本 (RFC822, RFC822.HEADER, RFC822.TEXT 和所有 BODY[...] fetch 数据项) 禁止 (MUST) 更改. 这不包括消息编号, 也不包括可以由 STORE 命令设置的属性 (例如, FLAGS).
2.3.1.2. Message Sequence Number Message Attribute (消息序列号消息属性)
从 1 到邮箱中消息数量的相对位置. 此位置必须 (MUST) 按升序唯一标识符排序. 当添加每条新消息时, 它被分配的消息序列号比添加新消息之前邮箱中的消息数量高 1.
消息序列号可以在会话期间重新分配. 例如, 当从邮箱中永久删除 (Expunged) 消息时, 所有后续消息的消息序列号都会递减. 邮箱中的消息数量也会递减. 类似地, 新消息可以被分配一个曾经在删除之前由某个其他消息持有的消息序列号.
除了通过邮箱中的相对位置访问消息外, 消息序列号还可以用于数学计算. 例如, 如果收到未标记的 "11 EXISTS", 并且之前收到未标记的 "8 EXISTS", 则已到达三条新消息, 消息序列号为 9, 10 和 11. 另一个例子, 如果 523 消息邮箱中的消息 287 具有 UID 12345, 则恰好有 286 条消息具有较小的 UID, 236 条消息具有较大的 UID.
2.3.2. Flags Message Attribute (标志消息属性)
与消息关联的零个或多个命名标记 (Named Tokens) 的列表. 通过将标志添加到此列表来设置标志, 通过将其删除来清除标志. IMAP4rev1 中有两种类型的标志. 任一类型的标志都可以是永久的或仅会话的.
系统标志 (System Flag) 是本规范中预定义的标志名称. 所有系统标志都以 \ 开头. 某些系统标志 (\Deleted 和 \Seen) 具有在其他地方描述的特殊语义. 当前定义的系统标志是:
-
\Seen: 消息已被阅读 -
\Answered: 消息已被回复 -
\Flagged: 消息被"标记"为紧急/特别关注 -
\Deleted: 消息被"删除"以供以后 EXPUNGE 删除 -
\Draft: 消息尚未完成撰写 (标记为草稿) -
\Recent: 消息"最近"到达此邮箱. 此会话是第一个收到有关此消息通知的会话, 如果会话是可读写的, 则后续会话不会看到此消息设置了\Recent. 客户端无法更改此标志.如果无法确定此会话是否是第一个收到有关消息通知的会话, 则该消息应该 (SHOULD) 被视为最近的.
如果多个连接同时选择了同一邮箱, 则哪个连接将看到设置了
\Recent的新到达消息, 哪个连接将看到未设置\Recent的消息是未定义的.
关键字 (Keyword) 由服务器实现定义. 关键字不以 \ 开头. 服务器可以 (MAY) 允许客户端在邮箱中定义新关键字 (有关更多信息, 请参阅 PERMANENTFLAGS 响应代码的描述).
标志可以是永久的或仅会话的, 基于每个标志. 永久标志 (Permanent Flags) 是客户端可以永久添加或从消息标志中删除的标志, 即, 并发和后续会话将看到永久标志的任何更改. 对会话标志 (Session Flags) 的更改仅在该会话中有效.
注意: \Recent 系统标志是会话标志的特殊情况. \Recent 不能用作 STORE 或 APPEND 命令中的参数, 因此根本无法更改.
2.3.3. Internal Date Message Attribute (内部日期消息属性)
服务器上消息的内部日期和时间. 这不是 [RFC-2822] 头部中的日期和时间, 而是反映消息何时被接收的日期和时间. 对于通过 [SMTP] 传递的消息, 这应该 (SHOULD) 是 [SMTP] 定义的消息最终传递的日期和时间. 对于由 IMAP4rev1 COPY 命令传递的消息, 这应该 (SHOULD) 是源消息的内部日期和时间. 对于由 IMAP4rev1 APPEND 命令传递的消息, 这应该 (SHOULD) 是 APPEND 命令描述中指定的日期和时间. 所有其他情况由实现定义.
2.3.4. [RFC-2822] Size Message Attribute (RFC-2822 大小消息属性)
以 [RFC-2822] 格式表示的消息中的八位字节数.
2.3.5. Envelope Structure Message Attribute (信封结构消息属性)
消息的 [RFC-2822] 头部的解析表示. 请注意, IMAP 信封结构与 [SMTP] 信封不同.
2.3.6. Body Structure Message Attribute (正文结构消息属性)
消息的 [MIME-IMB] 正文结构信息的解析表示.
2.4. Message Texts (消息文本)
除了能够获取消息的完整 [RFC-2822] 文本外, IMAP4rev1 还允许获取完整消息文本的部分内容. 具体来说, 可以获取 [RFC-2822] 消息头部, [RFC-2822] 消息正文, [MIME-IMB] 正文部分或 [MIME-IMB] 头部.
术语表 (本章重点术语):
- Tag (标签): 客户端命令的唯一标识符
- Untagged Response (未标记响应): 以
*开头的服务器响应 - UID (唯一标识符): 消息的永久标识符
- Message Sequence Number (消息序列号): 消息在邮箱中的相对位置
- UIDVALIDITY (UID有效性): 用于检测 UID 更改的值
- Flags (标志): 消息的状态标记
- System Flag (系统标志): 以
\开头的预定义标志 - Keyword (关键字): 用户定义的标志
- Internal Date (内部日期): 消息到达服务器的时间
- Envelope (信封): 消息头部的解析表示
- Body Structure (正文结构): 消息 MIME 结构的解析表示