← RFC Reference

RFC 3030 – SMTP 二进制MIME和分块

Proposed Standard Core SMTP & Message Format Published March 2026
ELI5: 标准 SMTP 像大声朗读一本书一样逐页发送消息数据,用来表示"我完成了"的特殊词是单独一行的句号。这意味着消息中每个行首的句号都需要特殊处理(点填充)。CHUNKING 用"接下来是 5,000 字节"替代了这种方式——服务器确切地知道要接收多少数据,所以不需要转义特殊字符。BINARYMIME 更进一步,允许原始二进制数据而无需任何编码开销。

此RFC存在的原因

传统SMTP使用DATA命令传输消息内容。消息正文作为文本流发送,以仅包含句点的行(.\r\n)终止。此设计有两个问题:

RFC 3030定义了两个相关扩展来解决这些问题。CHUNKING引入BDAT命令,以显式大小的块传输数据——无需点转义。BINARYMIME建立在CHUNKING之上,允许原始二进制内容而无需任何编码。

工作原理

CHUNKING(BDAT命令)

  1. 服务器在其EHLO响应中公布CHUNKING。
  2. 客户端使用BDAT <size>代替DATA来发送恰好<size>个八位字节的块。
  3. 服务器读取恰好该数量的字节,然后发送响应。
  4. 客户端可以发送多个BDAT块。最后一个块包括LAST关键字:BDAT <size> LAST。
  5. 因为大小是显式的,所以无需点转义。

BINARYMIME

  1. 服务器在其EHLO响应中同时公布CHUNKING和BINARYMIME。
  2. 客户端在MAIL FROM命令上声明BODY=BINARYMIME。
  3. 消息数据通过BDAT发送,可能包含原始二进制内容——无需Base64编码,无需CRLF行尾要求。

SMTP示例

使用BDAT而不是DATA发送消息:

S: 220 mx.example.com ESMTP C: EHLO sender.example.net S: 250-mx.example.com S: 250-CHUNKING S: 250-BINARYMIME S: 250-SIZE 52428800 S: 250 PIPELINING C: MAIL FROM:<alice@example.net> S: 250 2.1.0 OK C: RCPT TO:<bob@example.com> S: 250 2.1.5 OK # 发送消息头和正文的第一部分(2048字节) C: BDAT 2048 C: [2048字节的消息数据] S: 250 2.0.0 2048 bytes received # 发送剩余正文(4096字节,最后一个块) C: BDAT 4096 LAST C: [4096字节的消息数据] S: 250 2.0.0 OK, 6144 bytes total, queued

使用BINARYMIME处理原始二进制内容:

C: MAIL FROM:<alice@example.net> BODY=BINARYMIME S: 250 2.1.0 OK C: RCPT TO:<bob@example.com> S: 250 2.1.5 OK # 消息包含二进制MIME部分,无需Base64编码 C: BDAT 1048576 LAST C: [1,048,576字节的原始消息,包含二进制附件] S: 250 2.0.0 OK, queued

关键技术细节

BDAT与DATA的对比

方面 DATA BDAT(CHUNKING)
终止 .\r\n(单独一行的句点) 显式字节数+LAST关键字
点转义 必需 不需要
二进制内容 必须经过Base64编码 使用BINARYMIME的原始二进制
流处理 服务器扫描以寻找终止符 服务器读取精确的字节数
多个块 不适用 是,每个块后有中间状态

块大小

没有强制的块大小。客户端通常根据可用内存和网络条件选择块大小。常见策略包括将整个消息作为单个BDAT ... LAST发送,或分割成几百KB的块。较小的块允许中间错误检测;较大的块减少协议开销。

错误恢复

如果服务器拒绝BDAT块(例如消息过大),客户端可以发出BDAT 0 LAST以干净地中止事务。这比DATA模型更简洁,其中即使客户端知道服务器会拒绝它,也必须发送整个消息和点终止符。

BINARYMIME转发

接收BINARYMIME消息的服务器不得将其转发到不支持BINARYMIME的服务器。如果下一跳未公布BINARYMIME,转发服务器必须在中继前将二进制内容部分转换为Base64编码。这是一项关键的互操作性要求。

常见错误

可交付性影响

Related RFCs