RFC822 文档定义了邮件内容的主体结构和各种邮件头字段的详细细节,但是,它没有定义邮件体的格式,RFC822文档定义的邮件体部分通常都只能用于表述一段普通的文本,而无法表达出图片、声音等二进制数据。另外,SMTP服务器在接收邮件内容时,当接收到只有一个“.”字符的单独行时,就会认为邮件内容已经结束,如果一封邮件正文中正好有内容仅为一个“.”字符的单独行,SMTP服务器就会丢弃掉该行后面的内容,从而导致信息丢失。
由于 Internet的迅猛发展,人们已不满足于电子邮件仅仅是用来交换文本信息,而希望使用电子邮件来交换更为丰富多彩的多媒体信息,例如,在邮件中嵌入图片、声音、动画和附件。但是,由于图片和声音等内容是非ASCII码的二进制数据,而RFC822邮件格式只适合用来表达纯文本的邮件内容,所以,要使用 RFC822邮件格式发送这些非ASCII码的二进制数据时,必须先采用某种编码方式将它们“编码”成可打印的ASCII字符后再作为RFC822邮件格式的内容。邮件阅读程序在读取到这种经过编码处理的邮件后,再按照相应的解码方式解码出原始的二进制数据,这样就可以借助RFC822邮件格式来传递多媒体数据了。这种做法需要解决以下两个技术问题:
(1) 邮件阅读程序如何知道邮件中嵌入的原始二进制数据所采用的编码方式;
(2) 邮件阅读程序如何知道每个嵌入的图像或其他资源在整个邮件内容中的起止位置。
针对这个问题,人们后来专门为此定义了MIME(Multipurpose Internet Mail Extension,多用途Internet邮件扩展)协议。
邮件实例:
1. Return-Path: <[email protected]>
2. Delivered-To: [email protected]
3. Received: from smtp.sina.com.cn (unknown [202.108.3.177])
4. by sohumx139.sohu.com (Postfix) with SMTP id E4F9802C1249
5. for <[email protected]>; Thu, 10 Nov 2005 16:39:50 +0800 (CST)
6. Received: (qmail 49221 invoked from network); 10 Nov 2005 08:39: 33 -0000
7. Received: from unknown (HELO it315?test) (218.246.5.151)
8. by smtp.sina.com.cn with SMTP; 10 Nov 2005 08:39:33 -0000
9. From: [email protected]
10.To: [email protected]
11.Subject: test
12.Message-Id: <[email protected]>
13.Date: Thu, 10 Nov 2005 16:39:50 +0800 (CST)
14.Status: RO
15.X-UIDL: 1131611863.21509_77.mx72
16.
17.test!!!
邮件解析:
(1)邮件头和邮件体之间以一个空行进行分隔。第1~15行是邮件的邮件头,第17行是邮件的邮件体。
(2)每一个邮件头以“字段名:字段值”的格式出现,即每一行邮件头的内容依次由字段名、冒号、空格、字段值、回车换行符组成。RFC822文档中定义了多个标准的邮件头字段,每一个邮件头字段表示一种特定的信息。邮件头中也可以包含自定义的头字段,这种自定义的头字段通常是某个组织或机构内部专用的。
(3)一些主要的邮件头字段:
a. Return-Path 该字段代表邮件的回复地址
b. Received 该字段的基本格式为Received from A by B for C,其中A为发送方,B为接收方,C为收件人的邮箱地址。该字段的内容由接收邮件的SMTP服务器填写,常常被用来追踪邮件传输的路线和分析邮件的来源
c. From 该字段用于指定的发件人地址
d. To 该字段用于指定收件人地址
e. subject 该字段用于指定邮件的主题
f. date 该字段用于指定邮件的发送时间
g. cc 该字段用于指定邮件的抄送地址
f:bcc 该字段用于指定邮件的暗送地址
MIME协议用于定义复杂邮件体的格式,它可以表达多段平行的文本内容和非文本的邮件内容,例如,在邮件体中内嵌的图像数据和邮件附件等。另外,MIME 协议的数据格式也可以避免邮件内容在传输过程中发生信息丢失。MIME协议不是对RFC822邮件格式的升级和替代,而是基于RFC822邮件格式的扩展 应用。一言以蔽之,RFC822定义了邮件内容的格式和邮件头字段的详细细节,MIME协议则是定义了如何在邮件体部分表达出的丰富多样的数据内容。
一个采用了 MIME协议的电子邮件就叫做MIME邮件,MIME邮件在RFC822文档中定义的邮件头字段的基础上,扩充了一些自己专用的邮件头字段,例如,使用 MIME-Version头字段指定MIME协议的版本,使用Content-Type头字段指定邮件体的MIME类型,使用Content- Transfer-Encoding头字段指定编码方法,如下所示:
MIME-Version: 1.0
Content-Type:multipart/mixed;boundary="----=_NextPart_000_0050_01C"
其中,“multipart/mixed”部分说明邮件体中包含有多段数据,每段数据之间使用boundary属性中指定的字符文本作为分隔标识符。
另外,MIME邮件也扩展RFC822文档中已经定义了的邮件头字段的内涵,例如,定义了subject头字段中的值内容的格式,以便通过编码的方式让邮件主题中也可以使用非ASCII码的字符。subject头字段中的值嵌套在一对“=?”和“?=”标记符之间,标记符之间的内容由三部分组成:邮件主题 的原始内容的字符集、当前采用的编码方式、编码后的结果,这三部分之间使用“?”进行分隔。下面是一个对包含有非ASCII码字符的邮件主题进行了编码后 的结果:
Subject: =?gb2312?B?TUlNRdCt0unLtcP308q8/g==?=
其中,“gb2312”部分说明邮件主题的原始内容为gb2312编码的字符文本,“B”部分说明对邮件主题的原始内容按照BASE64方式进行了编码,“TUlNRdCt0unLtcP308q8/g==”为对邮件主题的原始内容进行了BASE64编码后的结果。
可见,MIME邮件与普通的RFC822邮件的关系犹如Java编程语言中的子类与父类的关系,子类是对父类的扩展,子类功能更强大,但子类离不开父类的支持。如果需要了解MIME的详细细节,可以查阅RFC 2045~2049系列文档。
1、MIME组织结构
一封MIME 邮件可以由多个不同类型的MIME消息组合而成,一个MIME消息表示邮件中的一个基本MIME资源或若干基本MIME消息的组合体。每个MIME消息的 数据格式与RFC822数据格式相似,也包括头和体两部分,分别称为MIME消息头和MIME消息体,它们之间使用空行分隔。MIME消息体中包含了资源 的具体内容,MIME消息头中则包含了对资源的描述信息。多个相同层次的MIME消息必须形成一个MIME组合消息,它们共同作为所形成的MIME组合消 息的MIME消息体,相互之间采用某种分隔标识符进行分隔,MIME组合消息的消息头中需要描述其中的多个MIME消息的组合类型和分隔标识符。一个 MIME组合消息还可以再与其他MIME消息共同形成一个更大的MIME组合消息,这样就形成了一种多层嵌套的组合关系,一封MIME邮件就是按这种组合 方式所形成的一个最顶层的MIME组合消息。
2、MIME消息的头字段
(1)Content-Type
对于表示某个具体资源的MIME消息,它的消息头中需要指定资源的数据类型;对于MIME组合消息,它的消息头中需要指定组合关系。具体资源的数据类型和 组合消息的组合关系,都是通过消息头中的Content-Type头字段来指定的。Content-Type字段中的内容以“主类型/子类型”的形式出 现,主类型有 text、image、audio、video、application、multipart、message等,分别表示文本、图片、音频、视频、应用 程序、组合结构、消息等。每个主类型下面都有多个子类型,例如text主类型包含plain、html、xml、css等子类型。multipart主类 型用于表示MIME组合消息,它是MIME协议中最重要的一种类型。一封MIME邮件中的MIME消息可以有三种组合关系:混合、关联、选择,它们对应 MIME类型如下:
— multipart/mixed
表示消息体中的内容是混和组合类型,内容可以是文本、声音和附件等不同邮件内容的混和体,例如图3.5中的整封邮件的MIME类型就必须定义为multipart/mixed。
— multipart/related
表 示消息体中的内容是关联(依赖)组合类型,例如图3.5中的邮件正文要使用HTML代码引用内嵌的图片资源,它们组合成的MIME消息的MIME类型就应 该定义为multipart/related,表示其中某些资源(HTML代码)要引用(依赖)另外的资源(图像数据),引用资源与被引用的资源必须组合 成multipart/related类型的MIME组合消息。
— multipart/alternative
表 示消息体中的内容是选择组合类型,例如一封邮件的邮件正文同时采用HTML格式和普通文本格式进行表达时,就可以将它们嵌套在一个 multipart/alternative类型的MIME组合消息中。这种做法的好处在于如果邮件阅读程序不支持HTML格式时,可以采用其中的文本格 式进行替代。
一封最复杂的电子邮件的基本情况为:含有邮件正文和邮件附件,邮件正文可以同时使用HTML格式和普通文本格式表示,并且HTML格式的正文中又引用了其他的内嵌资源。对于这种最复杂的电子邮件,可以采用如图3.6所示的MIME消息结构进行描述。
图3.6
从图3.6中 可以看出,如果要在邮件中要添加附件就必须将整封邮件的MIME类型定义为multipart/mixed;如果要在HTML格式的正文中引用内嵌资 源,那就要定义multipart/related类型的MIME消息;如果普通文本内容与HTML文本内容共存,那就要定义multipart /alternative类型的MIME消息。
注 意:如果整封邮件中只有普通文本内容与HTML文本内容,那么整封邮件的MIME类型则应定义为multipart/ alternative;如果整封邮件中包含有HTML文本内容和内嵌资源,但不包含附件,那么整封邮件的MIME类型则应定义为 multipart/related。
在Content-type头字段中除了可以定义消息体的MIME类型外,还可以在MIME类型后面包含相应的属性,属性以“属性名=属性值”的形式出现,属性与MIME类型之间采用分号(;)分隔,如下所示:
Content-Type:multipart/mixed;boundary="----=_NextPart_000_0050_01C"
常用的属性如表3.1所示。
表3.1
主 类 型 |
属 性 名 |
说 明 |
text |
charset |
用于说明文本内容的字符集编码 |
image |
name |
用于说明图片文件的文件名 |
application |
name |
用于说明应用程序的文件名 |
multipart |
boundary |
用于定义MIME消息之间的分隔符 |
(2)其他字段头
除了 Content-Type头字段之外,MIME协议中还定义Content- Transfer-Encoding、Content-Disposition、Content-ID、Content-Location、 Content-Base等几个重要的头字段,这几个头字段需要与Content-type头字段配合使用,它们的作用如下:
— Content-Transfer-Encoding头字段
Content-Transfer-Encoding头字段用于指定MIME消息体中的内容所采用的邮件编码方式,详细细节请参看3.4节的讲解。
— Content-Disposition头字段
Content- Disposition头字段用于指定邮件阅读程序处理数据内容的方式,有inline和attachment两种标准方式,inline表示直接处理, 而attachment表示当做附件处理。如果将Content-Disposition设置为attachment,在其后还可以指定filename 属性,如下所示:
Content-Disposition: attachment; filename="1.bmp"
上面的MIME头字段表示MIME消息体的内容为邮件附件,附件名"1.bmp"。
— Content-ID头字段
Content- ID头字段用于为“multipart/related”组合消息中的内嵌资源指定一个唯一标识号,在HTML格式的正文中可以使用这个唯一标识号来引用 该内嵌资源。例如,假设将一个表示内嵌图片的MIME消息的Content-ID头字段设置为如下形式:
Content-ID: it315logo_gif
那么,在HTML正文中就需要使用如下HTML语句来引用该图片资源:
<img src="cid:it315logo_gif">
注意,在引用Content-ID头字段标识的内嵌资源时,要在资源的唯一标识号前面加上“cid:”,以说明要采用唯一标识号对资源进行引用。
— Content-Location头字段
Content- Location头字段用于为内嵌资源设置一个URI地址,这个URI地址可以是绝对或相对的。当使用Content- Location头字段为一个内嵌资源指定一个URI地址后,在HTML格式的正文中也可以使用这个URI来引用该内嵌资源。例如,假设将一个表示内嵌图 片的MIME消息的Content- Location头字段设置为如下形式:
Content-Location:http://www.it315.org/images/it315logo.gif
那么,在HTML正文中就可以使用如下HTML语句来引用该图片资源:
<img src="http://www.it315.org/images/it315logo.gif">
— Content-Base头字段
Content- Base头字段用于为内嵌资源设置一个基准路径,只有这样,Content-Location头字段中设置的URI才可以采用相对地址。例如,假设将一个 表示内嵌图片的MIME消息的Content-Base和Content-Location头字段设置为如下形式:
Content-Base: http://www.it315.org/images/
Content-Location: it315logo.gif
那么,内嵌资源的完整路径就是Content-Base头字段设置的基准路径与Content-Location头字段设置的相对路径相加的结果,在HTML正文中就可以使用如下HTML语句来引用该图片资源:
<img src="http://www.it315.org/images/it315logo.gif">
由于每个ASCII码字符只占用一个字节(8个bit位),且最高bit位总为0,即ASCII码字符中的有真正意义的信息只是后面的7个低bit位,而传统的 SMTP协议又是基于ASCII码字符设计的,因此,一些基于传统SMTP协议设计的SMTP服务器在处理邮件内容时只取出每个字节中的7个低bit位进 行处理,而将最高bit位忽略不计。显然,这样的SMTP服务器在处理包含有非ASCII码字符的邮件内容时,会出现严重的问题,这就限制了邮件中只能出 现英文的ASCII码字符,而不能出现中文字符或二进制数据。
为了能够在邮