摘要

  • RFC 3676 增加 DelSp,让接收端区分“原文中连接词语的空格”和“发送端专为标记软换行而插入的空格”。
  • 默认值是 no。对很少或不使用 ASCII 空格的文字,新的换行方式必须声明 DelSp=yes,这样接收端拼接行时才会删去标记,而不会在原文中凭空添字。

行尾的一个空格,看上去微不足道,却可能有两种来历。在 text/plain; format=flowed 中,它可以表示段落还没有结束,下一物理行要接着读;但这个空格也可能原本就在两个词之间,也可能由邮件客户端临时加上。2004 年发布的 RFC 3676 用 DelSp 明确区分这两种情况。它取代 RFC 2646,保留 flowed 文本,同时补上接收端重组软换行所需的信号。(第 4 至 4.2 节。)

旧方法只能在原文已有词间空格的地方折行。发送端在这个空格之后插入 CRLF;接收端把物理行接回去时,原有空格仍须保留。因此,RFC 3676 建议旧方法使用 DelSp=no。这是内容保留规则:那个空格本来就属于文字,并非可以随重排一起删除的版式标记。

但有些语言和字符集很少使用 ASCII 空格,甚至完全不用。此时,发送端可能找不到天然的词间空隙。新方法允许它在合适的位置插入 SP CRLF。末尾的空格表示软换行;若使用 DelSp=yes,接收端拼接时会删除这个特定空格。否则,显示层的重排就可能在原有字符序列里多造出一个字符。RFC 3676 因此要求新方法必须带 DelSp=yes。这不是让客户端猜语言,而是让发送端声明它采用了哪一种编码规则。(第 4.1 至 4.2 节。)

缺省行为也很关键。若 DelSp 未出现或取值无法识别,接收端按 no 处理;没有 Format=Flowed 时,DelSp 的语义未定义;在 text/plain; format=flowed 之外,接收端应当忽略它。因此,客户端不能仅凭行尾位置猜测空格是合成的。这样的默认值延续旧解释,但如果参数在传输中丢失,就无法还原发送端原本的意图。

标记插在哪里也会影响解析。如果发送端把标记放在已有空格之前,原有空格就会变成下一行的首字符。Flowed 文本又规定,对以空格、> 或 From 开头的行使用 space-stuffing 保护;一个位置选择便触发了额外处理。RFC 3676 建议将 SP CRLF 放在原有空格之后,从而让词间分隔符与新插入的换行标记各司其职。(第 4.2、4.4 节。)

这项规范的边界很窄:它描述线上传输的 text/plain 格式,不规定本地文件怎样存储;MIME 转码又是另一层。RFC 3676 也说明了签名、加密与文本重排的先后次序,但那属于 RFC 2646 专题稿的论点,此处不重复。规范同样不能证明某个客户端实际遵守了规则。Lu Heng 的 Note 65 提醒我们,标准写下的规则与运行中的代码是两类证据。要知道用户屏幕上究竟显示了什么,仍需有版本号的客户端和捕获到的原始邮件。

来源

  • RFC 3676,尤其第 4.1、4.2 节和附录 A。
  • RFC 2646,前一版 flowed 文本规范。
  • RFC 2046,MIME 媒体类型框架。
  • RFC 2045,MIME 邮件正文与传输编码背景。
  • Lu Heng,Note 65,明确披露的分析视角,并非实现证据。