邮件MIME格式分析
邮件mime格式
参考:
rfc4021,Registration of Mail and MIME Header Fields,
http://www.apps.ietf.org/rfc/rfc4021.html,
总体来说,MIME消息由消息头和消息体两大部分组成。这里,分别称为为邮件头、邮件体。
邮件头
邮件头包含了发件人、收件人、主题、时 间、MIME版本、邮件内容的类型等重要信息。每条信息称为一个域,由域名后加“: ”和信息内容构成,可以是一行,较长的也可以占用多行。域的首行必须“顶头”写,即左边不能有空白字符(空格和制表符);续行则必须以空白字符打头,且第 一个空白字符不是信息本身固有的,解码时要过滤掉。
邮件头中不允许出现空行。有一些邮件不能被邮件客户端软件识别,显示的是原始码,就是因为首行是空行。
例如:
Date: Mon, 29 Jun 2009 18:39:03 +0800
From: "=?gb2312?B?26zQocHB?=" <gaoxl@legendsec.com>
To: "moreorless" <moreorless@live.cn>
Cc: "gxl0620" <gxl0620@163.com>
BCC: "=?gb2312?B?26zQocHB?=" <venus.oso@gmail.com>
Subject: attach
Message-ID: <200906291839032504254@legendsec.com>
X-mailer: Foxmail 6, 15, 201, 21 [cn]
Mime-Version: 1.0
邮件体
在邮件体中,大致有如下一些域:
有的域除了值之外,还带有参数。值与参数、参数与参数之间以“;”分隔。参数名与参数值之间以“=”分隔。
邮件体包含邮件的内容,它的类型由邮件头的“Content-Type”域指出。常见的简单类型有text/plain(纯文本)和text/html(超文本)。
multipart类型,是MIME邮件的精髓。邮件体被分为多个段,每个段又包含段头和段体两部分,这两部分之间也以空行分隔。常见的multipart类型有三种:multipart/mixed, multipart/related和multipart/alternative。从它们的名称,不难推知这些类型各自的含义和用处。它们之间的层次关系可归纳为下图所示:
可以看出,如果在邮件中要添加附件,必须定义multipart/mixed段;如果存在内嵌资源,至少要定义multipart/related段;如果纯文本与超文本共存,至少要定义multipart/alternative段。
示例:
MIME编码
参考rfc2047,MIME Part Three:Message Header Extensions for Non-ASCII Text
http://tools.ietf.org/html/rfc2047
MIME编码的两种方法:
对邮件进行编码最初的原因是因为Internet上的很多网关不能正确传输8bit内码的字符,比如汉字等。编码的原理就是把8bit的内容转换成7bit的形式以能正确传输,在接收方收到之后,再将其还原成8bit的内容。
MIME是“多用途网际邮件扩充协议”的缩写,在MIME协议之前,邮件的编码曾经有过UUENCODE等编码方式,但是由于MIME协议算法简单,并且易于扩展,现在已经成为邮件编码方式的主流,不仅是用来传输8 bit的字符,也可以用来传送二进制的文件,如邮件附件中的图像、音频等信息,而且扩展了很多基于MIME的应用。
从编码方式来说,MIME 定义了两种编码方法Base64与QP(Quote-Printable):
Base64
Base64是一种通用的方法,其原理很简单,就是把三个Byte的数据用4个Byte表示,这样,这四个Byte中,实际用到的都只有前面6 bit,这样就不存在只能传输7bit的字符的问题了。Base64的缩写一般是“B”。
Base64将输入的字符串或一段数据编码成只含有{'A'-'Z', 'a'-'z', '0'-'9', '+', '/'}这64个字符的串,'='用于填充。其编码的方法是,将输入数据流每次取6bit,用此6bit的值(0-63)作为索引去查表,输出相应字符。这样,每3个字节将编码为4个字符(3×8 → 4×6);不满4个字符的以'='填充。 Base64的算法很简单,它将字符流顺序放入一个24位的缓冲区,缺字符的地方补零。 然后将缓冲区截断成为4个部分,高位在先,每个部分6位,用64个字符重新表示。如果输入只有一个或两个字节,那么输出将用等号“=”补足。这可以隔断附加的信息造成编码的混乱。
QP
另一种方法是QP(Quote-Printable)方法,通常缩写为“Q”方法,其原理是把一个8 bit 的字符用两个16进制数值表示,然后在前面加“=”。所以我们看到经过QP编码后的文件通常是这个样子:=B3=C2=BF=A1=C7=E5=A3=AC=C4=FA=BA=C3=A3=A1。
QP编码要求编码后每行不能超过76个字符。当超过这个限制时,将使用软换行,用”=”表示编码行的断行,后接CRLF。(76的限制包括”=”)。
“=” 等号被编码为”=3D”。
tab和空格出现在行尾时,需要被编码为”=09”(tab) “=20”(space)
编码格式:encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
编码信息有"=?"和"?="括起来,"=?"后是字符集名称,再一个"?"后是编码方式,再一个"?"后是编码后的字符串。字符集和编码方式都不区分大小写。
字符集可以是任意系统支持的字符集(iso-8859-1、utf-8、gb2312、gbk、gb18030....)
编码方式有两种:"B"或"b"代表base64编码;"Q"或"q"代表QP编码。
Generally, an "encoded-word" is a sequence of printable ASCII characters that begins with "=?", ends with "?=", and has two "?"s in between. It specifies a character set and an encoding method, and also includes the original text encoded as graphic ASCII characters, according to the rules for that encoding method.
SMTP与MIME的关系
从上图可以看出发件人、收件人地址都出现了两次,一次在smtp命令中(SMTP email address),一次在邮件正文中(MIME email address)。需要注意的是:
- 邮件正文中可以包含发件人、收件人的别名,smtp命令中不可以
- 密送人的地址不一定会出现在邮件正文中。不同客户端实现不同。
本文参考了以下资源: