Base64编码的目的是将输入的数据全部转换成由64个指定ASCII字符组成的字符序列, 这64个字符由{'A'-'Z', 'a'-'z', '0'-'9', '+', '/'}构成。编码时将需要转换的数据每次取出6bit,然后将其转换成十进制数字,这个数字的范围最小为0,最大为63,然后查询{'A'-'Z', 'a'-'z', '0'-'9', '+', '/'}构成的字典表,输出对应位置的ASCII码字符,这样每3个字节的数据内容会被转换成4个字典中的ASCII码字符,当转换到数据末尾不足3个字节时,则用“=”来填充。
1.4.2 Quoted-printable编码
Quoted-printable编码的目的也是将输入的信息转换成可打印的ASCII码字符,但它是根据信息的内容来决定是否进行编码,如果读入的字节处于33-60、62-126范围内的,这些都是可直接打印的ASCII字符,则直接输出,如果不是,则将该字节分为两个4bit,每个用一个16进制数字来表示,然后在前面加“=”,这样每个需要编码的字节会被转换成三个字符来表示。
2 MIME邮件信息提取
从上面的分析可以看出,MIME邮件传递的实际是一个经过特殊编码并以约定格式排列的字符序列,我们只需要提取存储在邮件各种域中的格式、位置和编码信息,按照根据这些信息从字符序列中提取出对应的字符内容并对其进行反向解码,就可以得到我们需要的有关内容。
下面给出.Net环境下,利用C#结合正则表达式从邮件中提取相关信息的基本思路和部分代码。
2.1 收件人/发件人/邮件主题的提取
收件人、发件人、邮件主题是一封邮件的基本组成信息,分别存邮件的From域、To域、Subject域中。开发中只需要通过正则表达式来匹配这些指定的域,然后从匹配结果中取出相关信息即可。
示例代码:提取邮件主题
string emailContent = “……”;//emailContent中存储的是邮件内容
pat = @"^Subject:\s*(?<title>.*)\s*\r\n";
myMatches = Regex.Matches(emailContent,pat,RegexOptions.Multiline);
foreach(Match nextMatch in myMatches)
{
GroupCollection myGroup = nextMatch.Groups;
string title = myGroup["title"].ToString();//title变量存储From域的内容
……
}
需要注意的是上面的代码提取的是跟随在Subject:后面的字符串,如果邮件的主题内容是中文或者其它需要编码的地区文字,则还需要对其进行解码。比如,如果邮件的Subject域中的信息是“你好”,那么提取出来的字符串会是这种形式:=?gb2312?B?xOO6ww==?=,第一个?同第二个?之间的gb2312代表标题内容所使用的字符集,第二个?和第三个?之间的B代表这部分内容采用的是base64编码方式,如果采用Quoted-printabel编码方式则显示Q,第三个?和第四个?之间则是“你好”经过base64编码后的字符串。
2.2 multipart分段信息的提取
邮件通过multipart类型将内容分隔成不同的段,各段之间的边界标识由对应multipart类型的boundary属性定义。要从邮件中提取出需要的内容,首先需要提取出邮件中的分段信息。下面的代码从一封邮件中提取出所有的multipart类型的名称和boundary属性。
示例代码:提取multipart信息
string emailContent = “……”;//emailContent中存储的是邮件内容
string pat = @"\bContent-Type:\s*(?<type>\w+/\w+);\s+(type=\S(?<subtype>\S+)\S)?\s+boundary=""(?<flag>\S+)""";
MatchCollection myMatches = Regex.Matches(emailContent,pat);
foreach(Match nextMatch in myMatches)
{
GroupCollection myGroup = nextMatch.Groups;
string type = myGroup["type"].ToString();//type变量存储multipart类型的名称
string flag = myGroup["flag"].ToString();//flag变量存储multipart类型的boundary属性
……
}