多用途Internet邮件扩展(多用途网际邮件扩充协议(MIME))

多用途Internet邮件扩展(多用途网际邮件扩充协议(MIME))

第一部分:Internet信息体格式

(RFC2045--Multipurpose Internet Mail Extensions(MIME)
Part One:Format of Internet Message Bodies)
 

本备忘录的状态

本文档讲述了一种Internet团体的Internet标准跟踪协议,它需要进一步的讨论和建议以得到改进。请参考最新版的“Internet正式协议标准” (STD1)来获得本协议的标准化程度和状态。本备忘录的发布不受任何限制。

 

摘要

 

STD11,RFC 882定义了一种信息表示协议,该协议规定了US-ASCII消息报头(message header)的详细细节,并规定消息内容(message content)和消息体(message body)为US-ASCII 文本格式。本系列文档共同被称为MIME(Multipurpose Internet Mail   Extensions),重新定义了一系列允许下列内容的信息格式:

 

(1)    非US-ASCII的字符集的文本消息体(message body)

 

(2)    不同格式的非文本消息体(message body)的扩展集

 

(3)    多部分消息体(message body)

 

(4) 非US-ASCII字符集的文本报头息

 

这套文档基于更早的文档RFC934、STD 11及RFC1049,但对它们进行了扩展和修正。由于RFC822对消息体(message body)涉及太少,所以这套文档与RFC822的相关性不大(不是修正RFC822 )。

 

本文档说明了用于描述MIME消息(message)的多种报头;第二个文档RFC2046定义了MIME媒体类型系统的总体结构并且定义了媒体类型的初始集;第三个文档是RFC 2047,它扩展了RFC822,允许在Internet邮件报头中出现非US-ASCII文本;第四个文档RFC2048说明了MIME相关程序的不同IANA注册过程;第五个也是最后一个文档RFC2049描述了MIME一致性标准,同时提供了一些关于MIME消息格式的说明性示例,还有“致谢”和“参考书目”。

 

这些文档都是RFC1521、RFC1522和RFC1590的修正版,而后面三个RFC又是RFC1341和1342的修订版。在RFC2049中的附录描述了与以前版本的不同及变化。

 
目录

1. 介绍... 3

2. 定义、约定和一般的BNF语法... 4

2.1 CRLF. 5

2.2 字符集 (Character Set)... 5

2.3 消息 (Message). 5

2.4 实体 (Entity)... 6

2.5 部分主体 (Body Part)... 6

2.6 主体 (Body)... 6

2.7 7位的数据 (7bit Data)... 6

2.8 8位的数据 (8bit Data)... 6

2.9 二进制数据 (Binary Data)... 7

2.10 行 (Lines) 7

3. MIME头字段(MIME Header Fields)... 7

4. MIME-Version头字段... 8

5. Content-Type 头字段... 9

5.1 Content-Type头字段的语法... 10

5.2 Content-Type的缺省值... 12

6. Content-Transfer-Encoding头字段... 12

6.1 Content-Transfer-Encoding 句法... 12

6.2 Content-Transfer-Encoding 语义... 13

6.3 新的Content-Transfer-Encoding. 14

6.4 解释及使用... 14

6.5编码转换... 16

6.6 规范的编码模式(Canonical Encoding Model)... 16

6.7 Quoted-Printable编码... 16

6.8 Base64 Content-Transfer-Encoding. 20

7. Content-ID 头字段... 21

8. Content-Description 头字段... 22

9. 另外的MIME头字段... 22

10. 摘要... 22

11. 安全考虑... 23

12. 作者地址... 23

附录A :收集的语法... 24

1. 介绍
自从1982年发布以来,RFC822已经定义了一个在Internet上传输文本邮件的标准格式。RFC822格式是如此的成功,它已经完全或部分的为大家所接受,其程度甚至超越了Internet或在RFC821中定义的Internet SMTP。也正是由于这种格式被广泛的使用,所以许多限制因素日益约束着使用者群体。

 

RFC822被制定为用来指定文本信息格式。这样,非文本信息――如包含音频或图像的多媒体信息――就完全没有被提及。甚至对一些文本的情况也是这样。RFC822不适用于那些需要多于US-ASCII字符集内容的使用者。因为RFC822没有定义一种机制,以允许邮件包含音频、视频、亚洲语言的文本甚至一些欧洲的语言文本,所以需要一个额外的规范来进行说明。

 

RFC821/822中的一个基于邮件系统的明显限制,就是将电子邮件消息(message)内容限制在一些由7位的US-ASCII字符组成的短行中(每行1000字节或更少[RFC821])。这就迫使使用者在用本地用户代理(UA—User Agent,用来收发邮件的程序)发送他们的邮件之前,先要将将要发送的非文本数据转换为可打印的7位的US-ASCII字符。当前在Internet上使用的编码方式有:纯十六进制、uuencode、RFC1421中说明的base 64、ATK(the Andrew Toolkit Representation)及一些其它方式。

 

当为在RFC822主机与X.400主机之间交换邮件信息而设计网关时,RFC822的局限性就更加明显了。X.400[X400]指定了一种在电子邮件消息中包含非文本内容的机制。当前,从X.400消息到RFC822消息的映射标准规定,X.400消息中的非文本部分必须要转换为IA5Text格式,否则,这些内容就会被丢弃,并在丢弃即将发生时,通报RFC822的使用者。当一个用户丢掉了他想接收的内容时,这显然是十分另人不快的。即使在用户代理不能处理非文本内容的时候,用户也可以对其采取一些额外的机制,来提取有用的信息。另外,这种处理也没有考虑到:消息最后可能会被网关转发到支持非文本信息的X.400消息处理系统中。

 

这篇文档描述了几种机制,将它们联合起来,可以解决大部分的这类问题,而不会引入与RFC822不兼容的问题。详细的说,它描述了:

 

(1)         “MIME-Version”头字段。它使用一个版本号来说明消息适用于MIME,而且允许邮件处理代理将这类消息与其它由旧版本或不适用的软件所产生的消息相区别。

 

(2)         在RFC1049中归纳的“Content-Type”头字段。用来指定消息数据的媒体类型(media type)及子类型,以及指定这些数据的本地表示方法(规范形式)。

 

(3)         “Content-Transfer-Encoding”头字段。用来指定应用于主体(body)的编码转换方式及结果所处的范围。编码转换不同于恒等转换,它通常用于使数据通过那些有数据或字符集限制的邮件传输机制。

 

(4)         两个附加的头字段:“Content-ID”、“Content-Description”。它们被用来更深层的描述主体(body)中的数据。

 

这篇文档中的所有的头字段定义都服从于RFC822中规定的句法规则。特别的,除了“Content-Disposition”以外,所有的这些头字段都可以包含RFC822注释。这些注释没有实际意义,应该在MIME处理过程中忽略。

 

最后,为了说明及促进互用性,RFC2049为以上机制的子集提供了一个基本的适用性声明。它定义了与本文档相适应的最低限度。

 

历史注释:在第一次阅读时,这组文档中所描述的几个机制看起来会有些奇怪或具有巴洛克风格。但要注意,对于开发这组文档的团体而言,与现有标准兼容以及遇到现有习惯时的稳健性,这两者具有相同的优先级。特别是“兼容性”永远优先于“简洁”。

 

请查阅当前版本的《因特网官方标准》(“Internet Official Protocol Standards”)以得到本协议的标准化状态及情况。RFC 822和STD3,RFC1123也提供了MIME的基本背景,符合MIME的实现都不会违背它们。另外,MIME的实现者也许会关心几个另外的RFC文档,特别是RFC1344、RFC1345和RFC1524。

2. 定义、约定和一般的BNF语法
虽然这组文档所定义的机制都以文字的形式给出,但仍有一部分是由RFC 822定义的BNF符号所描述。为了了解这组文档,实现者需要熟悉这些符号,并参考RFC 822,以得到这些扩充的BNF符号的完整解释。

 

本文档中的一些扩展BNF所构成的名字参考了RFC 822中的句法规则。或要获得完整的语法则要组合如下内容:本系列每个文档中收集了语法的附录、RFC 822中定义的BNF以及在RFC 1123中对RFC 822 所进行的修正。(其中给出了“return”、“data”、“mailbox”的语法变化)

 

在这组文档中,所有的数值字及字节的值都由十进制的形式给出。所有的媒体类型(media type)、子类型以及参数名称都是大小写无关的。然而,除非特别说明,否则参数内容是大小写相关的。

 

格式注释:这部分的“注释”提供了一些不重要的信息,在阅读时可以跳过它们而不会错过任何本质的东西。添加这些注释的基本目的是为了说明关于这系列文档的基础原理,或是为了将其恰当地放置于历史或发展过程中。这些信息,可以被那些只关心建立实现的人所忽略,但对那些希望懂得为什么某种设计会被应用的人来说,这些信息还是会有一定用处的。

 

2.1 CRLF
在这系列文档中,术语CRLF指一个US-ASCII字符序列。它由两个字符组成:CR(十进制值为13)和LF(十进制值为10),它们按顺序放在一起,构成RFC 822邮件的换行。

 

2.2 字符集 (Character Set)
在MIME中,术语“字符集”(character set)被用来表示一种将字节序列转换成字符序列的方法。注意,反方向不需要绝对的、明确的转换,因为并不是所有的字符都可以被一个已知的字符集描述,而且一个字符集可能提供多于一个的字节序列,来表示某字符序列。

 

本定义允许将各种类型的字符编码做为字符集使用,如从简单的单表映射(如US-ASCII)到多表转换方法(如使用ISO 2022技术)等。然而与MIME字符集名称相关的定义则必须完全说明所要执行的映射。特别的,不允许使用外部描述信息来决定精确的映射。

 

注释:术语字符集(“character set”)最初是用来描述一些简单的方案如US-ASCII和ISO-8859-1的,它们都是从单一字节到单一字符的一对一映射。多字节编码字符集和转换方法使得情况更加复杂。例如,一些团体使用术语“character encoding”,而不是MIME中所使用的术语“character set”来表示字符集,而且使用“coded character set”来抽象的表示从整数(而不是字节)到字符的映射。

 

2.3 消息 (Message)
术语“消息”(Message)在没有进一步限定的时候,表示的是在Internet上传输的(完整或“顶层”的)RFC822消息,或者表示压缩在“message/rfc822”或“message/partial”中的内容。

 

2.4 实体 (Entity)
术语“实体”(Entity)特指MIME定义的头字段(header field)及内容(content),它们存在于消息(message)及多部分实体的一部分之中。对这些实体的规范是MIME的基本内容。因为一个实体的内容经常被称为“主体”(“body”),所以关于实体主体说法是有意义的。任何字段都可以出现在实体头信息中,但是只有那些以“content-”开头的字段有真实的、与MIME相关的意义。注意,这并不意味着它们没有意义,一个没有MIME头字段的实体(或消息)的意义由RFC822所定义。

 

2.5 部分主体 (Body Part)
“body part”指的是多部分实体(mulitpart entity)中的一个实体(entity)。

2.6 主体 (Body)
在没做进一步说明的时候,术语“主体”(body)指的是一个实体(entity)的主体部分。也就是指“消息”(message)或“部分主体”(body part)的主体部分。

 

注释:很明显,以上四个概念被循环定义。因为MIME消息的整个结构就是递归的,所以这种情况不可避免。

2.7 7位的数据 (7bit Data)
“7位的数据”(7bit Data)所描述的是相对较短的数据行:每行有998个或更少的8位字节内容,行分隔符为CRLF序列[RFC-821]。其中,每一个8位字节的值都不可以大于十进制的127,也不能为NUL(十进制的0),而且CR(十进制值为13)和LF(十进制值为10)字节只可以出现在CRLF序列中。

 

2.8 8位的数据 (8bit Data)
“8位的数据”(8bit Data)所描述的是相对较短的数据行:每行有998个或更少的8位字节内容,行分隔符为CRLF序列[RFC-821]。其但是字节的值可以大于十进制的127。与“7bit data”一样, CR(十进制值为13)和LF(十进制值为10)字节只可以出现在CRLF序列中,字节的值不能为NUL(十进制的0)。

 

2.9 二进制数据 (Binary Data)
“二进制数据”(Binary Data)是指可以包含任何字节序列的数据。

 

2.10 行 (Lines)
“行”(Lines)被定义为由CRLF分隔的字节序列。这与RFC 821及RFC 822一致。“行”(Lines)是指消息(Message)中的数据单位,它可以符合或不符合用户代理(user agent)所显示的真实情形。
3. MIME头字段(MIME Header Fields)
MIME定义了许多新的RFC822头字段,用以描述MIME实体内容(entity content)。这些头字段至少会在以下两个地方出现:

 

(1)      做为规则的RFC822消息(message)头信息的一部分。

 

(2)      在多部分结构(multipart construct)里,存在于“部分主体”(body part)头信息中。

 

这些头字段的形式定义如下:

 

     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头字段
自从1982年发布了RFC 822以来,实际上只存在这一种Internet消息格式标准,而且几乎没人意识到需要声明那些正在使用中的格式。这篇文档是一个补充RFC822的独立说明。虽然在这篇文档中所做的扩展已经被定义为与RFC 822兼容,但是,邮件处理代理仍然需要知道一个消息是否是按照新的标准构成。

 

为此,本文档定义了一个新的头字段:“MIME-Version”。它被用来声明Internet消息主体(message body)所使用格式的版本号。

 

按照本文档格式所构成的消息(message),必须按如下格式包含这个头字段:

 

MIME-Version: 1.0

 

这个字段就是一个声明,它表示消息的结构符合本文档所规定的格式。

 

因为今后的文档中有可能再次扩展消息格式的标准,所以这里给出MIME-Version头字段的BNF:

 

version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT

 

这样,将来的格式说明符都被约束为以小数点分隔的两个整数,它们可能会替代或扩展字符:“1.0”。如果接收到一个消息,它的MIME-version值不是“1.0”,那么就可以假定它不符合本文档的规范。

 

还有一件值得注意的事情是,不可以使用MIME-Version机制来实行对媒体类型的版本控制。特别的,一些格式(如application/postscript)拥有包含在媒体格式内部的约定版本号。当这种约定存在时,MIME不会将其取代。当这种约定不存在时,MIME会在必要的时候使用“content-type”字段中的一个“version”参数进行声明。

 

实现者要注意的问题:在检查MIME-Version的时候,一定要忽略任何在RFC822中所定义的注释部分。详细的说,以下的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邮件消息中只包含US-ASCII字符集的纯文本内容,因为这个消息很可能使用了一些非标准的比MIME更早出现的本地约定,或是包含其它字符集的内容或非文本的内容,这样,消息就无法被自动的识别。(如用UUENCODE方式编码的UNIX tar压缩文件)

5. Content-Type 头字段
 

设置“Content-Type”头字段的目的是为了完整的描述主体(body)中数据的内容。这样,接收代理就可以挑选出适当的代理或机制,来向用户呈现数据内容,或以适当的方式处理数据。这个字段值被称为“媒体类型”(media type)。

 

历史注释:“Content-Type”头字段最初是在RFC1049中定义的。RFC1049中使用的是相对简单的,不强大的语法,但是在很大程度上与本文档所定义的机制相兼容。

 

“Content-Type”头字段通过指定媒体类型及子类型的标识符来说明实体主体(body of an entity)中数据的原始类型,而且它还会为一些特别的媒体类型提供辅助信息。在媒体类型及子类型名称之后,本字段中的其余部分均为参数,它们以“属性 = 值”的形式给出,至于这些参数是按什么顺序给出的,则并不重要。

 

总的来说,顶层的媒体类型被用来声明数据的一般类型,而子类型则指明了数据的细节格式。因此,媒体类型“image/xyz”足以使用户代理知道,接收的数据是一个图像,哪怕这个用户代理并不知道这种特殊的图像类型:“xyz”。因此,这类信息可以被用来决定是否向用户显示一种拥有不能识别的子类型的原始数据――此操作对于拥有不可识别子类型的文本内容来说是合理的,但不适用于图像(image)和音频(audio)类型的数据。由于这个原因,文本、图像、音频和视频的子类型都不能包含有不同类型的嵌入信息。这种复合的格式应该由类型“multipart”和“application”所描述。

 

参数是媒体子类型的修饰成份,而不会影响内容的性质。一组有意义的参数依赖于媒体类型及子类型。大部分的参数只与某单一的子类型相关联。然而,一个顶级的媒体类型可以定义一些与其中的任何子类型都关联的参数。对于所涉及到的内容类型(content type)或子类型(subtype)来说,参数可能是必须的,也可能是可选的。MIME的实现过程中必须忽略所有不能识别的参数。

 

例如,“charset”参数可适用于“text”类型中的任何子类型,而“boundary”参数则是“multipart”类型中所有子类型所必须的。

 

不存在适用于所有媒体类型的全局参数。真正的全局机制是通过在MIME原型中定义“Content-*”头字段而提出的。

 

在RFC2046中定义了最初的七个顶级媒体类型。其中的五个是不连续的类型,它们的内容是MIME处理过程所不关心的。另外的两个类型是合成的,它们的内容需要MIME处理器进行额外的处理。

 

这组顶级的媒体类型(media type)已被完全定义。希望在对这组媒体类型进行扩充的时候,只是扩充初始类型中的子类型。将来,只可以在扩展本标准的情况下,才能定义更多的顶级媒体类型。无论任何原因,如果需要使用另一个顶级类型,那么这个类型的名称必须以“X-”开头,以表示它是一个非标准的状态,以避免今后与官方定义的名称冲突。

 

5.1 Content-Type头字段的语法
 

用一种扩充的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 := <An extension token defined by a

                    standards-track RFC and registered

                    with IANA.>

 

     x-token := <The two characters "X-" or "x-" followed, with

                 no intervening white space, by any token>

 

     subtype := extension-token / iana-token

 

     iana-token := <A publicly-defined extension token. Tokens

                    of this form must be registered with IANA

                    as specified in RFC 2048.>

 

     parameter := attribute "=" value

 

     attribute := token

                  ; 匹配属性( attributes)时,

                  ; 总是大小写无关的

 

     value := token / quoted-string

 

     token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,

                 or tspecials>

 

     tspecials :=  "(" / ")" / "<" / ">" / "@" /

                   "," / ";" / ":" / "/" / <">

                   "/" / "[" / "]" / "?" / "="

                   ; Must be in quoted-string,

                   ; to use within parameter values

 

 

注意,对“tspecials”的定义与RFC822中对“specials”的定义是几乎一样的,只是新增了三个字符:“/”、“?”、“=”,又去掉了一个字符:“.”。

 

还要注意到,对子类型(subtype)的定义是强制性的――子类型不可以被Content-Type字段所忽略,因此,也就不存在缺省的子类型(subtype)。

 

类型、子类型、参数名称都是大小写无关的。例如:“TEXT”、“Text”和“TeXt”表示相同的顶级媒体类型。参数值通常都是大小写相关的,但是一些时候也被定义为大小写无关的形式,这依赖于具体的应用。(例如,multipart boundary就是大小写相关的、而“access-type”则是大小写无关的)

 

注意一个用引号括起来的参数值中不包括引号,这就是说,一个被引号括起来的字符串中,引号是不包括在参数值中的,但这仅限于使用引号确定参数值界线的情况下。另外,格式与RFC822规则一致的注释也允许出现在这个字段中,因些,以下两种形式是完全等价的:

 

Content-type: text/plain; charset=us-ascii (Plain text)

 

Content-type: text/plain; charset="us-ascii"

 

除了这些句法之外,对构成子类型名称的唯一句法约束是它们在使用中不可以相互冲突。这就是说,不可以有两个不同的团体使用“Content-Type: application/foobar”来表示两种不同东西。定义一个媒体子类型的过程,并不受限制:只需要公布这些类型的定义,并使用它们即可。因此,两种广泛接受的定义媒体子类型的机制如下:

 

(1)           私有值(以“X-”开头的名称)可以在两个协同工作的代理之间双向的定义,而不需要外部的注册或标准化。这种值不可以被注册或制定为标准。

 

(2)           可以向IANA注册新的标准,如RFC2048中描述的情况。

 

这组文档中的第二篇:RFC2046定义了媒体类型的初始集合。

 

5.2 Content-Type的缺省值
 

没有“Content-Type”头字段的RFC822消息被默认为是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头字段
 

通过邮件传输的一些数据可能会被声明成它们的“原始”格式,如8位字符(8bit character)或二进制数据(binary data)。这些数据不通过一些传输协议进行传输。如:RFC821(SMTP)中限制邮件消息中只可以由一些包括行结束符CRLF序列在内,长度不超过1000字节的行组成,而且所有的字符都是7位的US-ASCII字符。

 

因此需要定义一种机制来将这些数据编码为7位数据(7bit data)的短行。并且,当在限制很少的系统中直接传输无限制的格式时,需要对其中未编码内容进行适当的标记。本文档通过一个新的“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”要求实体体中的内容都是7位字节。而且它也是缺省值,这就是说,如果没有“Content-Transfer-Encoding”头字段,则假定其为:“"Content-Transfer-Encoding: 7BIT”。

 

6.2 Content-Transfer-Encoding 语义
字符串“Content-Transfer-Encoding”实际上提供了两条信息。它指明了在传输主体(body)的时候,采用了哪种编码方式及必须用哪种解码方式将数据解码成它的原始状态。同时,它还指明了解码结果所处的范围。任何“Content-Transfer-Encoding”的转换部分――无论是确定的还是缺省的――都指定了一个单一的、详细定义的解码算法。这个算法可以将编码后的任意字节序列转换为编码前的原始序列,或说明某部分内容是非法的编码序列。“Content-Transfer-Encoding”转换永远不会依赖于附加的外部信息。注意,解码器必须为每一个合法的编码内容提供一个单一的、详细定义的输出。而对于编码器却不存在这样的限制。对同一个输入序列,编码器可以给出不同的,等价的编码序列――这是完全合法的。

 

目前定义了三种转换方式:恒等的、“quoted-printable”编码、“base64”编码。范围是“binary”、“8bit”、“7bit”。

 

“Content-Transfer-Encoding”的值为“7bit”、“8bit”、“binary”时,说明编码转换已经完成(也就是没有编码),同时,作为简单的标识符,它们给出了实体体数据的范围,并提供了在某个特定的传输系统中传输数据时可能会采用某种编码方式的相关信息。术语“7bit data”、“8bit data”、“binary data”的定义见第二节。

 

“quoted-printable”及“base64”会将任意的输入内容转换到“7bit”范围中,以使数据可以在受限制的系统中传输。转换的定义将在下文中给出。

 

必须始终使用正确的“Content-Transfer-Encoding”标志。不允许将未编码的8位字符(8bit characters)标志为“7bit”。而且,未编码的与行无关的内容只能被标识为“binary”。

 

与媒体子类型不同,“Content-Transfer-Encoding”值不需要有子类型值。然而,不可能只建立一个单一的到“7bit”的转化方式。因为要在以下两个方面进行权衡:对较长的二进制内容进行简洁、高效的编码,或是需要一个更易读的编码内容,而编码可以不完全是7bit的。由于这个原因,至少要提供两种编码机制:或多或少可读的编码(quoted-printable)和“紧凑”、“均匀”的编码(base64)。

 

在RFC1652中定义了传输未编码的8位数据的方式。到最初公布本文档时为止,还没有为在因特网上传输包含未编码二进制数据邮件而制定的标准。因此就不存在“二进制”(binary) Content-Transfer-Encoding类型值合法的出现在因特网邮件中的情况。然而,当传输“二进制”邮件成为可能时,或MIME被用来连接其它任何的可传输“二进制”邮件的邮件传输机构时,就必须用这种机制对“二进制”内容进行标识。

 

注意:为“Content-Transfer-Encoding”头字段所定义的五个值只是为媒体类型提供了编码或解码的算法。

 

6.3 新的Content-Transfer-Encoding
 

如果需要,实现者可以定义私有的“Content-Transfer-Encoding”值。但是必须使用x标记,就是指要在名字前面加上“X-”,以说明它是一个非标准的状态。如,“Content-Transfer-Encoding: x-my-new-encoding”。 其它的“Content-Transfer-Encoding”标准值,则必须通过标准途径RFC来定义。在RFC2048中给出了这些说明须符合的要求。同样的,除了以“X-”开头的“Content-Transfer-Encoding”名字之外,所有的名字都是为IETF将来的使用而保留的。

 

与媒体类型及子类型不同,不提倡创建新的“Content-Transfer-Encoding”值。因为它会阻碍互用性,并且几乎没有一点潜在的好处。

 

6.4 解释及使用
如果“Content-Transfer-Encoding”头字段是消息头信息的一部分,那么它对这个消息中的全部主体(body)都适用。如果“Content-Transfer-Encoding”头字段是实体(entity)头信息的一部分,那么它只适用于这个实体(entity)的主体(body)。如果实体类型是“multipart”,则“Content-Transfer-Encoding”只能是“7bit”、“8bit”、“binary”中的一个。一些更为严格的约束将应用于“message”媒体类型的子类型。

 

应该注意到,大部分的媒体类型都是按照字节而不是位而定义的,因此,这里描述的机制是解码任意字节流而非位流。如果需要通过这些机制对位流进行编码,则必须要先使用网络位顺序标准(大端字节序[big-endian])将位流转换成8位字节流――位流中靠前的位出现在字节的高位中。如果位流中剩下的部分不足8位,则必须补0。RFC2046中提供了用参数为“padding”的“application/octet-stream”媒体类型来说明上述这种填充机制。

 

这里定义的编码机制可以将任何数据编码为US-ASCII字符集的内容。因此,如果假设一个实体有如下头字段:

 

        Content-Type: text/plain; charset=ISO-8859-1

    Content-transfer-encoding: base64

 

则必须被解释为:实体内容是BASE64 US-ASCII编码的数据,而原始数据为ISO-8859-1字符集内容,而且解码后内容也处于同一字符集ISO-8859-1中。

 

特定的“Content-Transfer-Encoding”值可以被用于特定的媒体类型。特别的,明确禁止将除“7bit”、“8bit”、“binary”之外的编码方式应用于任何复合的媒体类型,如递归包含其它“Content-Type”头字段的媒体类型。当前仅有的复合媒体类型是“multipart”和“message”。想要对“multipart”或“message”类型的实体编码时,必须在最里面的一层中,对需要编码的真实实体进行编码。

 

同样要注意,如果一个实体的编码类型被定义为“7bit”,而其中还包含有一个编码类型为“8bit”的实体。这时,或者外部的“7bit”标签是错误的,因为它包含了8位的数据;或者内部的“8bit”标签对传输系统提出了不必要的要求,因为实际上它包含的数据类型只是7位的。

 

关于编码约束的注释:虽然禁止在复合结构中使用“Content-Transfer-Encoding”可能有些过度严格,但是必须要防止嵌套编码――这样会导致对数据进行多次编码,以及为正确显示出数据内容必须进行多次解码。嵌套编码会给用户代理的工作增加很大的复杂度:多次编码除了会带来效率问题,还会使消息的原始结构变得含糊。特别的,它们暗示了只有在进行所有的解码操作之后,才可以知道消息内容的类型是什么。禁止嵌套编码会使邮件网关的工作变得复杂,但是,与重复编码可能给用户代理所带来的影响相比,这个问题要小得多。

 

对于任何带有不可识别的“Content-Transfer-Encoding”值的实体,不论其“Content-Type”真实值是什么,都要将其看作为“application/octet-stream”类型。

 

“Content-Type”与“Content-Transfer-Encoding”的关系:看起来似乎可以通过被编码媒体的特征来推断出“Content-Transfer-Encoding”的值,或者至少可以通过对一些特定媒体类型的使用来确定“Content-Transfer-Encoding”。但实际上,这些假设是不正确的,这里给出几个原因:首先,对于邮件,存在不同的传输方式,一些编码可能只适用于某些而不是全部的媒体类型或传输方式。(如,在8位传输系统中,不需要对特定字符集中的文本进行编码,而在7位传输系统中,却一定需要编码。)

 

其次,同一媒体类型在不同的环境中,可能会需要不同的传输编码方式。例如,许多邮件的附言(PostScript)部分完全是由7位数据的短行组成,因此不需要编码。而其它的(特别是那些使用Level 2 PostScript二进制编码机制的)附言可能需要使用二进制传输编码进行描述。

 

最后,因为“Content-Type”已经被制定为可扩充式的规范机制,所以,如果严格定义媒体类型与编码的关系,就会将应用协议的定义与更低层的传输细节相结合。而这是不合乎 要求的,因为媒体类型的设计者不一定需要知道所有会被使用的传输方式及其局限性。

 

6.5编码转换
可以在“quoted-printable”和“base64”编码方式之间进行转换操作。只有当需要在“quoted-printable”编码中强制输出换行符的时候才需要这种操作。从“quoted-printable”转换到“base64”格式的时候,“quoted-printable”编码中的换行符被表示为CRLF序列。因此,它必须被转换为用“base64”方式编码后的相应内容。同样,解码后数据中的CRLF序列也必须被转换成“quoted-printable”的强制换行符,但这只适用于文本情况。
6.6 规范的编码模式(Canonical Encoding Model)
 

何时将邮件数据转换为标准形式并编码、这个过程如何处理CRLF(新行符,并且在不同的系统中具有不同的形式)、传输编码与字符集之间有什么关系――在以前版本的RFC中,关于这些方面的问题都很混乱。由于这个原因,RFC2049给出了编码的规范模型。

 

6.7 Quoted-Printable编码
Quoted-Printable编码适用于内容多为US-ASCII字符集中可打印字符的情况。经过它编码的数据不再需要邮件传输系统进行转换。如果被编码的数据多为US-ASCII字符,则编码后的内容会保留那些可人为识别的部分。完全由US-ASCII字符构成的内容也可以进行Quoted-Printable编码,以确保可以通过字符转换及(或)行封装的网关来传递所有的消息 数据。

 

在这种编码方式中,字节按如下规则描述:

 

(1)       (普通的8位字节描述)除了被编码内容中标准换行符CRLF序列里的CR和LF字节之外的任何字节,都应该被表示成“=”后面紧跟着两个表示字节值的十六进制数字的形式。此处使用的十六进制字符表是“0123456789ABCDEF”。必须使用大写字母,而不允许使用小写字母。因此,十进制的值12可以被表示为:“=0C”,十进制值61(表示US-ASCII字符集中的等号)可以被表示为“=3D”。除了选择后面规则中所规定的编码方式之外,必须遵循本规则。

 

(2)       (文字表示法)      十进制值从33到60、从62到126的字节,可以直接表示为US-ASCII字符集中的相应字符(即从感叹号‘!’到小于号‘<’、从大于号‘>’到符号‘~’)。

 

(3)       (空格)      十进制值为9和 32的字节可以被分别表示为US-ASCII字符集中的TAB(HT)和空格(SPACE)。但是这种表示方法不可以应用在编码行的末尾。在编码后的内容中,任何TAB(HT)及空格(SPACE)字符后面都必须跟随有可打印的字符。特别的,行末的“=”表示“软换行”(见规则5),它可以跟随在一个或多个TAB(HT)或空格(SPACE)字符后面。它遵循了这样一条规则:当行末的最后一个字节的值在9到32之间时,必须按照规则(1)进行编码。这是必要的,因为一些传送消息的MTA(Message Transport Agent--消息传送代理:将消息从一个用户传送至另一个用户处或进行其中一部分工作的程序)会用空白字符来填充行,而其它的则会从行末移除空白字符。因此,当进行“Quoted-Printable”解码时,要删除行末的任何空白字符, 因为它们很可能是被中间的传送代理加上的。

 

(4)       (换行符)      Quoted-Printable编码将文本内容中的换行符(CRLF序列)表示成RFC 822的换行符(也是CRLF序列)。因为,除了文本类型(text)之外的其它规范媒体类型通常都不会包含有换行符CRLF序列。这些媒体类型的Quoted-Printable编码中不会出现硬换行符(就是有意义的、要显示给用户的换行符)。所以,在Quoted-Printable编码的非文本类型的数据中就可能会出现“=0D”、“=0A”、“=0A0D”、“=0D0A”等序列。

 

注意,许多实现机制都是直接将不同的媒体类型编码为本地形式,而不是先将它们转换成规范的格式然后编码,最后再转换成本地形式。特别的,在不使用CRLF序列做为行终止符的系统中,当对纯文本内容进行操作时,会出现这种情况。而只有在某种组合的规范编码等价于分别执那三步操作的时候,才允许执行这种优化的操作。

 

(5)       (软换行符) Quoted-Printable编码规则要求每个编码行的长度不超过76字节。如果需要编码更长的行,就必须要使用“软”换行符。在编码内容中,出现在一行最后位置的等号(“=”)表示无意义的换行符(软换行符)。

 

因此,如果编码前的格式是一个单独的未编码行:

 

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编码的内容被包含在一个或多个multipart实体中时,一定要注意不能让边界分隔符(boundary delimiter)出现在编码内容的任何位置上。(选择边界分隔符时,最好使其包含一个“=_”序列,因为这个序列永远不会出现在Quoted-Printable编码内容中。参考RFC2046中关于multipart的定义)

 

注意:Quoted-Printable编码为传输中数据的可读性及可靠性提供了一种折中的方法。通过Quoted-Printable编码的主体(body)能可靠的在多数的邮件网关上传输,但是在少数网关上--特别是在涉及EBCDIC转换的网关上--它也许不能很好的工作。base64编码方式提供了更高的可信度。另外一个能经过EBCDIC网关进行可靠传输的方法,就是将如下US-ASCII字符按照规则(1)进行编码:

 

!"#$@[/]^`{|}~

 

quoted-printable数据内容都被假定为面向行的,因此可以预料,在传输过程中可能会转换各行之间的换行符。也就是说,在不同换行习惯的系统间传输的纯文本邮件通常被转换成因特网邮件。如果这种转换会构成错误的数据,那么就需要采用base64而不是quoted-printable来进行编码。

 

注释:quoted-printable编码规则决定了不能生成几种类型的子串,因此,如果quoted-printable编码器输出这些字符串,则说明它们是非法的。本注释列举了这些情况以及在解码过程中处理这些非法子串的方法。

 

(1)   等号“=”后而跟着两个十六进制的数字,但两个数字或其中的一个是小写字母“abcdef”的非法格式。一个健壮的执行程序可以选择将它们当做相应的大写字母来识别。

 

(2)   如果等号“=”后面的字符即不是十六进制数字(包括“abcdef”),也不是CRLF对中的CR字符,那么就是非法的。产生这种情况可能是因为将未编码的US-ASCII文本包含进了消息中的quoted-printable编码部分。对于健壮的执行程序来说,一个合理的解决方式是将等号及其后面的字符包含进解码内容中,而不进行任何转换。而且如若可能,要向用户指出:在这个位置处的解码也许会出现错误。

 

(3)   等号“=”不可以是编码内容中的最后一个或倒数第二个字符。相应的处理方式可以参考上面的情况(2)。

 

(4)   除TAB字符、CRLF对中的CRLF字符之外,不可以出现其它的控制字符。同样也不可以存在十进制值大于126的字节。如果解码时在输入数据中出现这些字符,则健壮的执行程序要将这些非法字符从解码数据中删除,并要警告用户发现非法字符。

 

(5)   编码后的行长度不可以超过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 := <any octet with decimal value of 33 through

                  60 inclusive, and 62 through 126>

                  ; 也不推荐使用

                  ; 没有在RFC2049中列为“mail-safe”的字符

 

hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")

                  ; 这些字节被用来表示值大于127的字节,

                  ; 以及出现在行尾的空格或TAB。而且,

                  ; 对于没有在RFC2049中列为“mail-safe”

                  ; 的字符,也推荐使用这种表示方式。

 

transport-padding := *LWSP-char

                  ; 设计者不可以产生非零长度的填充,

                  ; 但是接收者必须能够处理由传输机构

                  ; 增加的填充内容。

              

注意:本BNF中所提到的附加LWSP是不被承认的,因为这个BNF并没有详细说明一个结构头字段。
6.8 Base64 Content-Transfer-Encoding
 

设计Base64内容传输编码是为了描述任意的不需要人为识别的字节序列。编码及解码算法很简单,不过,编码后的数据总是比编码前的数据长33%。Base64与RFC1421中定义的Privacy Enhanced Mail (PEM)是同一个编码方法。

 

由US-ASCII中65个字符组成一个子集,使用6位来表示每一个可打印的字符(第65个字符“=”表示要进行特殊的操作)

 

注意:这个子集有个很重要的性质,那就是,在任何版本的ISO 646(包括US-ASCII)中,它都被描述成相同的内容。而且,在任何版本的EBCDIC中,子集中的所有字符也都具有相同的描述。其它常用的的编码,如UUENCODE、Macintosh binhex 4.0 [RFC-1741]、base85就没有这些性质,因此就无法满足邮件二进制传输编码的可移植性要求。

 

编码时,每次输入24位数据,输出为4个编码字符。将输入的3个8位字节从左到右连续排列,就可以形成24位数据。将这24位看做是4个连续的6位组,每组都可以单独译成一个base64表中的字符。当通过base64编码方式编码一个位流时,必须假定位流为“重要位优先”的顺序。就是说,位流中的第1位应该是第一个字节中的最高位;位流中的第8位应该是第一个字节中的最低位,依此累推。

 

用每组(6位)的值来索引64个可打印字符。索引后将得到的字符依次放入输出字符串中。选择表1中的这些字符,是为了能够完备的描述,并且排除在SMTP中有特殊意义的字符(如‘.’、CF、LF)以及在RFC2046中定义的multipart的边界分隔符中有特殊意义的字符(如‘-’)。

 

表1:base64字母表

 
     Value Encoding  Value Encoding  Value Encoding  Value Encoding
         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
        14 O            31 f            48 w         (pad) =
        15 P            32 g            49 x
        16 Q            33 h            50 y
 

编码输出的流必须被描述成一些不大于76字节的行。解码时,必须要忽略换行符及其它所有不存在于表1中的字符。在base64数据中,除表1中字符、换行符、空格之外的字符都可能表示存在传输错误,在某些情况下,可以适当的给出一些警告信息甚至是拒绝信息。

 

如果需要被编码数据的剩余部分不足24位,则要执行特殊的操作。编码量通常在主体(body)结尾部分结束。当输入少于24位时,会在末尾(右侧)添加一些值为0的位,以形成完整的6位组。用“=”来表示数据结尾的填充。因为所有base64的输入都是完整的字节,所以只可能出现如下情况:(1)最后的编码输入是完整的24位;这时,编码输出的最后一个单元会是完整的4个不为“=”的个字符。(2)最后的输入是8位;这时,编码输出的最后一个单元是两个编码字符后接两个填充字符“=”。(3)最后的输入刚好是16位;这时,编码输出的最后一个单元是三个编码字符后接一个填充字符“=”。

 

因为“=”是用来填充数据的结尾部分,所以,它的出现意味着可能已经到达数据末尾(但不切断传输)。然而,也可能无法以这种方式进行判断:当传输的字节个数是三的整数倍时,编码中就不会出现“=”。

 

在base64编码数据中,要忽略任何不属于base64字母表的字符。

 

一定要注意,当base64编码直接应用于未经过规范化的文本内容时,要使用恰当的字节做为换行符。特别是在进行base64编码前,必须要将文本换行符转换为CRLF序列。要注意,一件很重要的事情就是:这些操作可以直接由编码器来完成,而不是在一些实现中先进行一个标准化的步骤。

 

注释:不用担心multipart实体中的base64编码部分引用到潜在的边界分隔符(boundary delimiter),因为base64编码中没有使用连字符“-”。

 

7. Content-ID 头字段
 

在构建一个高级别的用户代理时,可能会需要在一个主体(body)中涉及到另一个主体。因此需要用“Content-ID”头字段给主体(body)设置标签。这个字段在语法构成上与“Message-ID”相同:

 

id := "Content-ID" ":" msg-id

 

        与Message-ID的值一样,Content-ID的值也必须是世界上唯一的。

 

        Content-ID的值可以被用来在多处上下文中唯一的确定MIME实体,尤其用于被message/external-body机制所引用的缓存数据。虽然Content-ID头字段通常是可选的,但是对于生成可选的媒体类型“message/external-body”的实现程序来说,它则是必须存在的。这就是说,每一个message/external-body实体(entity)必须有一个Content-ID字段来允许对这些数据的缓存。值得注意的是,Content-ID值在multipart/alternative媒体类型中有特殊的意义。这一点会在RFC2046中关于multipart/alternative的那一节中进行解释。

8. Content-Description 头字段
 

经常需要将一些描述信息与给定的实体结合起来。例如,将某个“image”类型的实体标记为“a picture of the Space Shuttle Endeavor.”会有一定的用处。这些文字可以被放入ContentDescription头字段中。这个头字段通常是可选的。

 

        description := "Content-Description" ":" *text

 

描述被假定为以US-ASCII字符集的形式给出,不过在RFC2047中定义了一种使用非US-ASCII字符集的Content-Description值的机制。

 

9. 另外的MIME头字段
 

将来的文档可能会为不同目的而另外定义一些MIME头字段。任何进一步描述消息内容的头字段都就应该以字符串“Content-”开始,以便在消息头域中从普通的RFC822头字段中区分出这类头字段。

 

        MIME-extension-field := <Any RFC 822 header field which
                              begins with the string
                             "Content-">

 

 10. 摘要
 

使用MIME-Version,Content-Type,以及Content-Transfer-Encoding头字段,就可以按照标准方法,在与RFC822标准相一致的邮件中包含任意的媒体类型。即没有违背RFC821与RFC822中所规定的任何约束,也小心的避免了由因特网邮件传输机制的约束所引起的问题。(见RFC 2049)

 

这个文档集中的下一篇文档是RFC2046, 它详细说明了可以使用这些头域进行标记及传输的媒体类型初始集合。

 

11. 安全考虑
 

安全问题在RFC2046中进行讨论。

 

12. 作者地址
 

若需要更多信息,请通过因特网邮件联系本文档作者。

 
   Ned Freed
   Innosoft International, Inc.
   1050 East Garvey Avenue South
   West Covina, CA 91790
   USA
 
   Phone: +1 818 919 3600
   Fax:   +1 818 919 3614
   EMail: ned@innosoft.com
 
   Nathaniel S. Borenstein
   First Virtual Holdings
   25 Washington Avenue
   Morristown, NJ 07960
   USA
 
   Phone: +1 201 540 8967
   Fax:   +1 201 993 3032
   EMail: nsb@nsb.fv.com
 
   MIME is a result of the work of the Internet Engineering Task Force
   Working Group on RFC 822 Extensions.  The chairman of that group,
   Greg Vaudreuil, may be reached at:
 
   Gregory M. Vaudreuil
   Octel Network Services
   17080 Dallas Parkway
   Dallas, TX 75248-1905
   USA
 
   EMail: Greg.Vaudreuil@Octel.Com
附录A :收集的语法
 

        这个附录中包含了本文档中定义的全部BNF语法。

 

        对于自身来说,这些语法是完整的。其中提及了几个在RFC 822中定义的语法名称,而没有重复进行定义,这样可以降低由于无意识操作而在两种定义中产生差别的风险。一旦发现了未定义的术语,请参考RFC 822中的相关定义。

 

 
  attribute := token
               ; Matching of attributes
               ; is ALWAYS case-insensitive.
 
  composite-type := "message" / "multipart" / extension-token
 
  content := "Content-Type" ":" type "/" subtype
             *(";" parameter)
             ; Matching of media type and subtype
             ; is ALWAYS case-insensitive.
 
  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")
               ; Octet must be used for characters > 127, =,
               ; SPACEs or TABs at the ends of lines, and is
               ; recommended for any character not listed in
               ; RFC 2049 as "mail-safe".
 
  iana-token := <A publicly-defined extension token. Tokens
                 of this form must be registered with IANA
                 as specified in RFC 2048.>
 
  ietf-token := <An extension token defined by a
                 standards-track RFC and registered
                 with IANA.>
 
  id := "Content-ID" ":" msg-id
 
  mechanism := "7bit" / "8bit" / "binary" /
               "quoted-printable" / "base64" /
               ietf-token / x-token
 
  MIME-extension-field := <Any RFC 822 header field which
                           begins with the string
                           "Content-">
 
  MIME-message-headers := entity-headers
                          fields
                          version CRLF
                          ; The ordering of the header
                          ; fields implied by this BNF
                          ; definition should be ignored.
 
  MIME-part-headers := entity-headers
                       [fields]
                       ; Any field not beginning with
                       ; "content-" can have no defined
                       ; meaning and may be ignored.
                       ; The ordering of the header
                       ; fields implied by this BNF
                       ; definition should be ignored.
 
  parameter := attribute "=" value
 
  ptext := hex-octet / safe-char
 
  qp-line := *(qp-segment transport-padding CRLF)
             qp-part transport-padding
 
  qp-part := qp-section
             ; Maximum length of 76 characters
 
  qp-section := [*(ptext / SPACE / TAB) ptext]
 
  qp-segment := qp-section *(SPACE / TAB) "="
                ; Maximum length of 76 characters
 
  quoted-printable := qp-line *(CRLF qp-line)
 
  safe-char := <any octet with decimal value of 33 through
               60 inclusive, and 62 through 126>
               ; Characters not listed as "mail-safe" in
               ; RFC 2049 are also not recommended.
 
  subtype := extension-token / iana-token
 
  token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
              or tspecials>
 
  transport-padding := *LWSP-char
                       ; Composers MUST NOT generate
                       ; non-zero length transport
                       ; padding, but receivers MUST
                       ; be able to handle padding
                       ; added by message transports.
 
  tspecials :=  "(" / ")" / "<" / ">" / "@" /
                "," / ";" / ":" / "/" / <">
                "/" / "[" / "]" / "?" / "="
                ; Must be in quoted-string,
                ; to use within parameter values
 
  type := discrete-type / composite-type
 
  value := token / quoted-string
 
  version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
 
  x-token := <The two characters "X-" or "x-" followed, with
              no  intervening white space, by any token>

阅读更多
个人分类: 网络
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭