Python发邮件之邮件头,附件及包格式

最近研究用python发送Email的问题,对email header等方面的编码颇有心得,着笔记录下,以备后查。

用python发的整个邮件,每个元素都以/r/n结束(当然如果内容里有/r/n如何就不太清楚了)。其邮件内容都是被一个大的boundary包起来的,Content-Type为multipart/mixed。

header部分,大致有MIME-Version、From、To、Subject等,看情况而定(事实上,我观察注意到,很多邮件服务器在处理邮件的时候,都会自动会加上些邮件头,如Received等)。下面重点记录下这几个常用项。

From表示邮件来源,格式为:显示名 <邮件地址>,记得两个项目之间应使用空格隔开。其中显示名部分可以允许为中文,但如果是中文,就要注意编码的问题。用python来实现是非常简单的:

from email.Header import Header
frm = Header('刘开良', 'utf-8')
frm.append(' ', 'ascii')
print(frm.encode())

打印出来,就是:=?utf-8?b?5YiY5byA6Imv?= kailiangliu@gmail.com。可以看出,这个内容里本身就有编码信息,因此反过来解析也很简单。因为=?、?、?=属于分隔符,用这三个分隔符简单的split后(re.recompile(r'''=/?(/?)(/?=''').split('=?utf-8?b?5YiY5byA6Imv?='))。可以得到['', 'utf-8', 'b', '5YiY5byA6Imv', ''],根据python的源码显示,utf-8表示数据编码,b表示base64。那么对内容'5YiY5byA6Imv'进行base64.b64decode后,就可得到utf-8编码的“刘开良”三个字。

搞清楚了From字段,那么To字段其实就简单了。To里如果只有一个地址的话,就和From里的格式是完全一样的。如果有多个,那么每个之间用逗号及换行(,/r/n)分割就可以了。一般我们在python代码里可以只用逗号分隔就行了,底层库会自动加上/r/n的。

Subject的内容,其实也和From里的“显示名”的编码方式一样的。如“测试邮件”,编码后就是:'=?utf-8?b?5rWL6K+V6YKu5Lu2?='。

搞清楚了邮件头,就可以来看看邮件的正文及附件。

其实邮件的正文和附件是在一起编码的,只是他们的Content-Type有区别罢了。比如正文的type一般是text/plain或text/html等,而附件的type一般是:application/octet-stream。但type不同,对应的内容头也会略有不同。

但这些都不需要太担心,因为python库大多会帮我们做好的。

为了发送带附件的邮件,我们一般要创建一个最外层的对象,msg = MIMEMultipart()。然后需要邮件内容就msg.attach(MIMEText("邮件内容", 'plain', 'utf-8')), 需要添加附件的话,要麻烦一点,用

att = MIMEText(open(filename, 'rb').read(), 'base64', 'utf-8')
att["Content-Type"] = 'application/octet-stream'
att["Content-Disposition"] = 'attachment; filename="%s"' % filename
msg.attach(att)

其他邮件头也一并设到里面,

msg['From'] = Header('刘开良', 'utf-8')
msg['From'].append(' <' + frm + '>', 'ascii')
msg['To'] = Header(','.join(to), 'ascii')
smtplib.sendmail(frm, to,  msg.as_string())

需要登录的话,就用smtplib对象的login函数即可。

来源:网络