非官方中文译本声明:本页为 IETF RFC 2045《Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies(多用途互联网邮件扩展 第一部分:互联网报文主体格式)》 的中文译本,由 ztpop.net 整理翻译,仅供学习参考。RFC 文档由 IETF 发布,受 BCP 78 与 IETF 信托法律条款约束;本译本保留原文编号与结构,权威性以英文原文为准。英文原文见 rfc-editor.org/rfc/rfc2045。
RFC 2045:MIME 第一部分(报文主体格式)
摘要
STD 11、RFC 822 定义了一种报文表示协议,对 US-ASCII 报文头给出了相当详尽的规定,而将报文内容(或称报文主体)留作扁平的 US-ASCII 文本。这套统称为多用途互联网邮件扩展(Multipurpose Internet Mail Extensions,简称 MIME)的文档,重新定义了报文的格式,使其能够支持:
- (1) 采用 US-ASCII 以外字符集的文本报文主体;
- (2) 一组可扩展的、用于非文本报文主体的不同格式;
- (3) 多部分(multi-part)报文主体;以及
- (4) 采用 US-ASCII 以外字符集的文本头信息。
这些文档基于 RFC 934、STD 11 与 RFC 1049 中记录的早期工作,但对其进行了扩展与修订。由于 RFC 822 对报文主体几乎只字未提,这些文档在很大程度上与 RFC 822 正交(而非对它的修订)。
本初始文档规定了用于描述 MIME 报文结构的各种头字段。第二份文档 RFC 2046 定义了 MIME 媒体类型系统的总体结构,并定义了初始的一组媒体类型。第三份文档 RFC 2047 描述了针对 RFC 822 的扩展,以允许互联网邮件头字段中出现非 US-ASCII 文本数据。第四份文档 RFC 2048 规定了针对 MIME 相关设施的各类 IANA 注册流程。第五份也是最后一份文档 RFC 2049 描述了 MIME 一致性准则,并提供了若干 MIME 报文格式的示例、致谢与参考文献。
这些文档是对 RFC 1521、1522 与 1590 的修订,而后者本身又是对 RFC 1341 与 1342 的修订。RFC 2049 中的一份附录描述了与先前版本的差异与变更。
本备忘录的状态
本文档为互联网社区规定了一种互联网标准跟踪(standards track)协议,并请求各方讨论并提出改进建议。有关本协议的标准化状态与现状,请参阅现行版的《互联网官方协议标准》(STD 1)。本备忘录的分发不受限制。
目录
- 1. 引言
- 2. 定义、约定与通用 BNF 语法
- 2.1. CRLF
- 2.2. 字符集
- 2.3. 报文
- 2.4. 实体
- 2.5. 主体部分
- 2.6. 主体
- 2.7. 7bit 数据
- 2.8. 8bit 数据
- 2.9. 二进制数据
- 2.10. 行
- 3. MIME 头字段
- 4. MIME-Version 头字段
- 5. Content-Type 头字段
- 5.1. Content-Type 头字段的语法
- 5.2. Content-Type 默认值
- 6. Content-Transfer-Encoding 头字段
- 6.1. Content-Transfer-Encoding 语法
- 6.2. Content-Transfer-Encoding 语义
- 6.3. 新的 Content-Transfer-Encoding
- 6.4. 解释与使用
- 6.5. 转换编码
- 6.6. 规范编码模型
- 6.7. Quoted-Printable Content-Transfer-Encoding
- 6.8. Base64 Content-Transfer-Encoding
- 7. Content-ID 头字段
- 8. Content-Description 头字段
- 9. 其他 MIME 头字段
- 10. 总结
- 11. 安全考量
- 12. 作者地址
- 附录 A. 收集语法
1. 引言
自 1982 年发布以来,RFC 822 定义了互联网上文本邮件报文的标准格式。它取得的成功如此之大,以至于 RFC 822 格式已被整体或部分地采用,远远超出了互联网以及由 RFC 821 定义的互联网 SMTP 传输的范围。随着该格式得到更广泛的使用,一些局限性对用户群体而言变得日益具有限制性。
RFC 822 意在规定一种文本报文的格式。因此,非文本报文(例如可能包含音频或图像的多媒体报文)根本未被提及。然而即便是在文本方面,对于那些需要使用比 US-ASCII 更丰富的字符集的语言的用户而言,RFC 822 也是不够的。由于 RFC 822 没有为包含音频、视频、亚洲语言文本、甚至大多数欧洲语言文本的邮件规定机制,因此需要额外的规范。
基于 RFC 821/822 的邮件系统一个显著的局限在于,它们将电子邮件报文的内容限制在相对较短的行内(例如 [RFC-821] 规定的 1000 字符或更少),且为 7bit US-ASCII。这迫使用户在调用本地邮件 UA(用户代理,即供人类用户收发邮件的程序)之前,必须将任何他们希望发送的非文本数据转换为可以用可打印的 US-ASCII 字符表示的七位字节。当前互联网上使用的此类编码包括纯十六进制、uuencode、RFC 1421 规定的 3-in-4 base 64 方案、Andrew Toolkit 表示法 [ATK] 等许多其他编码。
随着人们设计网关以允许 RFC 822 主机与 X.400 主机之间交换邮件报文,RFC 822 邮件的局限性变得更加明显。X.400 [X400] 规定了在电子邮件报文中包含非文本资料的机制。当前将 X.400 报文映射到 RFC 822 报文的标准规定,要么必须将 X.400 的非文本资料转换为(而非编码为)IA5Text 格式,要么必须将其丢弃,并通知 RFC 822 用户已发生丢弃。这显然是不可取的,因为用户可能希望接收的信息因此丢失。即便用户代理可能不具备处理非文本资料的能力,用户也可能拥有某个体现在 UA 之外的机制,能够从中提取有用信息。此外,这种做法未能考虑到报文最终可能再次经网关返回到某个 X.400 报文处理系统(即该 X.400 报文被"隧道"穿过互联网邮件)的事实,在那里非文本信息无疑会重新变得有用。
本文档描述了若干种机制,它们结合起来在不与现有的 RFC 822 邮件世界产生严重不兼容的前提下,解决了上述大部分问题。具体而言,它描述了:
- 一个 MIME-Version 头字段,它用版本号声明报文符合 MIME,并允许邮件处理代理将此类报文与由旧式或不合规软件生成的报文区分开来(后者被认为缺少此类字段)。
- 一个从 RFC 1049 泛化而来的 Content-Type 头字段,可用于指定报文主体中数据的媒体类型与子类型,并完整指定此类数据的原生表示(规范形式)。
- 一个 Content-Transfer-Encoding 头字段,可用于同时指定施加于主体的编码变换以及结果的域。除恒等(identity)变换以外的编码变换通常施加于数据,以使其能够穿越可能在数据或字符集方面存在限制的邮件传输机制。
- 两个可用于进一步描述主体中数据的附加头字段,即 Content-ID 与 Content-Description 头字段。
本文档中定义的所有头字段都受 RFC 822 为头字段规定的通用语法规则约束。特别地,除 Content-Disposition 之外,所有这些头字段都可以包含 RFC 822 注释,注释不具有语义内容,在 MIME 处理过程中应当被忽略。
最后,为规定并促进互操作性,RFC 2049 针对以上机制的子集提供了一份基本适用性声明,定义了与本文档的"一致性"的最低级别。
历史注记:这套文档中描述的若干机制,初读之下可能显得有些奇怪甚至是古怪。需要注意的是,与现有标准的兼容性,以及在既有实践中的健壮性,是开发这套文档的工作组最高的两大优先事项。特别地,兼容性始终优先于优雅性。
有关本协议的标准化状态与现状,请参阅现行版的《互联网官方协议标准》。RFC 822 以及 STD 3、RFC 1123 也为 MIME 提供了必要的背景,因为任何符合 MIME 的实现都不得违反它们。此外,MIME 实现者还会对其他若干信息类 RFC 文档感兴趣,尤其是 RFC 1344、RFC 1345 与 RFC 1524。
2. 定义、约定与通用 BNF 语法
尽管这套文档中规定的机制都用散文描述,但其中大多数也用 RFC 822 的扩展 BNF 记法进行了形式化描述。实现者需要熟悉这种记法才能理解这套文档,关于扩展 BNF 记法的完整说明请参阅 RFC 822。
这套文档中的部分扩展 BNF 以命名方式引用了 RFC 822 中定义的语法规则。因此,将本文档集中附录中的收集语法与 RFC 822 的 BNF 以及 RFC 1123(其专门更改了 `return`、`date` 与 `mailbox` 的语法)中对 RFC 822 的修改组合起来,即可得到一份完整的形式化语法。
在这套文档中,所有数值与八位组值均以十进制记法给出。所有已定义的媒体类型取值、子类型取值与参数名都不区分大小写。然而,除非针对特定参数另有说明,参数值区分大小写。
格式注记:像本条这样的注释提供了额外的、非必需的信息,读者可以跳过而不遗漏任何要点。这些非必需注释的主要目的是传达关于这套文档设计理由的信息,或将这套文档置于恰当的历史或演进语境之中。完全专注于构建合规实现的人尤其可以跳过此类信息,但希望了解某些设计选择为何如此的人可能会从中受益。
2.1. CRLF
在这套文档中,术语 CRLF 指的是对应于两个 US-ASCII 字符 CR(十进制值 13)与 LF(十进制值 10)的八位组序列,二者合在一起、且按此顺序,表示 RFC 822 邮件中的一个换行(line break)。
2.2. 字符集
在 MIME 中,"字符集(character set)"这一术语指的是将八位组序列转换为字符序列的方法。请注意,并不要求反方向无条件且无歧义的转换,因为并非所有字符都能由某个给定的字符集表示,并且一个字符集也可能用多个八位组序列来表示某个特定的字符序列。
这一定义意在允许各种字符编码被用作字符集,从 US-ASCII 这样的简单单表映射到使用 ISO 2022 技术(如码表切换方法)的复杂映射。但是,与某个 MIME 字符集名称相关联的定义必须完整指定所要执行的映射。特别地,不允许使用外部 profiling 信息来确定确切的映射。
注:"字符集"一词最初用于描述 US-ASCII 与 ISO-8859-1 这类在单个八位组与单个字符之间存在简单一一映射的方案。多八位组编码字符集与切换技术使情况变得更加复杂。例如,某些群体用"字符编码(character encoding)"表示 MIME 所称的"字符集",而用"编码字符集(coded character set)"表示从整数(而非八位组)到字符的抽象映射。
2.3. 报文
在未有进一步限定时,术语"报文(message)"指的是正在网络上传输的(完整的或"顶层"的)RFC 822 报文,或被封装于 "message/rfc822" 或 "message/partial" 类型主体中的报文。
2.4. 实体
术语"实体(entity)"特指 MIME 定义的头字段,以及报文或多部分实体主体中某个部分的主体内容。此类实体的规定正是 MIME 的本质。由于实体的内容常被称为"主体",因此谈论实体的主体是合理的。实体的头中可以出现任何种类的字段,但只有那些以 "content-" 开头的字段才真正具有 MIME 相关的含义。请注意,这并不意味着它们毫无含义——一个同时也是报文的实体拥有由 RFC 822 定义其含义的非 MIME 头字段。
2.5. 主体部分
术语"主体部分(body part)"指的是多部分实体内部的一个实体。
2.6. 主体
在未有进一步限定时,术语"主体(body)"指的是实体的主体,即报文主体或主体部分主体的主体。
注:前面这四条定义显然是循环的。这不可避免,因为 MIME 报文的总体结构确实是递归的。
2.7. 7bit 数据
"7bit 数据"指的是全部表示为相对较短的行的数据,相邻 CRLF 行分隔序列之间的八位组不超过 998 个 [RFC-821]。不允许出现十进制值大于 127 的八位组,也不允许出现 NUL(十进制值为 0 的八位组)。CR(十进制值 13)与 LF(十进制值 10)八位组仅作为 CRLF 行分隔序列的一部分出现。
2.8. 8bit 数据
"8bit 数据"指的是全部表示为相对较短的行的数据,相邻 CRLF 行分隔序列之间的八位组不超过 998 个 [RFC-821],但可以使用十进制值大于 127 的八位组。与"7bit 数据"一样,CR 与 LF 八位组仅作为 CRLF 行分隔序列的一部分出现,且不允许出现 NUL。
2.9. 二进制数据
"二进制数据"指的是允许出现任意八位组序列的数据。
2.10. 行
"行(Lines)"被定义为由 CRLF 序列分隔的八位组序列。这与 RFC 821 和 RFC 822 都一致。"行"仅指标报文中数据的单位,它可能与用户代理实际显示的内容相对应,也可能不对应。
3. MIME 头字段
MIME 定义了许多新的 RFC 822 头字段,用于描述 MIME 实体的内容。这些头字段至少出现在两种语境中:
- (1) 作为常规 RFC 822 报文头的一部分。
- (2) 在多部分结构内部的某个 MIME 主体部分头中。
这些头字段的形式化定义如下:
entity-headers := [ content CRLF ]
[ encoding CRLF ]
[ id CRLF ]
[ description CRLF ]
*( MIME-extension-field CRLF )
MIME-message-headers := entity-headers
fields
version CRLF
; 此 BNF 定义所暗示的
; 头字段顺序应被忽略。
MIME-part-headers := entity-headers
[ fields ]
; 任何不以 "content-" 开头的
; 字段都没有已定义的含义,
; 可被忽略。
; 此 BNF 定义所暗示的
; 头字段顺序应被忽略。
各种具体 MIME 头字段的语法将在后续各节中描述。
4. MIME-Version 头字段
由于 RFC 822 于 1982 年发布,互联网报文实际上只有过一种格式标准,也几乎没有人觉得有必要声明所使用的格式标准。本文档是一份对 RFC 822 进行补充的独立规范。尽管本文档中的扩展以与 RFC 822 兼容的方式定义,但在某些情形下,邮件处理代理仍可能希望知道某封报文是否是以新标准为导向而撰写的。
因此,本文档定义了一个新的头字段 "MIME-Version",用于声明所使用互联网报文主体格式标准的版本。
依据本文档撰写的报文必须包含这样一个头字段,其逐字文本如下:
MIME-Version: 1.0
该头字段的存在即断言此报文是按照本文档编写的。
由于未来的文档可能再次扩展报文格式标准,因此为 MIME-Version 字段的内容给出了一份形式化 BNF:
version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
因此,可能取代或扩展 "1.0" 的未来格式说明符被约束为两个由句点分隔的整数域。如果收到的报文其 MIME-version 值不是 "1.0",则不能假定其符合本文档。
请注意,MIME-Version 头字段在报文的顶层是必需的。对于多部分实体的每个主体部分,它并非必需。当且仅当被嵌入的报文本身声称符合 MIME 时,对于 "message/rfc822" 或 "message/partial" 类型主体的嵌入头,它才是必需的。
无法完整规定,符合本文档所定义 MIME 的邮件阅读器应如何处理未来可能到达、且 MIME-Version 取 "1.0" 以外某个值的报文。
同样值得注意的是,特定媒体类型的版本控制并非通过 MIME-Version 机制来完成。特别地,某些格式(如 application/postscript)拥有媒体格式内部的版本号约定。当此类约定存在时,MIME 不会去取代它们。当不存在此类约定时,如有必要,某个 MIME 媒体类型可以在 content-type 字段中使用 "version" 参数。
致实现者注:在检查 MIME-Version 值时,必须忽略任何出现的 RFC 822 注释字符串。特别地,以下四个 MIME-Version 字段是等价的:
MIME-Version: 1.0
MIME-Version: 1.0 (produced by MetaSend Vx.x)
MIME-Version: (produced by MetaSend Vx.x) 1.0
MIME-Version: 1.(produced by MetaSend Vx.x)0
在缺少 MIME-Version 字段时,接收邮件的用户代理(无论是否符合 MIME 要求)可以自行选择依据本地约定来解释报文主体。当前有许多此类约定在使用,并且应当注意到,在实践中非 MIME 报文几乎可以包含任何内容。
由于非 MIME 邮件报文实际上可能是某种使用早于 MIME 的非标准本地约定的报文,其中可能包含另一字符集中的文本,或以无法被自动识别的方式呈现的非文本数据(例如一个经 uuencode 压缩的 UNIX tar 文件),因此无法确定它真的是 US-ASCII 字符集中的纯文本。
5. Content-Type 头字段
Content-Type 字段的目的是充分描述主体中所包含的数据,使接收用户代理能够挑选合适的代理或机制将数据呈现给用户,或以其他恰当的方式处理数据。该字段中的取值称为媒体类型(media type)。
历史注记:Content-Type 头字段最早定义于 RFC 1049。RFC 1049 使用了一种更简单、能力更弱的语法,但在很大程度上与本文给出的机制兼容。
Content-Type 头字段通过给出媒体类型与子类型标识符,并提供某些媒体类型可能需要的辅助信息,来规定实体主体中数据的性质。在媒体类型与子类型名称之后,该头字段的其余部分就是一组以 attribute=value 记法指定的参数。参数的顺序无关紧要。
一般而言,顶层媒体类型用于声明数据的通用类型,而子类型则规定该类型数据的具体格式。因此,媒体类型 "image/xyz" 足以告诉用户代理该数据是图像,即使用户代理并不知道具体的图像格式 "xyz"。例如,此类信息可用于决定是否向用户显示来自无法识别的子类型的原始数据——对于无法识别的 text 子类型,这样的动作是合理的,但对于无法识别的 image 或 audio 子类型则不然。出于此原因,text、image、audio 与 video 的已注册子类型不应包含实际上属于不同类型的内嵌信息。此类复合格式应当使用 "multipart" 或 "application" 类型来表示。
参数是媒体子类型的修饰符,因而从根本上不影响内容的性质。有意义的参数集合取决于媒体类型与子类型。大多数参数与某个单一的特定子类型相关联。然而,某个给定的顶层媒体类型可以定义适用于该类型任何子类型的参数。参数可能由其定义的 Content 类型或子类型要求为必需,也可能是可选的。MIME 实现必须忽略任何它们无法识别的参数名。
例如,"charset" 参数适用于 "text" 的任何子类型,而 "boundary" 参数则是 "multipart" 媒体类型任何子类型所必需的。
不存在适用于所有媒体类型的、具有全局意义的参数。在 MIME 模型中,真正的全局机制最好通过定义额外的 Content-* 头字段来解决。
RFC 2046 中定义了一组初始的七个顶层媒体类型。其中五个是离散类型,就 MIME 处理而言其内容基本上是不可穿透的(opaque)。其余两个是复合类型,其内容需要 MIME 处理器做额外处理。
这组顶层媒体类型的设定意在做到基本完备。预计对受支持类型这一更大集合的扩充,通常可以通过创建这些初始类型的新子类型来完成。未来,只有通过对本标准进行标准跟踪扩展,才可能定义更多的顶层类型。如果出于任何原因要使用另一个顶层类型,必须给它一个以 "X-" 开头的名称,以表明其非标准状态,并避免与未来的官方名称产生潜在冲突。
5.1. Content-Type 头字段的语法
在 RFC 822 的扩展 BNF 记法中,Content-Type 头字段的取值定义如下:
content := "Content-Type" ":" type "/" subtype
*(";" parameter)
; 媒体类型与子类型的匹配
; 总是大小写不敏感的。
type := discrete-type / composite-type
discrete-type := "text" / "image" / "audio" / "video" /
"application" / extension-token
composite-type := "message" / "multipart" / extension-token
extension-token := ietf-token / x-token
ietf-token := <由标准跟踪 RFC 定义、
并在 IANA 注册的扩展记号。>
x-token := <两个字符 "X-" 或 "x-" 后面紧跟
(中间无空白)任意记号>
subtype := extension-token / iana-token
iana-token := <一个公开定义的扩展记号。此类
记号必须按 RFC 2048 的规定在
IANA 注册。>
parameter := attribute "=" value
attribute := token
; 属性的匹配
; 总是大小写不敏感的。
value := token / quoted-string
token := 1*<除 SPACE、CTL 以及
tspecials 之外的任意
(US-ASCII) 字符>
tspecials := "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "\" / <">
"/" / "[" / "]" / "?" / "="
; 在参数值中使用时
; 必须置于 quoted-string 中
请注意,"tspecials" 的定义与 RFC 822 中 "specials" 的定义相同,只是增加了三个字符 "/"、"?" 与 "=",并去掉了 "."。
还需注意,子类型规定是强制性的——它不能从 Content-Type 头字段中省略。因此,不存在默认子类型。
类型、子类型与参数名不区分大小写。例如,TEXT、Text 与 TeXt 都是等价的顶层媒体类型。参数值通常区分大小写,但有时会以不区分大小写的方式解释,这取决于预期用途(例如,multipart 边界是大小写敏感的,但 message/External-body 的 "access-type" 参数则不区分大小写)。
请注意,带引号字符串参数的值不包含引号。也就是说,quoted-string 中的引号并非参数值的一部分,而仅仅用于界定该参数值。此外,根据 RFC 822 针对结构化头字段的规则,允许出现注释。因此以下两种形式
Content-type: text/plain; charset=us-ascii (Plain text)
Content-type: text/plain; charset="us-ascii"
是完全等价的。
除本语法之外,对子类型名称定义唯一的句法约束,是希望它们的用途不得冲突。也就是说,若两个不同的群体都用 "Content-Type: application/foobar" 来表示两种不同的事物,那是不可取的。因此,定义新媒体子类型的过程并非意在成为一种施加限制的机制,而仅仅是一种公布其定义与用法的机制。于是,定义新媒体子类型有两种可接受的方式:
- (1) 私有取值(以 "X-" 开头)可在两个协作的代理之间双边定义,无需外部注册或标准化。此类取值不能被注册或标准化。
- (2) 新的标准取值应按 RFC 2048 的描述在 IANA 注册。
这套文档中的第二份文档 RFC 2046,定义了 MIME 的初始媒体类型集合。
5.2. Content-Type 默认值
本协议将没有 MIME Content-Type 头的默认 RFC 822 报文视为 US-ASCII 字符集中的纯文本,可显式指定为:
Content-type: text/plain; charset=us-ascii
若未指定 Content-Type 头字段,则假定为此默认值。同时也建议,在遇到句法无效的 Content-Type 头字段时也假定为此默认值。在存在 MIME-Version 头字段且不存在任何 Content-Type 头字段的情况下,接收用户代理也可以假定发送者的意图是纯 US-ASCII 文本。在缺少 MIME-Version 或存在句法无效的 Content-Type 头字段的情况下,仍可以假定为纯 US-ASCII 文本,但发送者的意图可能并非如此。
6. Content-Transfer-Encoding 头字段
许多本可通过电子邮件有效传输的媒体类型,是以 8bit 字符或二进制数据的"自然"格式表示的。此类数据无法通过某些传输协议传输。例如,RFC 821(SMTP)将邮件报文限制为 7bit US-ASCII 数据,且每行不超过 1000 个字符(含任何尾部 CRLF 行分隔符)。
因此,有必要定义一种标准机制,将此类数据编码为 7bit 短行格式。对于直接经由限制较少的传输使用、以限制较少格式表示的未编码资料,妥善地加以标注也是可取的。本文档规定,此类编码将由一个新的 "Content-Transfer-Encoding" 头字段来指示。该字段此前未被任何标准定义过。
6.1. Content-Transfer-Encoding 语法
Content-Transfer-Encoding 字段的取值是一个单独的记号,指定如下所枚举的编码类型。形式化定义如下:
encoding := "Content-Transfer-Encoding" ":" mechanism
mechanism := "7bit" / "8bit" / "binary" /
"quoted-printable" / "base64" /
ietf-token / x-token
这些取值不区分大小写——Base64、BASE64 与 bAsE64 全都等价。编码类型为 7BIT 要求主体已经处于一种 7bit 的、可邮件化的表示中。这是默认值——也就是说,若 Content-Transfer-Encoding 头字段不存在,则假定为 "Content-Transfer-Encoding: 7BIT"。
6.2. Content-Transfer-Encoding 语义
这一个 Content-Transfer-Encoding 记号实际上提供了两部分信息。它规定了主体经受了何种编码变换,从而规定了必须采用何种解码操作才能将其恢复为原始形式,并且它规定了结果所处的域。
任何 Content-Transfer-Encoding 的变换部分,要么显式要么隐式地规定了一个单一的、定义良好的解码算法;对于任意编码八位组序列,该算法要么将其变换为被编码的原始八位组序列,要么表明它作为编码序列是非法的。Content-Transfer-Encoding 变换的正确运作从不依赖任何额外的外部 profiling 信息。请注意,虽然解码器对合法编码必须产生单一、定义良好的输出,但对编码器则无此类限制:将给定八位组序列编码为不同的、等价的编码序列是完全合法的。
当前定义了三种变换:恒等变换、"quoted-printable" 编码与 "base64" 编码。其域分别为 "binary"、"8bit" 与 "7bit"。
Content-Transfer-Encoding 取值 "7bit"、"8bit" 与 "binary" 都表示已施加了恒等(即无)编码变换。因此,它们仅作为主体数据域的指示器,并提供关于在给定的传输系统中可能需要何种编码的有用信息。术语 "7bit 数据"、"8bit 数据" 与 "二进制数据" 都在第 2 节中定义。
quoted-printable 与 base64 编码将其输入从任意域变换为 "7bit" 范围内的资料,从而使其能够安全地通过受限的传输。这些变换的具体定义见下文。
必须始终使用恰当的 Content-Transfer-Encoding 标签。将包含 8bit 字符的未编码数据标为 "7bit" 是不允许的,将未采用面向行表示的未编码数据标为 "binary" 以外的任何值也不允许。
与媒体子类型不同,Content-Transfer-Encoding 取值的泛滥既不可取也不必要。然而,仅确立一种进入 "7bit" 域的变换似乎并不可行。在希望得到大体为二进制数据的紧凑高效编码,与希望得到大体(但并非完全)为 7bit 的数据的某种可读编码之间,存在权衡。出于此原因,至少两种编码机制是必要的:一种多少可读的编码(quoted-printable)与一种"密集"或"均匀"的编码(base64)。
未编码 8bit 数据的邮件传输在 RFC 1652 中定义。在本文档最初发布时,尚不存在任何标准化的互联网邮件传输,使得在邮件主体中包含未编码的二进制数据是合法的。因此在互联网邮件中,"binary" Content-Transfer-Encoding 实际有效的情况并不存在。然而,一旦二进制邮件传输在互联网邮件中成为现实,或者当 MIME 与任何其他具备二进制能力的邮件传输机制一起使用时,二进制主体必须如此标注。
注:为 Content-Transfer-Encoding 字段定义的五个取值,除了它所经由的编码算法或(若未编码)传输系统要求之外,对媒体类型不隐含任何信息。
6.3. 新的 Content-Transfer-Encoding
如有必要,实现者可以定义私有的 Content-Transfer-Encoding 取值,但必须使用 x-token,即以 "X-" 为前缀的名称,来表明其非标准状态,例如 "Content-Transfer-Encoding: x-my-new-encoding"。额外的标准化 Content-Transfer-Encoding 取值必须由标准跟踪 RFC 规定。此类规范必须满足的要求在 RFC 2048 中给出。因此,除以 "X-" 开头的名称空间之外,所有 content-transfer-encoding 名称空间都明确保留给 IETF 将来使用。
与媒体类型和子类型不同,强烈不鼓励创建新的 Content-Transfer-Encoding 取值,因为这似乎可能以极小的潜在收益阻碍互操作性。
6.4. 解释与使用
如果 Content-Transfer-Encoding 头字段作为报文头的一部分出现,它适用于该报文整个主体。如果它作为某个实体的头的一部分出现,则仅适用于该实体的主体。如果某个实体是 "multipart" 类型,则 Content-Transfer-Encoding 不允许取 "7bit"、"8bit" 或 "binary" 以外的任何值。对 "message" 类型的某些子类型适用更严格的限制。
应当注意,大多数媒体类型是以八位组而非位来定义的,因此此处描述的机制是对任意八位组流而非位流进行编码的机制。如果要用这些机制之一对位流编码,则必须首先使用网络标准位序("big-endian",高位在前)将其转换为 8bit 字节流,其中流中较早的位成为 8bit 字节中的高位。未结束在 8bit 边界上的位流必须以零填充。RFC 2046 为 application/octet-stream 媒体类型(其拥有 "padding" 参数)提供了标注此类填充添加的机制。
此处定义的编码机制显式地将所有数据以 US-ASCII 编码。因此,举例来说,假设某个实体具有如下头字段:
Content-Type: text/plain; charset=ISO-8859-1
Content-transfer-encoding: base64
这必须解释为:该主体是原本为 ISO-8859-1、经 base64 的 US-ASCII 编码后的数据,解码后将再次回到该字符集。
某些 Content-Transfer-Encoding 取值只能用于某些媒体类型。特别地,明确禁止对任何复合媒体类型(即递归包含其他 Content-Type 字段的类型)使用 "7bit"、"8bit" 或 "binary" 以外的任何编码。当前唯一的复合媒体类型是 "multipart" 与 "message"。期望施加于 multipart 或 message 类型主体上的所有编码,必须在最内层通过编码实际需要编码的实际主体来完成。
还应当注意,根据定义,如果一个复合实体具有诸如 "7bit" 这样的 transfer-encoding 取值,但其内部某个被包含实体却具有诸如 "8bit" 这样限制较小的取值,那么要么外部的 "7bit" 标注有误(因为包含了 8bit 数据),要么内部的 "8bit" 标注对传输系统施加了不必要的高要求(因为实际包含的数据其实是 7bit 安全的)。
关于编码限制的注:尽管禁止对复合主体数据使用 content-transfer-encoding 似乎过于严格,但这是为防止嵌套编码所必须的;嵌套编码中数据会多次通过编码算法,也必须多次解码才能被正确查看。嵌套编码给用户代理增加了相当程度的复杂性:除了此类多重编码明显的效率问题外,它们还会掩盖报文的基本结构。特别地,它们可能暗示需要多次解码操作,仅仅是为了弄清报文包含哪些类型的主体。禁止嵌套编码可能会给某些邮件网关的工作带来麻烦,但这似乎比嵌套编码对用户代理的影响问题更小。
任何具有无法识别的 Content-Transfer-Encoding 的实体,无论 Content-Type 头字段实际说了什么,都必须被视为具有 "application/octet-stream" 的 Content-Type。
关于 Content-Type 与 Content-Transfer-Encoding 之间关系的注:或许会认为 Content-Transfer-Encoding 可以从待编码媒体的特征推断出来,或者至少可以强制将某些 Content-Transfer-Encoding 与特定媒体类型搭配使用。情况并非如此,原因如下。首先,鉴于用于邮件的传输类型各不相同,某些编码可能适用于某些媒体类型与传输的组合,但不适用于其他组合(例如,在 8bit 传输中,某些字符集的文本无需编码,而在 7bit SMTP 中此类编码显然必需)。其次,某些媒体类型在不同情况下可能需要不同类型的传输编码。例如,许多 PostScript 主体可能完全由 7bit 数据的短行组成,因而完全不需要编码;其他 PostScript 主体(尤其是那些使用 Level 2 PostScript 二进制编码机制的)可能只有用二进制传输编码才能合理地表示。最后,由于 Content-Type 字段意在成为一种开放式的规范机制,严格规定媒体类型与编码之间的关联实际上是将应用层协议的规范与某个特定的低层传输耦合在了一起。这并不可取,因为媒体类型的开发者不必去了解所有在用传输及其限制。
6.5. 转换编码
quoted-printable 与 base64 编码的设计使得二者之间可以相互转换。此类转换中唯一出现的问题,是 quoted-printable 编码输出中硬换行(hard line break)的处理。当从 quoted-printable 转换到 base64 时,quoted-printable 形式中的硬换行表示数据规范形式中的一个 CRLF 序列。因此必须将其转换为 base64 形式数据中相应的已编码 CRLF。类似地,base64 解码后所得数据的规范形式中的 CRLF 序列必须转换为 quoted-printable 的硬换行,但仅在转换文本数据时才如此。
6.6. 规范编码模型
在本 RFC 的先前版本中,关于何时将电子邮件数据转换为规范形式并加以编码,尤其是考虑到换行在不同系统间差异极大、以及 content-transfer-encoding 与字符集之间的关系,这一模型存在一些混淆。出于此原因,RFC 2049 给出了一个用于编码的规范模型。
6.7. Quoted-Printable Content-Transfer-Encoding
Quoted-Printable 编码意在表示大体上由对应于 US-ASCII 字符集中可打印字符的八位组所组成的数据。它对数据进行编码,使得所得八位组不大可能被邮件传输修改。如果被编码的数据大多是 US-ASCII 文本,那么编码后的数据形式在很大程度上仍可被人类识别。完全由 US-ASCII 组成的主体也可以编码为 Quoted-Printable,以确保数据的完整性——如果报文要穿越一个会进行字符转换和/或行折(line-wrapping)的网关的话。
在此编码中,八位组按以下规则表示:
- (通用 8bit 表示)除属于被编码数据规范(标准)形式的 CRLF 换行一部分的 CR 或 LF 之外,任何八位组都可以用一个 "=" 后跟该八位组值的两位十六进制表示来代表。为此目的,十六进制字母表使用的数字是 "0123456789ABCDEF"。必须采用大写字母;不允许小写字母。因此,例如十进制值 12(US-ASCII 的 form feed)可以表示为 "=0C",十进制值 61(US-ASCII 的等号)可以表示为 "=3D"。必须遵循此规则,除非下列规则允许另一种编码方式。
- (字面表示)十进制值为 33 至 60(含)以及 62 至 126(含)的八位组,可以表现为与这些八位组相对应的 US-ASCII 字符(分别是感叹号至小于号,以及大于号至波浪号)。
- (空白)值为 9 和 32 的八位组可以表现为 US-ASCII 的 TAB(HT)与 SPACE 字符,但在编码行的行末不得如此表现。因此,编码行上的任何 TAB(HT)或 SPACE 字符在该行上必须后跟一个可打印字符。特别地,编码行行末的 "=",表示软换行(见规则 #5),可以后跟一个或多个 TAB(HT)或 SPACE 字符。由此可知,出现在编码行行末、十进制值为 9 或 32 的八位组必须按规则 #1 表示。此规则是必要的,因为已知某些 MTA(邮件传输代理,即把报文从一个用户传输到另一个用户的程序,或执行此类传输的一部分的程序)会用 SPACE 填充文本行,而其他 MTA 已知会删除行末的"空白"字符。因此,在解码 Quoted-Printable 主体时,行上任何尾部空白都必须被删除,因为它必然是由中间传输代理添加的。
- (换行)文本主体中的换行,在文本规范形式中表现为 CRLF 序列,在 Quoted-Printable 编码中必须表现为(RFC 822 的)换行,即也是一个 CRLF 序列。由于除 text 以外的媒体类型的规范表示通常不包括以 CRLF 序列表示的换行,因此在对此类类型的 quoted-printable 编码中不会出现硬换行(即意在具有含义、并要显示给用户的换行)。当然,像 "=0D"、"=0A"、"=0A=0D" 与 "=0D=0A" 这样的序列会例行地出现在以 quoted-printable 表示的非文本数据中。
- (软换行)Quoted-Printable 编码要求编码行长度不超过 76 个字符。如果要使用 Quoted-Printable 编码对更长的行编码,则必须使用"软"换行。作为编码行最后一个字符的等号,表示该编码文本中一个非显著的("软")换行。
因此,如果该行的"原始"形式是一行未经编码、内容为:
Now's the time for all folk to come to the aid of their country.
那么它可以用 Quoted-Printable 编码表示为:
Now's the time =
for all folk to come=
to the aid of their country.
这提供了一种机制,使长行以一种能被用户代理还原的方式被编码。76 字符的限制不计算尾部 CRLF,但计算所有其他字符,包括任何等号。
由于连字符("-")在 Quoted-Printable 编码中可以表现为自身,当将一个 quoted-printable 编码的主体封装在一个或多个多部分实体内部时,必须小心确保边界分隔符不会出现在编码主体的任何地方。(一个好的策略是选择一个包含诸如 "=_" 这样在 quoted-printable 主体中永远不会出现的字符序列的边界。见 RFC 2046 中对多部分报文的定义。)
注:quoted-printable 编码在传输的可读性与可靠性之间是一种折中。以 quoted-printable 编码的主体在大多数邮件网关上都能可靠工作,但在少数网关(尤其是涉及转换为 EBCDIC 的那些)上可能无法完美工作。Base64 Content-Transfer-Encoding 提供了更高一级的把握。要通过 EBCDIC 网关获得相当可靠的传输,一种方法是将以下的 US-ASCII 字符也按规则 #1 加以引用:
!"#$@[\]^`{|}~
由于 quoted-printable 数据通常被认为是面向行的,可以预期 quoted-printable 数据各行之间换行表示的间隔在传输中可能会改变,这与纯文本邮件在具有不同换行约定的系统间传递时一贯被更改的方式相同。如果此类更改可能构成对数据的损坏,那么使用 base64 编码而非 quoted-printable 编码可能更明智。
注:有若干种子串无法根据 quoted-printable content-transfer-encoding 的编码规则生成,因此如果它们出现在 quoted-printable 编码器的输出中,则在形式上是非法的。本注列举这些情况,并建议如果在待解码的 quoted-printable 数据中发现此类非法子串时应如何处理。
- 一个 "=" 后跟两个十六进制数字,其中一位或两位是小写字母 "abcdef" 中的字母,这在形式上是非法的。健壮的实现可以选择将它们识别为相应的大写字母。
- 一个 "=" 后跟一个既不是十六进制数字(包括 "abcdef")也不是 CRLF 对中 CR 字符的字符,是非法的。这种情况可能是 US-ASCII 文本未经自身 quoted-printable 编码就被包含进报文 quoted-printable 部分的结果。健壮的实现可以采取的一种合理做法是,将 "=" 字符及其后一个字符不加变换地纳入解码数据,并在可能时向用户表明此点处的正确解码无法完成。
- 一个 "=" 不能是编码对象的倒数第一个或倒数第二个字符。这可以按上述情况 (2) 处理。
- 除 TAB,或作为 CRLF 对一部分的 CR 与 LF 之外,控制字符不得出现。十进制值大于 126 的八位组同样如此。如果解码器在传入的 quoted-printable 数据中发现它们,健壮的实现可以将它们排除在解码数据之外,并警告用户发现了非法字符。
- 编码行长度不得超过 76 个字符,不计算尾部 CRLF。如果在传入的编码数据中发现更长的行,健壮的实现仍可以解码这些行,并可能向用户报告编码有误。
致实现者警告:如果将二进制数据编码为 quoted-printable,必须小心将 CR 与 LF 字符分别编码为 "=0D" 与 "=0A"。特别地,二进制数据中的 CRLF 序列应编码为 "=0D=0A"。否则,如果 CRLF 被表示为硬换行,在无换行约定差异的平台上可能会被错误解码。
对形式主义者而言,quoted-printable 数据的语法由以下文法描述:
quoted-printable := qp-line *(CRLF qp-line)
qp-line := *(qp-segment transport-padding CRLF)
qp-part transport-padding
qp-part := qp-section
; 最大长度为 76 个字符
qp-segment := qp-section *(SPACE / TAB) "="
; 最大长度为 76 个字符
qp-section := [*(ptext / SPACE / TAB) ptext]
ptext := hex-octet / safe-char
safe-char := <十进制值为 33 至 60(含)
以及 62 至 126 的任意八位组>
; RFC 2049 中未列为 "mail-safe" 的
; 字符也不推荐使用。
hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
; 对于 > 127、=、行末的 SPACE 或
; TAB 的字符必须使用八位组,并且
; 对于任何未在 RFC 2049 中列为
; "mail-safe" 的字符推荐使用。
transport-padding := *LWSP-char
; 生成者不得生成长度
; 非零的传输填充,但
; 接收者必须能够处理由
; 报文传输添加的填充。
重要:由于此 BNF 未规定结构化头字段,因此不允许在此 BNF 所示元素之间添加 LWSP。
6.8. Base64 Content-Transfer-Encoding
Base64 Content-Transfer-Encoding 设计用于将任意八位组序列表示为一种不必人类可读的形式。编码与解码算法都很简单,但编码后的数据始终只比未编码数据大约 33%。此编码与 RFC 1421 定义的隐私增强邮件(PEM)应用中所用的编码几乎相同。
使用了一个由 65 个字符组成的 US-ASCII 子集,使得每个可打印字符可表示 6 位(额外的第 65 个字符 "=" 用于表示一个特殊的加工功能)。
注:此子集有一个重要特性:它在 ISO 646 的所有版本(包括 US-ASCII)中都以相同方式表示,并且该子集中的所有字符在 EBCDIC 的所有版本中也以相同方式表示。其他流行的编码,如 uuencode 实用程序使用的编码、Macintosh binhex 4.0 [RFC-1741],以及作为 Level 2 PostScript 一部分规定的 base85 编码,都不具备这些特性,因而不能满足邮件二进制传输编码必须满足的可移植性要求。
编码过程将 24 位一组的输入位表示为 4 个编码字符组成的输出字符串。从左向右进行,将 3 个 8 位输入组拼接形成一个 24 位输入组。然后将这 24 位视为 4 个拼接的 6 位组,每个 6 位组被翻译成 base64 字母表中的一个数字。通过 base64 编码对位流编码时,必须假定该位流以最高有效位在前的顺序排列。也就是说,流中的第一个位是第一个 8 位字节中的高位,第八位是第一个 8 位字节中的低位,依此类推。
每个 6 位组用作一个包含 64 个可打印字符的数组的索引。由索引引用的字符被放入输出字符串。下面表 1 中标识的这些字符经过挑选,以便普遍可表示,并且该集合排除了对 SMTP(例如 "."、CR、LF)以及对 RFC 2046 定义的多部分边界分隔符(例如 "-")具有特殊意义的字符。
| 值 | 编码 | 值 | 编码 | 值 | 编码 | 值 | 编码 |
|---|---|---|---|---|---|---|---|
| 0 | A | 17 | R | 34 | i | 51 | z |
| 1 | B | 18 | S | 35 | j | 52 | 0 |
| 2 | C | 19 | T | 36 | k | 53 | 1 |
| 3 | D | 20 | U | 37 | l | 54 | 2 |
| 4 | E | 21 | V | 38 | m | 55 | 3 |
| 5 | F | 22 | W | 39 | n | 56 | 4 |
| 6 | G | 23 | X | 40 | o | 57 | 5 |
| 7 | H | 24 | Y | 41 | p | 58 | 6 |
| 8 | I | 25 | Z | 42 | q | 59 | 7 |
| 9 | J | 26 | a | 43 | r | 60 | 8 |
| 10 | K | 27 | b | 44 | s | 61 | 9 |
| 11 | L | 28 | c | 45 | t | 62 | + |
| 12 | M | 29 | d | 46 | u | 63 | / |
| 13 | N | 30 | e | 47 | v | (pad) | = |
| 14 | O | 31 | f | 48 | w | ||
| 15 | P | 32 | g | 49 | x | ||
| 16 | Q | 33 | h | 50 | y |
编码输出流必须以每行不超过 76 个字符表示。所有换行或其他未出现在表 1 中的字符,解码软件都必须忽略。在 base64 数据中,表 1 之外的字符、换行以及其他空白,可能表明发生了传输错误,在某些情况下或许适宜给出警告消息甚至拒绝报文。
如果被编码数据末尾可用的位不足 24 位,则执行特殊处理。在主体末尾总是会完成一个完整的编码量子。当输入组中可用的输入位少于 24 位时,会在右侧补零,以构成整数个 6 位组。数据末尾的填充使用 "=" 字符完成。由于所有 base64 输入都是整数个八位组,只可能出现以下情况:(1) 编码输入的最终量子是 24 位的整数倍;此时最终的编码输出单元将是 4 个字符的整数倍,没有 "=" 填充;(2) 编码输入的最终量子恰好为 8 位;此时最终的编码输出单元将是两个字符后跟两个 "=" 填充字符;或 (3) 编码输入的最终量子恰好为 16 位;此时最终的编码输出单元将是三个字符后跟一个 "=" 填充字符。
由于 "=" 字符仅用于数据末尾的填充,因此任何 "=" 字符的出现都可以作为数据已到达末尾(在传输中未被截断)的证据。然而,当传输的八位组数是 3 的倍数且不存在 "=" 字符时,则无法提供此类保证。
base64 编码数据中,base64 字母表之外的任何字符都应被忽略。
如果对尚未转换为规范形式的文本资料直接施加 base64 编码,必须小心使用恰当的八位组表示换行。特别地,文本换行必须在 base64 编码之前转换为 CRLF 序列。需要注意的重要一点是,在某些实现中,这可能由编码器直接完成,而无需预先的规范化步骤。
注:无需担心在多部分实体内对 base64 编码主体中可能存在的边界分隔符进行引用,因为 base64 编码中不使用连字符。
7. Content-ID 头字段
在构建高级用户代理时,可能希望允许一个主体引用另一个主体。因此,主体可以使用 "Content-ID" 头字段加以标注,其句法与 "Message-ID" 头字段完全相同:
id := "Content-ID" ":" msg-id
与 Message-ID 取值一样,Content-ID 取值必须生成为全球唯一的。
Content-ID 取值可用于在多种语境中唯一标识 MIME 实体,特别是用于缓存由 message/external-body 机制引用的数据。尽管 Content-ID 头通常是可选的,但在生成可选 MIME 媒体类型 "message/external-body" 数据的实现中,它的使用是强制性的。也就是说,每个 message/external-body 实体都必须有一个 Content-ID 字段,以允许对此类数据进行缓存。
同样值得注意的是,在 multipart/alternative 媒体类型的情况下,Content-ID 取值具有特殊语义。这点在 RFC 2046 中论述 multipart/alternative 的小节中加以解释。
8. Content-Description 头字段
常常希望将某些描述性信息与给定主体相关联。例如,将一个 "image" 主体标记为"奋进号航天飞机的照片"可能很有用。此类文本可以放在 Content-Description 头字段中。此头字段始终可选。
description := "Content-Description" ":" *text
该描述被假定以 US-ASCII 字符集给出,尽管 RFC 2047 规定的机制可用于非 US-ASCII 的 Content-Description 取值。
9. 其他 MIME 头字段
未来的文档可以选择为各种目的定义额外的 MIME 头字段。任何进一步描述报文内容的新头字段都应以字符串 "Content-" 开头,以便出现在报文头中的此类字段能与普通的 RFC 822 报文头字段区分开来。
MIME-extension-field := <任何以字符串
"Content-" 开头的
RFC 822 头字段>
10. 总结
使用 MIME-Version、Content-Type 与 Content-Transfer-Encoding 头字段,可以标准化的方式将任意类型的数据包含在符合 RFC 822 的邮件报文中。既不违反 RFC 821 或 RFC 822 施加的任何限制,也注意避免了由某些互联网邮件传输机制特性所施加的额外限制所引起的问题(见 RFC 2049)。
这套文档中的下一份文档 RFC 2046,规定了可以用这些头字段标注并传输的初始媒体类型集合。
11. 安全考量
安全问题在本套文档的第二份文档 RFC 2046 中讨论。
12. 作者地址
欲了解更多信息,最好经由互联网邮件联系本文档的作者:
Ned Freed
Innosoft International, Inc.
1050 East Garvey Avenue South
West Covina, CA 91790
USA
电话:+1 818 919 3600
传真:+1 818 919 3614
电子邮件:ned@innosoft.com
Nathaniel S. Borenstein
First Virtual Holdings
25 Washington Avenue
Morristown, NJ 07960
USA
电话:+1 201 540 8967
传真:+1 201 993 3032
电子邮件:nsb@nsb.fv.com
MIME 是互联网工程任务组(IETF)RFC 822 扩展工作组的工作成果。该组主席 Greg Vaudreuil 可通过以下方式联系:
Gregory M. Vaudreuil
Octel Network Services
17080 Dallas Parkway
Dallas, TX 75248-1905
USA
电子邮件:Greg.Vaudreuil@Octel.Com
附录 A. 收集语法(Collected Grammar)
本附录包含本文档规定的全部语法的完整 BNF 文法。
然而,仅凭本附录自身,该文法并不完整。它以名称引用了若干由 RFC 822 定义的语法规则。与其在此复述那些定义、并冒着两份文档之间出现无意差异的风险,本文档只是请读者参阅 RFC 822 以获取其余定义。凡术语未加定义之处,均指 RFC 822 的定义。
attribute := token
; 属性的匹配
; 总是大小写不敏感的。
composite-type := "message" / "multipart" / extension-token
content := "Content-Type" ":" type "/" subtype
*(";" parameter)
; 媒体类型与子类型的匹配
; 总是大小写不敏感的。
description := "Content-Description" ":" *text
discrete-type := "text" / "image" / "audio" / "video" /
"application" / extension-token
encoding := "Content-Transfer-Encoding" ":" mechanism
entity-headers := [ content CRLF ]
[ encoding CRLF ]
[ id CRLF ]
[ description CRLF ]
*( MIME-extension-field CRLF )
extension-token := ietf-token / x-token
hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
; 对于 > 127、=、行末的 SPACE 或
; TAB 的字符必须使用八位组,并且
; 对于任何未在 RFC 2049 中列为
; "mail-safe" 的字符推荐使用。
iana-token := <一个公开定义的扩展记号。此类
记号必须按 RFC 2048 的规定在
IANA 注册。>
ietf-token := <由标准跟踪 RFC 定义、
并在 IANA 注册的扩展记号。>
id := "Content-ID" ":" msg-id
mechanism := "7bit" / "8bit" / "binary" /
"quoted-printable" / "base64" /
ietf-token / x-token
MIME-extension-field := <任何以字符串
"Content-" 开头的
RFC 822 头字段>
MIME-message-headers := entity-headers
fields
version CRLF
; 此 BNF 定义所暗示的
; 头字段顺序应被忽略。
MIME-part-headers := entity-headers
[fields]
; 任何不以 "content-" 开头的
; 字段都没有已定义的含义,
; 可被忽略。
; 此 BNF 定义所暗示的
; 头字段顺序应被忽略。
parameter := attribute "=" value
ptext := hex-octet / safe-char
qp-line := *(qp-segment transport-padding CRLF)
qp-part transport-padding
qp-part := qp-section
; 最大长度为 76 个字符
qp-section := [*(ptext / SPACE / TAB) ptext]
qp-segment := qp-section *(SPACE / TAB) "="
; 最大长度为 76 个字符
quoted-printable := qp-line *(CRLF qp-line)
safe-char := <十进制值为 33 至 60(含)
以及 62 至 126 的任意八位组>
; RFC 2049 中未列为 "mail-safe" 的
; 字符也不推荐使用。
subtype := extension-token / iana-token
token := 1*<除 SPACE、CTL 以及
tspecials 之外的任意
(US-ASCII) 字符>
transport-padding := *LWSP-char
; 生成者不得生成长度
; 非零的传输填充,但
; 接收者必须能够处理由
; 报文传输添加的填充。
tspecials := "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "\" / <">
"/" / "[" / "]" / "?" / "="
; 在参数值中使用时
; 必须置于 quoted-string 中
type := discrete-type / composite-type
value := token / quoted-string
version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
x-token := <两个字符 "X-" 或 "x-" 后面紧跟
(中间无空白)任意记号>
