#SMTP是发送邮件的协议,Python内置对SMTP支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。本节腾讯企业邮箱的服务为例进行介绍。学习本节内容时,可以自己开通对应的邮箱服务,各个邮件服务公司有介绍邮箱服务的开通方法,参照这些开通方法开通即可。如果安装了邮箱服务,就可以使用自己的邮箱服务器进行学习。
1、SMTP发送邮件
#Python对SMTP的支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。
#简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)是从源地址到目的地址传送邮件的规则,由该协议控制信件的中转方式。
#Python的smtplib提供了一种很方便的途径发送电子邮件,对SMTP协议进行了简单的封装。
#Python创建SMTP对象的语法如下:
1 smtpObj=smtplib.SMTP([host[,port[,local_hostname]]])
#语法中各个参数说明如下:
#host:SMTP服务器主机。可以指定主机的IP地址或域名(如www.baidu.com),是可选参数。
#port:如果提供了host参数,就需要指定SMTP服务使用的端口号。一般情况下SMTP的端口号为25.
#local_hostname:如果SMTP在本机主机上,只需要指定服务器地址为localhost即可。
#如果创建SMTP对象时提供了host和port两个参数,在初始化时会自动调用connect方法连接服务器。
#PythonSMTP对象使用sendmail方法发送邮件的语法如下:
1 SMTP.sendmail(from_addr,to_addrs,msg[,mail_options,rcpt_options])
#语法中各个参数说明如下:
#from_addr:邮件发送者的地址。
#to_adds:字符串列表,邮件发送地址。
#msg:发送消息。
#msg是字符串,表示邮件内容。我们知道邮件一般由标题、发信人、收件人、邮件内容、附件等构成,发送邮件时,要注意msg的格式。这个格式就是SMTP协议中定义的格式。
#SMTP类中提供了下表所示的一下常用方法。
方法
|
描述
|
set_debuglevel(level)
|
设置是否为调试模式。默认为False,即非调试模式,
表示不输出任何调试信息
|
connect([host[,port]])
|
连接到指定的SMTP服务器。参数分别表示SMTP主机和端口
|
docmd(cmd,[,argstring])
|
向SMTP服务器发送指令。可选参数argstring表示指令的参数
|
helo([hostname])
|
向服务器确认身份。相当于告诉SMTP服务器“我是谁”
|
has_extn(name)
|
判断指定名称在服务器邮件列表中是否存在,
出于安全考虑。SMTP服务器往往屏蔽该指令
|
verify(address)
|
判断指定邮件地址是否在服务器中存在。
出于安全考虑,SMTP服务器往往屏蔽该指令
|
login(use,password)
|
登陆SMTP服务器。现在几乎所有SMTP服务器都必须验证
用户信息合法后才允许发送邮件
|
quit()
|
断开与SMTP服务器的连接,相当于发送quit指令
|
#普通文本邮件发送的实现关键要将MIMEText中的_subtype设置为plain。首先导入smtplib和mimetext。创建smtplib.smtp实例,连接邮件SMTP服务器,登陆后发送,具体代码如下:
1 #! /usr/bin/python3 2 #-*-coding:UTF-8-*- 3 #Email 4 5 import smtplib 6 from email.mime.text import MIMEText 7 from email.header import Header 8 sender='from@qq.com' #发件人 9 pwd='xxxxxxx' #邮箱密码 10 receivers=['xxxxxxxxx@qq.com'] #收件人 11 12 message=MIMEText('This is test','plain','utf-8') #邮件文本 13 message['From']=Header('测试邮件','utf-8') #邮件主题 14 message['To']=Header('测试收件人') #邮件收件人显示名称 15 16 subject='Python email test' 17 message['Subject']=Header(subject,'utf-8') 18 19 try: 20 smtpObj=smtplib.SMTP_SSL("smtp.exmail.qq.com",465) 21 smtpObj.login(sender,pwd) 22 smtpObj.sendmail(sender,receivers,message.as_string()) 23 print("邮件发送成功") 24 except smtplib.SMTPException as e: 25 print("Error:无法发送邮件.Case:%s"%e)
#我们使用3个引号设置邮件信息。标准邮件需要3个头部信息:From、To和Subject。每个信息直接使用空行分割。
#我们通过实例化smtplib模块的SMTP_SSL对象smtpObj连接SMTP访问,并使用sendermail方法发送信息。
#执行以上程序,如果你开通了非本地邮件服务,就会输出:
1 D:\Python\workspace\datatime\20180210>python Email.py 2 邮件发送成功
#如果本地主机安装了sendmail服务,发送邮件的代码可以更改为:
1 #! /usr/bin/python3 2 #-*-coding:UTF-8-*- 3 #localhost_email 4 5 import smtplib 6 from email.mime.text import MIMEText 7 from email.header import Header 8 9 sender='xxxxxx@xxxxxx.com' 10 receviers=['xxxxxxx@qq.com'] 11 12 message=MIMEText('Thi is test mail','plain','utf-8') 13 message['From']=Header('测试邮件','utf-8') 14 message['To']=Header('测试收件','utf-8') 15 16 subject='Python test mail' 17 message['Subject']=Header(subject,'utf-8') 18 19 try: 20 smtpObj=smtplib.SMTP('localhost') 21 smtpObj.sendermail(sender,receviers,message.as_string()) 22 print('邮件发送成功') 23 except smtplib.SMTPException as e: 24 print('Error:无法发送邮件.Case:'%e)
#不需要客户端授权密码、SSL连接和登陆服务。
2、发送HTML格式邮件
#如果我们要发送的是HTML邮件,而不是普通的纯文本文件怎么办?方法很简单,在构造MIMEText对象时把HTML字符串传进去,再把第二个参数由plain变为html就可以了。代码实现如下:
1 #! /usr/bin/python3 2 #-*-coding:UTF-8-*- 3 #HTML_Email 4 5 import smtplib 6 from email.mime.text import MIMEText 7 from email.header import Header 8 9 sender='xxxxxx@xxxxxx.com' 10 pwd='xxxxx' 11 receivers=['xxxxxxxxxx@qq.com'] 12 13 mail_msg=""" 14 <p>Python test mail..</p> 15 <p><a href="http://www.cnblogs.com/DLHe/">这是一个链接</a></p> 16 """ 17 18 message=MIMEText(mail_msg,'html','utf-8') 19 message['From']=Header('test mail','utf-8') 20 message['To']=Header('test','utf-8') 21 subject="Python test mail" 22 message['Subject']=Header(subject,'utf-8') 23 24 try: 25 smtpObj=smtplib.SMTP_SSL('smtp.exmail.qq.com',465) 26 smtpObj.login(sender,pwd) 27 smtpObj.sendmail(sender,receivers,message.as_string()) 28 print('邮件发送成功') 29 except smtplib.SMTPException as e: 30 print('Error:无法发送邮件.Case:%s'%e)
#执行以上程序,如果你开通了非本地服务,就会输出:
1 D:\Pythonworkspace>python HTML_Email.py 2 邮件发送成功
3、发送带附件的邮件
#如果Email中要添加附件怎么办?
#带附件的邮件可以看作包含文本和各个附件,可以构造一个MIMEMultipart对象代表邮件本身,然后往里面添加一个MIMEText作为邮件正文,再添加表示附件的MIMEBase对象即可。代码实现如下:
1 #! /usr/bin/python3 2 #-*-coding:UTF-8-*- 3 4 5 import smtplib 6 from email.mime.text import MIMEText 7 from email.mime.multipart import MIMEMultipart 8 from email.header import Header 9 10 sender='xxxx@xxx.com' 11 pwd='xxxxxx' 12 receviers=['xxxxxxxxxxxxxx@qq.com'] 13 14 message=MIMEMultipart() 15 message['From']=Header('test mail','utf-8') 16 message['To']=Header('test','utf-8') 17 subject='Python mail test' 18 message['Subject']=Header(subject,'utf-8') 19 message.attach(MIMEText('This is a mail test','plain','utf-8')) 20 21 att1=MIMEText(open('test.txt','rb').read(),'base64','utf-8') 22 att1['Content-Type']='application/octet-stream' 23 att1['Content-Disposition']='attachment;filname="test.txt"' 24 message.attach(att1) 25 26 att2=MIMEText(open('runoob.txt','rb').read(),'base64','utf-8') 27 att2['Content-Type']='application/octet-stream' 28 att2['Content-Disposition']='attachment;filname="runoob.txt' 29 message.attach(att2) 30 31 try: 32 smtpObj=smtplib.SMTP_SSL('smtp.exmail.qq.com',465) 33 smtpObj.login(sender,pwd) 34 smtpObj.sendmail(sender,receviers,message.as_string()) 35 print('邮件发送成功') 36 except smtplib.SMTPException as e: 37 print('Error:无法发送邮件.Case:%s'%e)
#执行结果如下:
1 D:\Pythonworkspace>python MIMEMultipart.py 2 邮件发送成功
#如果本地主机安装了sendmail服务,就不需要客户端授权密码、SSL连接和登陆服务,直接使用smtplib模块的SMTP对象连接本地访问即可。
4、发送图片
#如果要把一个图片嵌入邮件正文,怎么做呢?是否可以直接在HTML邮件中链接图片地址?
#大部分邮件服务商都会自动屏蔽带有外链的图片,因为不知道这些链接是否指向恶意网址。
#要把图片嵌入邮件正文,我们只需要按照发送附件的方式把邮件作为附件添加进去,然后在HTML中通过引用src="cid:0"把附件作为图片嵌入。如果有多张图片,就需要给他们一次编号,然后引用不用的cid:x。
1 #! /usr/bin/python3 2 #-*-coding:UTF-8-*- 3 #src 4 5 import smtplib 6 from email.mime.image import MIMEImage 7 from email.mime.multipart import MIMEMultipart 8 from email.mime.text import MIMEText 9 from email.header import Header 10 11 sender='xxxxx@xxxxxx.com' 12 pwd='bxxxxxxx' 13 receivers=['xxxxxxxx@qq.com'] 14 15 msgRoot=MIMEMultipart('related') 16 msgRoot['From']=Header('test mail','utf-8') 17 msgRoot['To']=Header('test','utf-8') 18 subject='Python test mail' 19 msgRoot['Subject']=Header(subject,'utf-8') 20 21 msgAlternative=MIMEMultipart('alternative') 22 msgRoot.attach(msgAlternative) 23 24 mail_msg=""" 25 <p>Python test mail...</p> 26 <p><a href="http://www.python.org">Python官方网站</a></p> 27 <p>图片演示:</p> 28 <p><img src="cid:image1"></p> 29 """ 30 31 msgAlternative.attach(MIMEText(mail_msg,'html','utf-8')) 32 33 #指定图片为当前目录 34 fp=open('test.png','rb') 35 msgImage=MIMEImage(fp.read()) 36 fp.close() 37 38 #定义图片ID,在HTML文本中引用 39 msgImage.add_header('Content-ID','<image1>') 40 msgRoot.attach(msgImage) 41 42 try: 43 #使用非本地服务器,需要建立ssl连接 44 smtpObj=smtplib.SMTP_SSL("smtp.exmail.qq.com",465) 45 smtpObj.login(sender,pwd) 46 smtpObj.sendmail(sender,receivers,msgRoot.as_string()) 47 print("邮件发送成功") 48 except smtplib.SMTPException as e: 49 print('Error:无法发送邮件.Case:%s'%e)
#执行以上程序,如果有开通了非本地服务,就会输出:
1 D:\Python\workspace\datatime\20180211>python src.py 2 邮件发送成功
#如果本地主机安装了sendmail服务,就不需要客户端授权密码、SSL连接和登陆服务,直接使用smtplib模块的SMTP对象连接本地访问即可。
5、同时支持HTML和Plain格式
#如果我们发送HTML邮件,收件人通过浏览器或Outlook之类的软件就可以正常浏览邮件内容。如果收件人使用的设备太古老,查看不了HTML邮件怎么办呢?
#办法实在发送HTML的同时附件一个纯文本,如果收件人无法查看HTML格式的邮件,就可以自动降级查看纯文本邮件。
#利用MIMEMultipart可以组合一个HTML和Plain,注意指定是subtype是alternative。使用代码格式如下:
1 #! /usr/bin/python3 2 #-*-coding:UTF-8-*- 3 #HTML_PLAIN 4 5 import smtplib 6 from email.mime.image import MIMEImage 7 from email.mime.multipart import MIMEMultipart 8 from email.mime.text import MIMEText 9 from email.header import Header 10 11 sender='xxxxx@xxxxx.com' 12 pwd='xxxxxx' 13 receivers=['xxxxx@qq.com'] 14 15 msgRoot=MIMEMultipart('related') 16 msgRoot['From']=Header('test mail','utf-8') 17 msgRoot['To']=Header('TEST','utf-8') 18 subject='Python test mail' 19 msgRoot['Subject']=Header(subject,'utf-8') 20 21 msgAlternative=MIMEMultipart('alternative') 22 msgRoot.attach(msgAlternative) 23 24 msgAlternative.attach(MIMEText('hello','plain','utf-8')) 25 mail_msg='<html><body><h1>hello</h1></body></html>' 26 msgAlternative.attach(MIMEText(mail_msg,'html','utf-8')) 27 28 #指定图片为当前目录 29 fp=open('test.png','rb') 30 msgImage=MIMEImage(fp.read()) 31 fp.close() 32 33 #定义图片ID,在HTML文本中引用 34 msgImage.add_header('Content-ID','<image1>') 35 msgRoot.attach(msgImage) 36 37 try: 38 smtpObj=smtplib.SMTP_SSL("smtp.exmail.qq.com",465) 39 smtpObj.login(sender,pwd) 40 smtpObj.sendmail(sender,receivers,msgRoot.as_string()) 41 print('邮件发送成功') 42 except smtplib.SMTPException as e: 43 print('Error:无法发送邮件.Case:%s'%e)
#执行以上程序,如果你开通了非本地服务,就会输出:
D:\Python\workspace\datatime\20180211>python HTML_PLAIN.py
邮件发送成功
6、加密SMTP
#使用标准25端口连接SMTP服务器时使用的是明文传输,发送邮件的整个过程可能会被窃听。要更安全地发送邮件,可以加密SMTP会话,实际上是先创建SSL安全连接,然后使用SMTP协议发送邮件。
#某些邮件服务商(如Gmail)提供的SMTP服务必须进行加密传输。下面来看如何通过Gmail提供的安全SMTP发送邮件。
#由于Gmail的SMTP端口是587,因此修改代码如下:
1 smtp_server='smtp.gmail.com' 2 smtp_port=587 3 server=smtplib.SMTP(smtp_server,smtp_port) 4 server.starttls() 5 server.set_debuglevel(1)
#只需要要创建SMTP对象后立刻调用starttls()方法,就可以创建安全连接。后面的代码和前面的发送邮件代码完全一样。