Python高级编程之SMTP邮件服务
Python SMTP发送邮件
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。
python的smtplib提供了一种很方便的途径发送电子邮件。它对smtp协议进行了简单的封装。
Python创建 SMTP 对象语法如下:
import smtplib smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )
参数说明:
- host: SMTP 服务器主机。 你可以指定主机的ip地址或者域名如: baidu.com,这个是可选参数。
- port: 如果你提供了 host 参数, 你需要指定 SMTP 服务使用的端口号,一般情况下 SMTP 端口号为25。
- local_hostname: 如果 SMTP 在你的本机上,你只需要指定服务器地址为 localhost 即可。
Python SMTP 对象使用 sendmail 方法发送邮件,语法如下:
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options]
参数说明:
- from_addr: 邮件发送者地址。
- to_addrs: 字符串列表,邮件发送地址。
- msg: 发送消息
这里要特别注意一下第三个参数,msg 是字符串,表示邮件。邮件一般由标题,发信人,收件人,邮件内容,附件等构成,发送邮件的时候,要注意 msg 的格式。这个格式就是 smtp 协议中定义的格式。
实例
首先开启并设置用于发件的QQ邮箱SMTP服务
如有问题,可点击这个Q&A
然后就是Python代码,使用QQ的SMTP服务,利用授权码,创建SMTP_SSL连接,发送邮件:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
mailSender = 'XXXXXXXX@qq.com'
# QQ邮箱帐户的提供的授权码
securityCode = 'cvfqrxroexaupajgd'
mailTarget = 'XXXXXXXX@qq.com'
def mail():
ret = True
try:
msg = MIMEText('这是邮件内容','plain','utf-8')
msg['From'] = formataddr(["这是发件人昵称",mailSender])
msg['To'] = formataddr(["这是收件人昵称",mailTarget])
# 邮件的主题(标题)
msg['Subject'] = "这是邮件Subject"
# 发件人QQ邮箱中的SMTP服务器,端口
server = smtplib.SMTP_SSL("smtp.qq.com", 465)
# 登录并发送
server.login(mailSender, securityCode)
server.sendmail(mailSender,[mailTarget,],msg.as_string())
server.quit()
except Exception as s:
ret = False
print "fail:",s
return ret
ret = mail()
if ret:
print("邮件发送成功")
else:
print("邮件发送失败")
效果如下 :
使用新浪的SMTP服务器,创建非SSL连接,发送邮件
1.先到sina邮箱打开smtp设置,如图所示
2.python代码如下:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import smtplib
#创建普通的SMTP(非SSL)
service = smtplib.SMTP("smtp.sina.cn",25)
#打印出和SMTP服务器交互的所有信息。SMTP协议就是简单的文本命令和响应
service.set_debuglevel(1)
#登录SMTP服务器
mailSender = "xxxxxx@sina.cn"
mailTarget = "yyyyyyy@qq.com"
service.login(mailSender,"passcode")
from email.mime.text import MIMEText
from email.utils import formataddr
#邮件正文
msg = MIMEText('这是邮件内容','plain','utf-8')
msg['From'] = formataddr(["这是发件人昵称",mailSender])
msg['To'] = formataddr(["这是收件人昵称",mailTarget])
# 邮件的主题(标题)
msg['Subject'] = "这是邮件Subject"
#发送邮件
try:
service.sendmail(mailSender,[mailTarget,],msg.as_string())
except Exception as s:
print "Error: 无法发送邮件:",s
CMD运行Python smtp_4.py后,中间连接步骤消息打印如下 :
beyondnoMacBookPro:~ beyond$ python /Users/beyond/sg_python/smtp_4.py
send: 'ehlo 1.0.0.127.in-addr.arpa\r\n'
reply: '250-smtp-5-123.smtpsmail.fmail.xd.sinanode.com\r\n'
reply: '250-AUTH LOGIN PLAIN\r\n'
reply: '250-AUTH=LOGIN PLAIN\r\n'
reply: '250-STARTTLS\r\n'
reply: '250 8BITMIME\r\n'
reply: retcode (250); Msg: smtp-5-123.smtpsmail.fmail.xd.sinanode.com
AUTH LOGIN PLAIN
AUTH=LOGIN PLAIN
STARTTLS
8BITMIME
send: 'AUTH PLAIN AGl4aXhpaUBzaW5hLmNuADEyMzQ1Nk9v\r\n'
reply: '235 OK Authenticated\r\n'
reply: retcode (235); Msg: OK Authenticated
send: 'mail FROM:<xxxxx@sina.cn>\r\n'
reply: '250 ok\r\n'
reply: retcode (250); Msg: ok
send: 'rcpt TO:<yyyyy@qq.com>\r\n'
reply: '250 ok\r\n'
reply: retcode (250); Msg: ok
send: 'data\r\n'
reply: '354 End data with <CR><LF>.<CR><LF>\r\n'
reply: retcode (354); Msg: End data with <CR><LF>.<CR><LF>
data: (354, 'End data with <CR><LF>.<CR><LF>')
send: 'Content-Type: text/plain; charset="utf-8"\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: base64\r\nFrom: \xe8\xbf\x99\xe6\x98\xaf\xe5\x8f\x91\xe4\xbb\xb6\xe4\xba\xba\xe6\x98\xb5\xe7\xa7\xb0 <xxxxx@sina.cn>\r\nTo: \xe8\xbf\x99\xe6\x98\xaf\xe6\x94\xb6\xe4\xbb\xb6\xe4\xba\xba\xe6\x98\xb5\xe7\xa7\xb0 <yyyyy@qq.com>\r\nSubject: \xe8\xbf\x99\xe6\x98\xaf\xe9\x82\xae\xe4\xbb\xb6Subject\r\n\r\n6L+Z5piv6YKu5Lu25YaF5a65\r\n.\r\n'
reply: '250 ok queue id 733794444351\r\n'
reply: retcode (250); Msg: ok queue id 733794444351
data: (250, 'ok queue id 733794444351')
效果如下:
QQ的SMTP只能使用SSL连接,代码极其类似:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import smtplib
#QQ只能创建SMTP_SSL
service = smtplib.SMTP_SSL("smtp.qq.com",465)#方法换成SMTP_SSL,端口从25换成465
#打印出和SMTP服务器交互的所有信息。SMTP协议就是简单的文本命令和响应
service.set_debuglevel(1)
#登录SMTP服务器
mailSender = "xxxx@qq.com"
mailTarget = "yyyy@qq.com"
pwd = "etmnhjmgqkymajia"#密码换成授权码
service.login(mailSender,pwd)
from email.mime.text import MIMEText
from email.utils import formataddr
#邮件正文
msg = MIMEText('这是邮件内容','plain','utf-8')
msg['From'] = formataddr(["这是发件人昵称",mailSender])
msg['To'] = formataddr(["这是收件人昵称",mailTarget])
# 邮件的主题(标题)
msg['Subject'] = "这是邮件Subject"
#发送邮件
try:
service.sendmail(mailSender,[mailTarget,],msg.as_string())
except Exception as s:
print "Error: 无法发送邮件:",s
发送HTML邮件:
使用Python发送HTML格式的邮件
Python发送HTML格式的邮件与发送纯文本消息的邮件不同之处就是将MIMEText中第2个参数_subtype由plain改为html。具体代码如下:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#发送HTML
import smtplib
#QQ只能创建SMTP_SSL
service = smtplib.SMTP_SSL("smtp.qq.com",465)
#打印出和SMTP服务器交互的所有信息。SMTP协议就是简单的文本命令和响应
service.set_debuglevel(1)
#登录SMTP服务器
mailSender = "xxx@qq.com"
mailTarget = "yyy@qq.com"
pwd = "etmnhjmgqkymajia"
service.login(mailSender,pwd)
from email.mime.text import MIMEText
from email.utils import formataddr
#邮件正文(plain,html)
mailContent = """
<p>html格式的内容</p>
<p><a href="http://www.baidu.com">百度一下</a></p>
"""
msg = MIMEText(mailContent,'html','utf-8')
msg['From'] = formataddr(["这是发件人昵称",mailSender])
msg['To'] = formataddr(["这是收件人昵称",mailTarget])
# 邮件的主题(标题)
msg['Subject'] = "这是邮件Subject"
#发送邮件
try:
service.sendmail(mailSender,[mailTarget,],msg.as_string())
except Exception as s:
print "Error: 无法发送邮件:",s
效果如下:
发送带附件的邮件:
带附件的邮件可以看做包含若干部分的邮件:文本和N个附件本身,所以,可以构造一个MIMEMultipart
对象代表邮件本身,然后往里面加上一个MIMEText
作为邮件正文,再继续往里面加上表示附件的MIMEBase
对象即可,代码如下图所示:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#发送带附件的邮件
import smtplib
#QQ只能创建SMTP_SSL
service = smtplib.SMTP_SSL("smtp.qq.com",465)
#打印出和SMTP服务器交互的所有信息。SMTP协议就是简单的文本命令和响应
service.set_debuglevel(1)
#登录SMTP服务器
mailSender = "xxx@qq.com"
mailTarget = "yyy@qq.com"
pwd = "etmnhjmgqkymajia"
service.login(mailSender,pwd)
from email.mime.text import MIMEText
from email.utils import formataddr
#附件
from email.mime.multipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import encoders
#邮件正文(plain,html)
mailContent = "带附件的邮件正文"
msgMulti = MIMEMultipart();
msgMulti['From'] = formataddr(["这是发件人昵称",mailSender])
msgMulti['To'] = formataddr(["这是收件人昵称",mailTarget])
# 邮件的主题(标题)
msgMulti['Subject'] = "这是带附件邮件的Subject"
# attach正文
msgMulti.attach(MIMEText(mailContent,'plain','utf-8'))
# attach附件1
# 添加附件就是加上一个MIMEBase,从本地读取一个图片:
with open('/Users/beyond/sg_python/iscream.jpg', 'rb') as iscreamImg:
# 设置附件的MIME和文件名,这里是png类型:
mimeFile = MIMEBase('image', 'png', filename='iscream.jpg')
# 加上必要的头信息:
mimeFile.add_header('Content-Disposition', 'attachment', filename='iscream.jpg')
mimeFile.add_header('Content-ID', '<0>')
mimeFile.add_header('X-Attachment-Id', '0')
# 把附件的内容读进来:
mimeFile.set_payload(iscreamImg.read())
# 用Base64编码:
encoders.encode_base64(mimeFile)
# 添加到MIMEMultipart:
msgMulti.attach(mimeFile)
# attach附件2
mimeFile2 = MIMEText(open('/Users/beyond/sg_python/QQ.dmg', 'rb').read(), 'base64', 'utf-8')
mimeFile2["Content-Type"] = 'application/octet-stream'
mimeFile2["Content-Disposition"] = 'attachment; filename="QQ.dmg"'
msgMulti.attach(mimeFile2)
#发送邮件
try:
service.sendmail(mailSender,[mailTarget,],msgMulti.as_string())
except Exception as s:
print "Error: 无法发送邮件:",s
运行效果如下:
附Python的SMTP模块详细函数参数摘要:
对于Python来说,需要编写脚本调用邮件服务器来发送邮件,使用的协议是SMTP。接收邮件,使用的协议是POP3和IMAP。
POP3和IMAP的区别:POP3在客户端邮箱中所做的操作不会反馈到邮箱服务器,比如删除一封邮件,邮箱服务器并不会删除。
IMAP则会反馈到邮箱服务器,会做相应的操作。
Python分别提供了收发邮件的库,smtplib、poplib和imaplib。
在smtplib库中,主要主要用smtplib.SMTP_SSL()类,用于连接SMTP服务器,发送邮件。
这个类有几个常用的方法:
方法 | 描述 |
SMTP.set_debuglevel(level) | 设置输出debug调试信息,默认不输出 |
SMTP.docmd(cmd[, argstring]) | 发送一个命令到SMTP服务器 |
SMTP.connect([host[, port]]) | 连接到指定的SMTP服务器 |
SMTP.helo([hostname]) | 使用helo指令向SMTP服务器确认你的身份 |
SMTP.ehlo(hostname) | 使用ehlo指令像ESMTP(SMTP扩展)确认你的身份 |
SMTP.ehlo_or_helo_if_needed() | 如果在以前的会话连接中没有提供ehlo或者helo指令,这个方法会调用ehlo()或helo() |
SMTP.has_extn(name) | 判断指定名称是否在SMTP服务器上 |
SMTP.verify(address) | 判断邮件地址是否在SMTP服务器上 |
SMTP.starttls([keyfile[, certfile]]) | 使SMTP连接运行在TLS模式,所有的SMTP指令都会被加密 |
SMTP.login(user, password) | 登录SMTP服务器 |
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) | 发送邮件 from_addr:邮件发件人 to_addrs:邮件收件人 msg:发送消息 |
SMTP.quit() | 关闭SMTP会话 |
SMTP.close() | 关闭SMTP服务器连接 |