电子邮件
电子邮件软件成为MUA:Mail User Agent—-邮件用户代理。E-mail从MUA发出去,不是直接到达对方电脑而是发到MTA(Mail Transfer Agent—邮件传输代理),就是Email服务提供商,比如网易,新浪等。MTA会把email投递到MDA(Mail Delivery Agent—邮件投递代理),存储在某个文件或特殊的数据库里也就是邮箱。要想获取邮件,必须通过MUA从MDA上获取到自己电脑上。
发件人—>MUA—>MTA—>MTA—>若干个MTA—>MDA<—MUA<—收件人
要编写程序来发送和接收邮件,本质上就是:
1、编写MUA把邮件发到MTA
2、编写MUA从MDA上收邮件
发邮件时MUA和MTA使用的协议是SMTP:Simple Mail Transfer Protocol。
收邮件时,MUA和MDA使用的协议有两种:POP:Post Office Protocol,目前版本是3,俗称POP3;IMAP:Internet Message Access Protocol,目前版本是4,优点是不但能取邮件,还可以直接操作MDA上存储的邮件,比如从收件箱移到垃圾箱。
邮件客户端在发邮件时,会让你先配置SMTP服务器,也就是你要发到哪个MTA上。比如你在用163邮箱,就不能直接发送到新浪的MTA上,你要填163提供的SMTP服务器地址:smtp.163.com
,还需要输入邮箱地址和邮箱口令来证明你是163用户,这样MUA才能正常地把Email通过SMTP协议发送到MTA。
从MDA收取邮件时,MDA服务器会要求验证邮箱口令,这样MUA才能顺利地通过POP或IMAP协议从MDA获取邮件。
SMTP发送邮件
SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件,HTML邮件及其附件。
Python对SMTP支持有smtplib
和email
两个模块,email
负责构造邮件,stmplib
负责发送邮件。首先,我们来构造一个最简单的纯文本邮件:
注意到构造MIMEText
对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入plain
表示纯文本,最终的MIME就是text/plain
,最后一定要用utf-8
编码保证多语言兼容性。然后通过SMTP发送出去:
我们用set_debuglevel(1)
就可以打印出和SMTP服务器交互的所有信息。SMTP协议就是简单的文本命令和相应。login()
方法用来登录SMTP服务器,sendmail()
方法就是发邮件,由于可以一次发给对个人,所以传入一个list
,邮件正文是一个str
,as_string()
把MIMEText对象编程str
。收到的邮件的问题是没有主题收件人没有显示为友好的名字,且收到了邮件却提示你不在收件人中。这是因为邮件主题、如何显示发件人、收件人的信息并不是通过SMTP协议发给MTA,而是包含在发给MTA的文本中的,所以,我们必须把From、To、Subject添加到MIMEText中才是一封完整的邮件:
我们编写了一个函数_format_addr()
来格式化一个邮件地址。注意不能简单地传入name <addr@example.com>
,因为如果包含中文,需要通过Header
对象编码。
msg['To']
发送的是字符串而不是list,如果有多个地址邮件,用,分隔即可。发送邮箱显示:
你看到的收件人的名字可能不是我们传入的管理员,因为很多邮件服务商在显示邮件时会把收件人名字自动替换为用户注册的名字。我们插卡Email原始内容如下:
From: =?utf-8?b?UHl0aG9u54ix5aW96ICF?= xxxxxx@163.com
To: =?utf-8?b?566h55CG5ZGY?= xxxxxx@qq.com
Subject: =?utf-8?b?5p2l6IeqU01UUOeahOmXruWAmeKApuKApg==?=
发送HTML邮件
如果我们要发送HTML邮件而不是普通的纯文本文件怎么办,就在构造MIMEText
对象时,把HTML字符串传进去,再把第二个参数由plain改为plain就可以了:
再发送一遍邮件:
发送附件
如果Email中要加上附件,可以把带附件的邮件看做包含若干部分的邮件:文本和各个附件本身,所以可以构造一个MIMEMultipart
对象代表邮件本身,然后往里面加上一个MIMEText
作为邮件正文,再继续往里面加上表示附件的MIMEBase
对象即可:
发送结果:
发送图片
如果要把一个图片嵌入到邮件正文中,直接在HTML邮件中连接图片地址是不行的,我们需要按照发送附件的方法,把邮件作为附件添加进去,然后在HTML中通过引用src="cid:0"
就可以把附件作为图片嵌入。如果有多个图片,可以依次编号,然后引用不同的cid:x
就可以。
把上面代码中加入MIMEMultipart
的MIMEText
从plain
改为html
,然后在适当的位置引用图片:
发送结果:
同时支持HTML和Plain格式
如果我们发送HTML邮件,收件人通过浏览器或者Outlook之类的软件是可以正常浏览邮件内容的,但是如果收件人的设备无法查看HTML邮件时,我们可以在发送HTML的同时再附加一个纯文本,如果收件人无法查看HTML格式的邮件,就可以自动降级查看纯文本邮件。
利用MIMEMultipart
可以组合一个HTML和Plain,要注意指定subtype是alternative
:
加密SMTP
使用标准的25端口连接SMTP服务器时,使用的是明文传输,发送邮件的整个过程可能会被窃听。要更安全地发送邮件,可以加密SMTP会话,实际上就是先创建SSL安全连接,然后再使用SMTP协议发送邮件。
Gmail提供的SMTP服务必须要加密传输。首先知道Gmail的SMTP端口是587,修改代码如下:
只需要在创建SMTP对象后,立刻调用starttls()
方法,就创建了安全链接。后面的代码和前面的发送邮件代码完全一样。
使用Python的smtplib发送邮件很简单,只要掌握了各种邮件类型的构造方法,正确设置好邮件头就可以顺利发出。构造一个邮件对象就是一个Message
对象,如果构建一个MIMEText
对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart
,MIMEBase
可以表示任何对象,继承关系如下:
POP3收取邮件
收邮件就是编写一个MUA作为客户端,从MDA把邮件获取到用户的电脑或者手机上。收取邮件最常用的协议是POP协议。Python内置了一个poplib
模块,实现了POP3协议。
POP3收取的不是一个已经可以阅读的邮件本身,而是邮件的原始文本,这和SMTP一样,SMTP发送的也是经过编码后的一大段文本。要把POP3收取的文本变为可以阅读的邮件,还需要用email
模块提供的各种类来解析原始文本,变成可阅读的邮件对象。收取邮件分为两部分:
1、用
poplib
把邮件的原始文本下载到本地;
2、用
通过POP3下载邮件
POP3的协议本身很简单,以下面的代码为例,我们来获取最新的一封邮件内容:
用POP3协议很简单,要获取所有邮件,只需要循环使用retr()
把每一封邮件内容拿到即可。
解析邮件
解析邮件的过程和上一节构造邮件刚好相反,必须导入必要的模块:
一行代码可以把邮件内容解析为Message对象:
这个Message
对象本身可能是一个MIMEMultipart
对象,即包含嵌套的其他MIMEBase
对象,嵌套可能还不止一层。所以我们要递归地打印出Message对象的层次结构:
邮件的Subject或者Email中包含的名字都是经过编码后的str,要正常显示,就必须decode:
decode_header()
返回一个list,因为像Cc``Bcc
这样的字段可能包含多个邮件地址,所以解析出来的会有多个元素。上面的代码我们只取了第一个元素。文本邮件的内容也是str,还需要检测编码,否则非UTF-8编码的邮件都无法正常显示:
把上面的代码整理好,我们就可以来试试获取一封邮件。先往自己的邮箱发送一封邮件,然后用Python程序把它收到本地:
源码: