第十四章 Python发送邮件(常见四种邮件内容)

简介:
在写脚本时,放到后台运行,想知道执行情况,会通过邮件、SMS(短信)、飞信、微信等方式通知管理员,用的最多的是邮件。在linux下,Shell脚本发送邮件告警是件很简单的事,有现成的邮件服务软件或者调用运营商邮箱服务器。
对于Python来说,需要编写脚本调用邮件服务器来发送邮件,使用的协议是SMTP。接收邮件,使用的协议是POP3和IMAP。 我想有必要说明下 , POP3和IMAP的区别:POP3在客户端邮箱中所做的操作不会反馈到邮箱服务器,比如删除一封邮件,邮箱服务器并不会删除。IMAP则会反馈到邮箱服务器,会做相应的操作。
Python分别提供了收发邮件的库,smtplib、poplib和imaplib。
本章主要讲解如果使用smtplib库实现发送各种形式的邮件内容。 在smtplib库中,主要主要用smtplib.SMTP()类,用于连接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服务器连接
看下官方给的示例:
>>> import smtplib
>>> s=smtplib.SMTP("localhost")
>>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
>>> msg = '''\
     ... From: Me@my.org
     ... Subject: testin'...
     ...
     ... This is a test '''
>>> s.sendmail("me@my.org",tolist,msg)
     { "three@three.org" : ( 550 ,"User unknown" ) }
>>> s.quit()
我们根据示例给自己发一个邮件测试下:
我这里测试使用本地的SMTP服务器,也就是要装一个支持SMTP协议的服务,比如sendmail、postfix等。CentOS安装sendmail:yum install sendmail
>>> import smtplib
>>> s = smtplib.SMTP("localhost")
>>> tolist = ["xxx@qq.com", "xxx@163.com"]
>>> msg = '''\
... From: Me@my.org
... Subject: test
... This is a test '''
>>> s.sendmail("me@my.org", tolist, msg)
{}
进入腾讯和网易收件人邮箱,就能看到刚发的测试邮件,一般都被邮箱服务器过滤成垃圾邮件,所以收件箱没有,你要去垃圾箱看看。
可以看到,多个收件人可以放到一个列表中进行群发。msg对象里From表示发件人,Subject是邮件标题,换行后输入的是邮件内容。
上面是使用本地SMTP服务器发送的邮件,测试下用163服务器发送邮件看看效果:
>>> import smtplib
>>> s = smtplib.SMTP("smtp.163.com")
>>> s.login("baojingtongzhi@163.com", "xxx")
(235, 'Authentication successful')
>>> tolist = ["xxx@qq.com", "xxx@163.com"]
>>> msg = '''\
... From: baojingtongzhi@163.com
... Subject: test
... This is a test '''
>>> s.sendmail("baojingtongzhi@163.com", tolist, msg)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.6/smtplib.py", line 725, in sendmail
    raise SMTPDataError(code, resp)
smtplib.SMTPDataError: (554, 'DT:SPM 163 smtp10,DsCowAAXIdDIJAtYkZiTAA--.65425S2 1477125592,please see http://mail.163.com/help/help_spam_16.htm?ip=119.57.73.67&hostid=smtp10&time=1477125592')
访问给出的163网址,SMTP554错误是: "554 DT:SUM 信封发件人和信头发件人不匹配;"
大概已经明白啥意思,看上面再使用本地SMTP服务器时候,收件人位置是“undisclosed-recipients”,看这样163的SMTP服务器不给我们服务的原因就是这里收件人没指定。
重新修改下msg对象,添加上收件人:
>>> msg = '''\           
... From: baojingtongzhi@163.com
... To: 962510244@qq.com ,zhenliang369@163.com
... Subject: test
...
... This is a test '''
>>> s.sendmail("baojingtongzhi@163.com", tolist, msg)
{}
好了,可以正常发送邮件了。msg这个格式是SMTP规定的,一定要遵守。
14.1 Python发送邮件并抄送
#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib

def sendMail(body):
    smtp_server = 'smtp.163.com'
    from_mail = 'baojingtongzhi@163.com'
    mail_pass = 'xxx'
    to_mail = ['962510244@qq.com', 'zhenliang369@163.com']
    cc_mail = ['lizhenliang@xxx.com']
    from_name = 'monitor' 
    subject = u'监控'.encode('gbk')   # 以gbk编码发送,一般邮件客户端都能识别

#     msg = '''\
# From: %s <%s>
# To: %s
# Subject: %s

# %s''' %(from_name, from_mail, to_mail_str, subject, body)  # 这种方式必须将邮件头信息靠左,也就是每行开头不能用空格,否则报SMTP 554

    mail = [
        "From: %s <%s>" % (from_name, from_mail),
        "To: %s" % ','.join(to_mail),   # 转成字符串,以逗号分隔元素
        "Subject: %s" % subject,
        "Cc: %s" % ','.join(cc_mail),
        "",
        body
        ]
    msg = '\n'.join(mail)  # 这种方式先将头信息放到列表中,然后用join拼接,并以换行符分隔元素,结果就是和上面注释一样了

    try:
        s = smtplib.SMTP()
        s.connect(smtp_server, '25')
        s.login(from_mail, mail_pass)
        s.sendmail(from_mail, to_mail+cc_mail, msg)   
        s.quit()
    except smtplib.SMTPException as e:
        print "Error: %s" %e
if __name__ == "__main__":
    sendMail("This is a test!")
s.sendmail(from_mail, to_mail+cc_mail, msg) 在这里注意下,收件人和抄送人为什么放一起发送呢?其实无论是收件人还是抄送人,它们收到的邮件都是一样的,SMTP都是认为收件人这样一封一封的发出。所以实际上并没有抄送这个概念,只是在邮件头加了抄送人的信息罢了!另外,如果不需要抄送人,直接把上面cc的信息去掉即可。
14.2 Python发送邮件带附件
由于SMTP.sendmail()方法不支持添加附件,所以可以使用email模块来满足需求。email模块是一个构造邮件和解析邮件的模块。
先看下如何用email库构造一个简单的邮件:
message = Message()
message['Subject'] = '邮件主题'
message['From'] = from_mail
message['To'] = to_mail
message['Cc'] = cc_mail
message.set_payload('邮件内容')
基本的格式就是这样的!
继续回到主题,发送邮件带附件:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email import encoders
from email.mime.base import MIMEBase
from email.utils import parseaddr, formataddr

# 格式化邮件地址
def formatAddr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

def sendMail(body, attachment):
    smtp_server = 'smtp.163.com'
    from_mail = 'baojingtongzhi@163.com'
    mail_pass = 'xxx'
    to_mail = ['962510244@qq.com', 'zhenliang369@163.com']

    # 构造一个MIMEMultipart对象代表邮件本身
    msg = MIMEMultipart()
    # Header对中文进行转码
    msg['From'] = formatAddr('管理员 <%s>' % from_mail).encode()
    msg['To'] = ','.join(to_mail)
    msg['Subject'] = Header('监控', 'utf-8').encode()

    # plain代表纯文本
    msg.attach(MIMEText(body, 'plain', 'utf-8'))

    # 二进制方式模式文件
    with open(attachment, 'rb') as f:
        # MIMEBase表示附件的对象
        mime = MIMEBase('text', 'txt', filename=attachment)
        # filename是显示附件名字
        mime.add_header('Content-Disposition', 'attachment', filename=attachment)
        # 获取附件内容
        mime.set_payload(f.read())
        encoders.encode_base64(mime)
        # 作为附件添加到邮件
        msg.attach(mime)
    try:
        s = smtplib.SMTP()
        s.connect(smtp_server, "25")
        s.login(from_mail, mail_pass)
        s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText对象变成str
        s.quit()
    except smtplib.SMTPException as e:
        print "Error: %s" % e
if __name__ == "__main__":
    sendMail('附件是测试数据, 请查收!', 'test.txt')

博客地址:http://lizhenliang.blog.51cto.com and https://yq.aliyun.com/u/lizhenliang
QQ群:323779636(Shell/Python运维开发群)

14.3 Python发送HTML邮件
#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import parseaddr, formataddr

# 格式化邮件地址
def formatAddr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

def sendMail(body):
    smtp_server = 'smtp.163.com'
    from_mail = 'baojingtongzhi@163.com'
    mail_pass = 'xxx'
    to_mail = ['962510244@qq.com', 'zhenliang369@163.com']

    # 构造一个MIMEMultipart对象代表邮件本身
    msg = MIMEMultipart() 
    # Header对中文进行转码
    msg['From'] = formatAddr('管理员 <%s>' % from_mail).encode()
    msg['To'] = ','.join(to_mail)
    msg['Subject'] = Header('监控', 'utf-8').encode()
    msg.attach(MIMEText(body, 'html', 'utf-8'))

    try:
        s = smtplib.SMTP()     
        s.connect(smtp_server, "25")   
        s.login(from_mail, mail_pass)
        s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText对象变成str     
        s.quit()
    except smtplib.SMTPException as e:
        print "Error: %s" % e
if __name__ == "__main__":
    body = """
    <h1>测试邮件</h1>
    <h2 style="color:red">This is a test</h1>
    """
    sendMail(body)
14.4 Python发送图片邮件
#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import parseaddr, formataddr

# 格式化邮件地址
def formatAddr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

def sendMail(body, image):
    smtp_server = 'smtp.163.com'
    from_mail = 'baojingtongzhi@163.com'
    mail_pass = 'xxx'
    to_mail = ['962510244@qq.com', 'zhenliang369@163.com']

    # 构造一个MIMEMultipart对象代表邮件本身
    msg = MIMEMultipart() 
    # Header对中文进行转码
    msg['From'] = formatAddr('管理员 <%s>' % from_mail).encode()
    msg['To'] = ','.join(to_mail)
    msg['Subject'] = Header('监控', 'utf-8').encode()
    msg.attach(MIMEText(body, 'html', 'utf-8'))

    # 二进制模式读取图片
    with open(image, 'rb') as f:
        msgImage = MIMEImage(f.read())

    # 定义图片ID
    msgImage.add_header('Content-ID', '<image1>')
    msg.attach(msgImage)

    try:
        s = smtplib.SMTP()     
        s.connect(smtp_server, "25")   
        s.login(from_mail, mail_pass)
        s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText对象变成str     
        s.quit()
    except smtplib.SMTPException as e:
        print "Error: %s" % e
if __name__ == "__main__":
    body = """
    <h1>测试图片</h1>
    <img src="cid:image1"/>    # 引用图片
    """
    sendMail(body, 'test.png')
上面发邮件的几种常见的发邮件方法基本满足日常需求了。
目录
相关文章
|
4月前
|
存储 搜索推荐 数据安全/隐私保护
python实战讲解之使用Python批量发送个性化邮件
python实战讲解之使用Python批量发送个性化邮件
|
18天前
|
运维 Shell Linux
第十四章 Python发送邮件(常见四种邮件内容)
第十四章 Python发送邮件(常见四种邮件内容)
|
13天前
|
Linux API Python
【python】如何通过python来发邮件,各种发邮件方式详细解析
【python】如何通过python来发邮件,各种发邮件方式详细解析
|
5月前
|
Python
【代码】利用Python每天自动发新闻到邮箱
【代码】利用Python每天自动发新闻到邮箱
26 0
|
Python
编程 | 详解使用Python接收邮件
编程 | 详解使用Python接收邮件
1248 2
|
数据安全/隐私保护 Python
python小玩意——自动发送邮件
python小玩意——自动发送邮件
|
网络安全 数据安全/隐私保护 Python
开心档-软件开发入门之Python SMTP发送邮件
本文主要讲解SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。
|
网络协议 Python
进阶——python——邮件的发送与收取(发送邮件)
进阶——python——邮件的发送与收取(发送邮件)
进阶——python——邮件的发送与收取(发送邮件)
|
Linux Shell 数据安全/隐私保护
python接口自动化(三十二)--Python发送邮件(常见四种邮件内容)番外篇——上(详解)
本篇文章与前边没有多大关联,就是对前边有关发邮件的总结和梳理。在写脚本时,放到后台运行,想知道执行情况,会通过邮件、SMS(短信)、飞信、微信等方式通知管理员,用的最多的是邮件。在linux下,Shell脚本发送邮件告警是件很简单的事,有现成的邮件服务软件或者调用运营商邮箱服务器
141 0
python接口自动化(三十二)--Python发送邮件(常见四种邮件内容)番外篇——上(详解)
|
API 数据安全/隐私保护 Python
如何用Python发送邮件?
相信邮箱对许多人来说只是一个全是推销邮件的垃圾桶,或者接收验证码的一个工具。但是邮箱其实还有很多作用,其中最重要的作用就是消息交流。
224 0