ysm
cleverysm@gmail.com
很久以来一直在用Thunderbird的pop3功能收邮件,时间长了邮箱里积累了很多旧邮件,今天打算整理一下。由于曾经有段时间用瑞星,结果瑞星的邮件过滤功能在我很多邮件的标题里加了“(瑞星提示-此邮件可能是垃圾邮件)”这样的字样,而这邮件明明是正常的工作邮件,这个死瑞星真是笨死了。以前懒得理睬,结果时间一长,邮箱里竟有上百封邮件都被瑞星打了标签,现在发现看上去是多么的不爽,于是决定要解决这个问题。
首先,将Thunderbird里的几封被瑞星修改的邮件以eml的格式保存成文件。由于eml文件就是文本格式的,所以可以用notepad++打开看看是什么样子。其实不用太了解eml文件格式的细节也能很容易对文件各部分的含义作出判断,瑞星修改的是信件标题,也就是Subject:处的内容,只要找到瑞星修改的内容,然后删掉就ok了。
经过对照几个文件,发现瑞星就是在Subject:后面插入了一段如下的字符:
=?gb2312?B?KMjw0MfM4cq+LbTL08q8/r/JxNzKx8Csu/jTyrz+KQ==?=
虽然看不懂具体什么含义,但能很容猜出来,就是用gb2312编码的那句需要删掉的话。
由于需要修改的文件比较多,决定用python写段程序批量修改一下。
基本过程很简单,就是把有问题的邮件都保存成eml文件,放到一个目录下,然后程序依次读取文件,将要删掉的那段字符用空字符串地换一下就行了,代码如下:
def fix_eml_mail_1(from_dir, to_dir): from_dir_list=os.listdir(from_dir) for file in from_dir_list: from_file = open(from_dir+'/'+file) to_file = open(to_dir+'/'+file, 'w') content = from_file.read() to_file.write(content.replace('=?gb2312?B?KMjw0MfM4cq+LbTL08q8/r/JxNzKx8Csu/jTyrz+KQ==?=','')) print '%d files fixed' % len(from_dir_list)
修改后的eml文件再导入Thunderbird就ok了。导入的最简单办法就是,直接用鼠标拖进去。
不过,导入之后发现一个问题,仍有一小部分邮件标题里还有那句讨厌的话。再保存出来打开仔细观察,发现,其中有一部分是因为被瑞星修改标题的邮件被转发,于是标题再次被修改,这样那句话编码后的字符串就不是程序里的那样子,也就不会被删掉了。甚至有个别信件虽然不是转发或回复的信件,但是信件原有的标题不知为什么被一并包含进=?与?=之间进行了编码转换,同样无法用上面的代码消除。那该怎么办呢?看来得想办法把编码后的标题解码成正常文字,这个功能自然就想到了用python的email包。
首先,我们需要导入email包:
import email
然后,将文件读入一个Message对象msg中:
from_file = open('somewhere/mail.eml') msg = email.message_from_file(from_file)
接着读取邮件中的subject内容:
subject = msg.get("subject")
这时读出来的subject还是经过编码后的字符串,需要对其进行解码:
dh = email.Header.decode_header(subject)
这里的dh是一个包含多个元组元素的列表[('',''),('','')],列表中每个元素是一个元组(‘@#%%^%$#’,'charset’),元组的第一个元素是剔除了编码信息的subject内容,这个内容到这里依然是经过编码的,而其所使用的编码就是元组的第二个元素。元组可以有多于一个,表示subject里有多个编码的字段,比如可以有如下一个subject:
=?gb2312?B?asdfdgdsfdss?= =?gb2312?B?##@$%^&%$#?=
两段要有空格或换行隔开,这样dh中就是有两个元组了。
在处理问题邮件过程中发现瑞星在修改subject时是直接在原subject内容前面不加间隔紧贴着插上那么一句话,如果在这里不加处理直接用decode_header会无法正确识别瑞星那句话和原有的subject,唉,真可恶。只好在decode_header之前另加一个处理,上一句就变成:
subject = subject.replace('?=','?= ') dh = email.Header.decode_header(subject)
现在,我们就可以用下面一段来把subject打出来看看是什么效果:
for i in range(len(dh)): encode = dh[i][1] if encode is None: encode = msg.get_content_charset() if encode is None: encode = 'gbk' print "subject:", dh[i][0].decode(encode)
这个地方的编码首先是根据subject中编码信息来进行解码,但subject也不一定会是编码后的文本,这时dh[i][1]返回的是None,那么就试着查一下content编码,如果也不差不到,就用gbk,当然gbk也不一定就保险,因为也许有utf-8的信件,但一般我们多数情况下还是用gb2312和gbk写中文的,真碰到问题改一下就行了。
好,接下来就是需要把那段可恶的话删掉,然后给msg重做一个subject:
new_subject = '' new_dh=[] for i in range(len(dh)): encode = dh[i][1] if encode is None: encode = msg.get_content_charset() if encode is None: encode = 'gbk' str = dh[i][0].decode(encode) if str is not None: new_subject = str.replace(u'(瑞星提示-此邮件可能是垃圾邮件)','') new_subject = new_subject.encode(encode) new_dh.append((new_subject, encode)) new_header = email.Header.make_header(new_dh) msg.replace_header('Subject', new_header) to_file.write(msg.as_string())
把修改后的eml文件再导回Thunderbird,终于,干净了。
拜拜,瑞星。
完整的两段函数如下:
def fix_eml_mail_1(from_dir, to_dir): from_dir_list=os.listdir(from_dir) for file in from_dir_list: from_file = open(from_dir+'/'+file) to_file = open(to_dir+'/'+file, 'w') content = from_file.read() to_file.write(content.replace('=?gb2312?B?KMjw0MfM4cq+LbTL08q8/r/JxNzKx8Csu/jTyrz+KQ==?=','')) print '%d files fixed' % len(from_dir_list) pass def fix_eml_mail_2(from_dir, to_dir): from_dir_list=os.listdir(from_dir) for file in from_dir_list: from_file = open(from_dir+'/'+file) to_file = open(to_dir+'/'+file, 'w') msg = email.message_from_file(from_file) subject = msg.get("Subject") subject = subject.replace('?=','?= ') dh = email.Header.decode_header(subject) new_subject = '' new_dh=[] for i in range(len(dh)): encode = dh[i][1] if encode is None: encode = msg.get_content_charset() if encode is None: encode = 'gbk' str = dh[i][0].decode(encode) if str is not None: new_subject = str.replace(u'(瑞星提示-此邮件可能是垃圾邮件)','') new_subject = new_subject.encode(encode) new_dh.append((new_subject, encode)) new_header = email.Header.make_header(new_dh) msg.replace_header('Subject', new_header) to_file.write(msg.as_string())
代码下载:risingmail.py