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

转载 2017年03月03日 17:17:04
 

转自:http://lizhenliang.blog.51cto.com/7876557/1875330

在写脚本时,放到后台运行,想知道执行情况,会通过邮件、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服务器连接

看下官方给的示例:

  1. >>> import smtplib
  2. >>> s=smtplib.SMTP("localhost")
  3. >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
  4. >>> msg = '''''\
  5. ... From: Me@my.org
  6. ... Subject: testin'...
  7. ...
  8. ... This is a test '''
  9. >>> s.sendmail("me@my.org",tolist,msg)
  10. { "three@three.org" : ( 550 ,"User unknown" ) }
  11. >>> s.quit()

我们根据示例给自己发一个邮件测试下:

我这里测试使用本地的SMTP服务器,也就是要装一个支持SMTP协议的服务,比如sendmail、postfix等。

CentOS安装sendmail:yum install sendmail

  1. >>> import smtplib
  2. >>> s = smtplib.SMTP("localhost")
  3. >>> tolist = ["xxx@qq.com", "xxx@163.com"]
  4. >>> msg = '''''\
  5. ... From: Me@my.org
  6. ... Subject: test
  7. ... This is a test '''
  8. >>> s.sendmail("me@my.org", tolist, msg)
  9. {}

进入腾讯和网易收件人邮箱,就能看到刚发的测试邮件,一般都被邮箱服务器过滤成垃圾邮件,所以收件箱没有,你要去垃圾箱看看。

可以看到,多个收件人可以放到一个列表中进行群发。msg对象里From表示发件人,Subject是邮件标题,换行后输入的是邮件内容。

上面是使用本地SMTP服务器发送的邮件,测试下用163服务器发送邮件看看效果:

  1. >>> import smtplib
  2. >>> s = smtplib.SMTP("smtp.163.com")
  3. >>> s.login("baojingtongzhi@163.com", "xxx")
  4. (235, 'Authentication successful')
  5. >>> tolist = ["xxx@qq.com", "xxx@163.com"]
  6. >>> msg = '''''\
  7. ... From: baojingtongzhi@163.com
  8. ... Subject: test
  9. ... This is a test '''
  10. >>> s.sendmail("baojingtongzhi@163.com", tolist, msg)
  11. Traceback (most recent call last):
  12. File "<stdin>", line 1, in <module>
  13. File "/usr/lib64/python2.6/smtplib.py", line 725, in sendmail
  14. raise SMTPDataError(code, resp)
  15. 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对象,添加上收件人:

  1. >>> msg = '''''\
  2. ... From: baojingtongzhi@163.com
  3. ... To: 962510244@qq.com ,zhenliang369@163.com
  4. ... Subject: test
  5. ...
  6. ... This is a test '''
  7. >>> s.sendmail("baojingtongzhi@163.com", tolist, msg)
  8. {}

好了,可以正常发送邮件了。msg这个格式是SMTP规定的,一定要遵守。

1、Python发送邮件并抄送

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import smtplib
  4. def sendMail(body):
  5. smtp_server = 'smtp.163.com'
  6. from_mail = 'baojingtongzhi@163.com'
  7. mail_pass = 'xxx'
  8. to_mail = ['962510244@qq.com', 'zhenliang369@163.com']
  9. cc_mail = ['lizhenliang@xxx.com']
  10. from_name = 'monitor'
  11. subject = u'监控'.encode('gbk')   # 以gbk编码发送,一般邮件客户端都能识别
  12. #     msg = '''\
  13. # From: %s <%s>
  14. # To: %s
  15. # Subject: %s
  16. # %s''' %(from_name, from_mail, to_mail_str, subject, body)  # 这种方式必须将邮件头信息靠左,也就是每行开头不能用空格,否则报SMTP 554
  17. mail = [
  18. "From: %s <%s>" % (from_name, from_mail),
  19. "To: %s" % ','.join(to_mail),   # 转成字符串,以逗号分隔元素
  20. "Subject: %s" % subject,
  21. "Cc: %s" % ','.join(cc_mail),
  22. "",
  23. body
  24. ]
  25. msg = '\n'.join(mail)  # 这种方式先将头信息放到列表中,然后用join拼接,并以换行符分隔元素,结果就是和上面注释一样了
  26. try:
  27. s = smtplib.SMTP()
  28. s.connect(smtp_server, '25')
  29. s.login(from_mail, mail_pass)
  30. s.sendmail(from_mail, to_mail+cc_mail, msg)
  31. s.quit()
  32. except smtplib.SMTPException as e:
  33. print "Error: %s" %e
  34. if __name__ == "__main__":
  35. sendMail("This is a test!")

s.sendmail(from_mail,
to_mail+cc_mail, msg)
在这里注意下,收件人和抄送人为什么放一起发送呢?其实无论是收件人还是抄送人,它们收到的邮件都是一样的,SMTP都是认为收件人这样一封一封的发出。所以实际上并没有抄送这个概念,只是在邮件头加了抄送人的信息罢了!另外,如果不需要抄送人,直接把上面cc的信息去掉即可。

2 Python发送邮件带附件

由于SMTP.sendmail()方法不支持添加附件,所以可以使用email模块来满足需求。email模块是一个构造邮件和解析邮件的模块。

先看下如何用email库构造一个简单的邮件:

  1. message = Message()
  2. message['Subject'] = '邮件主题'
  3. message['From'] = from_mail
  4. message['To'] = to_mail
  5. message['Cc'] = cc_mail
  6. message.set_payload('邮件内容')

基本的格式就是这样的!

继续回到主题,发送邮件带附件:

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import smtplib
  4. from email.mime.text import MIMEText
  5. from email.mime.multipart import MIMEMultipart
  6. from email.header import Header
  7. from email import encoders
  8. from email.mime.base import MIMEBase
  9. from email.utils import parseaddr, formataddr
  10. # 格式化邮件地址
  11. def formatAddr(s):
  12. name, addr = parseaddr(s)
  13. return formataddr((Header(name, 'utf-8').encode(), addr))
  14. def sendMail(body, attachment):
  15. smtp_server = 'smtp.163.com'
  16. from_mail = 'baojingtongzhi@163.com'
  17. mail_pass = 'xxx'
  18. to_mail = ['962510244@qq.com', 'zhenliang369@163.com']
  19. # 构造一个MIMEMultipart对象代表邮件本身
  20. msg = MIMEMultipart()
  21. # Header对中文进行转码
  22. msg['From'] = formatAddr('管理员 <%s>' % from_mail).encode()
  23. msg['To'] = ','.join(to_mail)
  24. msg['Subject'] = Header('监控', 'utf-8').encode()
  25. # plain代表纯文本
  26. msg.attach(MIMEText(body, 'plain', 'utf-8'))
  27. # 二进制方式模式文件
  28. with open(attachment, 'rb') as f:
  29. # MIMEBase表示附件的对象
  30. mime = MIMEBase('text', 'txt', filename=attachment)
  31. # filename是显示附件名字
  32. mime.add_header('Content-Disposition', 'attachment', filename=attachment)
  33. # 获取附件内容
  34. mime.set_payload(f.read())
  35. encoders.encode_base64(mime)
  36. # 作为附件添加到邮件
  37. msg.attach(mime)
  38. try:
  39. s = smtplib.SMTP()
  40. s.connect(smtp_server, "25")
  41. s.login(from_mail, mail_pass)
  42. s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText对象变成str
  43. s.quit()
  44. except smtplib.SMTPException as e:
  45. print "Error: %s" % e
  46. if __name__ == "__main__":
  47. sendMail('附件是测试数据, 请查收!', 'test.txt')


3 Python发送HTML邮件

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import smtplib
  4. from email.mime.text import MIMEText
  5. from email.mime.multipart import MIMEMultipart
  6. from email.header import Header
  7. from email.utils import parseaddr, formataddr
  8. # 格式化邮件地址
  9. def formatAddr(s):
  10. name, addr = parseaddr(s)
  11. return formataddr((Header(name, 'utf-8').encode(), addr))
  12. def sendMail(body):
  13. smtp_server = 'smtp.163.com'
  14. from_mail = 'baojingtongzhi@163.com'
  15. mail_pass = 'xxx'
  16. to_mail = ['962510244@qq.com', 'zhenliang369@163.com']
  17. # 构造一个MIMEMultipart对象代表邮件本身
  18. msg = MIMEMultipart()
  19. # Header对中文进行转码
  20. msg['From'] = formatAddr('管理员 <%s>' % from_mail).encode()
  21. msg['To'] = ','.join(to_mail)
  22. msg['Subject'] = Header('监控', 'utf-8').encode()
  23. msg.attach(MIMEText(body, 'html', 'utf-8'))
  24. try:
  25. s = smtplib.SMTP()
  26. s.connect(smtp_server, "25")
  27. s.login(from_mail, mail_pass)
  28. s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText对象变成str
  29. s.quit()
  30. except smtplib.SMTPException as e:
  31. print "Error: %s" % e
  32. if __name__ == "__main__":
  33. body = """
  34. <h1>测试邮件</h1>
  35. <h2 style="color:red">This is a test</h1>
  36. """
  37. sendMail(body)


4 Python发送图片邮件

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import smtplib
  4. from email.mime.text import MIMEText
  5. from email.mime.image import MIMEImage
  6. from email.mime.multipart import MIMEMultipart
  7. from email.header import Header
  8. from email.utils import parseaddr, formataddr
  9. # 格式化邮件地址
  10. def formatAddr(s):
  11. name, addr = parseaddr(s)
  12. return formataddr((Header(name, 'utf-8').encode(), addr))
  13. def sendMail(body, image):
  14. smtp_server = 'smtp.163.com'
  15. from_mail = 'baojingtongzhi@163.com'
  16. mail_pass = 'xxx'
  17. to_mail = ['962510244@qq.com', 'zhenliang369@163.com']
  18. # 构造一个MIMEMultipart对象代表邮件本身
  19. msg = MIMEMultipart()
  20. # Header对中文进行转码
  21. msg['From'] = formatAddr('管理员 <%s>' % from_mail).encode()
  22. msg['To'] = ','.join(to_mail)
  23. msg['Subject'] = Header('监控', 'utf-8').encode()
  24. msg.attach(MIMEText(body, 'html', 'utf-8'))
  25. # 二进制模式读取图片
  26. with open(image, 'rb') as f:
  27. msgImage = MIMEImage(f.read())
  28. # 定义图片ID
  29. msgImage.add_header('Content-ID', '<image1>')
  30. msg.attach(msgImage)
  31. try:
  32. s = smtplib.SMTP()
  33. s.connect(smtp_server, "25")
  34. s.login(from_mail, mail_pass)
  35. s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText对象变成str
  36. s.quit()
  37. except smtplib.SMTPException as e:
  38. print "Error: %s" % e
  39. if __name__ == "__main__":
  40. body = """
  41. <h1>测试图片</h1>
  42. <img src="cid:image1"/>    # 引用图片
  43. """
  44. sendMail(body, 'test.png')


上面发邮件的几种常见的发邮件方法基本满足日常需求了。

Python发送邮件(常见四种邮件内容)的更多相关文章

  1. 【转】【Python】Python发送邮件(常见四种邮件内容)

    在写脚本时,放到后台运行,想知道执行情况,会通过邮件.SMS(短信).飞信.微信等方式通知管理员,用的最多的是邮件.在linux下,Shell脚本发送邮件告警是件很简单的事,有现成的邮件服务软件或者调 ...

  2. python接口自动化(三十二)--Python发送邮件(常见四种邮件内容)番外篇——上(详解)

    简介 本篇文章与前边没有多大关联,就是对前边有关发邮件的总结和梳理.在写脚本时,放到后台运行,想知道执行情况,会通过邮件.SMS(短信).飞信.微信等方式通知管理员,用的最多的是邮件.在linux下, ...

  3. 最全总结!聊聊 Python 发送邮件的几种方式

    1. 前言 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的知识.那么针对这三类人,我给大 ...

  4. Python自动化测试发送邮件太麻烦?!一起聊一聊 Python 发送邮件的3种方式

    1. 前言 发送邮件,我们在平时工作中经用到,做为测试人员,在自动化测试中用的也比较多,需要发送邮件给某领导 SMTP是Python默认的邮件模块,可以发送纯文本.富文本.HTML 等格式的邮件 今天 ...

  5. Python实现接口测试中的常见四种Post请求数据

    前情: 在日常的接口测试工作中,模拟接口请求通常有两种方法, 利用工具来模拟,比如fiddler,postman,poster,soapUI等 利用代码来模拟,使用到一些网络模块,比如HttpClie ...

  6. Python请求外部POST请求,常见四种请求体

    原文http://blog.csdn.net/silencemylove/article/details/50462206 HTTP 协议规定 POST 提交的数据必须放在消息主体(entity-bo ...

  7. Mysql常见四种索引的使用

    提到MySQL优化,索引优化是必不可少的.其中一种优化方式 --索引优化,添加合适的索引能够让项目的并发能力和抗压能力得到明显的提升. 我们知道项目性能的瓶颈主要是在"查(select)&q ...

  8. python函数的四种参数传递方式

    python中函数传递参数有四种形式 fun1(a,b,c) fun2(a=1,b=2,c=3) fun3(*args) fun4(**kargs) 四种中最常见是前两种,基本上一般点的教程都会涉及, ...

  9. Python单例模式的四种方法

    在这之前,先了解super()和__new__()方法 super()方法: 返回一个父类或兄弟类类型的代理对象,让你能够调用一些从继承过来的方法. 它有两个典型作用: a. 在单继承的类层次结构中, ...

随机推荐

  1. 数据库 三范式 BCFN

    # 三范式 范式  设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小.  目前关系数据库有六种范式:第一 ...

  2. Eureka 源码分析之 Eureka Server

    文章首发于公众号<程序员果果> 地址 : https://mp.weixin.qq.com/s/FfJrAGQuHyVrsedtbr0Ihw 简介 上一篇文章<Eureka 源码分析 ...

  3. catch that cow POJ 3278 搜索

    catch that cow POJ 3278 搜索 题意 原题链接 john想要抓到那只牛,John和牛的位置在数轴上表示为n和k,john有三种移动方式:1. 向前移动一个单位,2. 向后移动一个 ...

  4. [BZOJ5306] [HAOI2018]染色(容斥原理+NTT)

    [BZOJ5306] [HAOI2018]染色(容斥原理+NTT) 题面 一个长度为 n的序列, 每个位置都可以被染成 m种颜色中的某一种. 如果n个位置中恰好出现了 S次的颜色有 K种, 则小 C ...

  5. 洛谷P3412 仓鼠找$Sugar\ II$题解(期望+统计论?)

    洛谷P3412 仓鼠找\(Sugar\ II\)题解(期望+统计论?) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1327573 原题链接:洛谷P3412 ...

  6. 6-3 如何解析简单的XML文档

    元素节点.元素树 >>> from xml.etree.ElementTree import parse >>> help(parse) Help on funct ...

  7. mysql支持的存储引擎

    1.InnoDB 存储引擎 支持事务,其设计目标主要面向联机事务处理(OLTP)的应用.其特点是行锁设计.支持外键,并支持类似 Oracle 的非锁定读,即默认读取操作不会产生锁. 从 MySQL 5 ...

  8. 在cmd下用cd怎么进不了其他的盘

    你当前就是在C盘目录下的,可以切换到别的盘比如D:,然后在切换E:!然后可以切换C:,然后可以用cd\回到根目录. cd是打开文件根目录里面文件夹的,比如C:目录下可以cd Windows打开Wind ...

  9. 对table最后一行显示与隐藏

    //显示table最后一行,如果用block的话,可能会影响到页面的样式 $("#table tr").get($("#table tr").length - ...

  10. 高并发-原子性-AtomicInteger

    线程不安全: //请求总次数private static int totalCount = 10000;//最大并发数private static int totalCurrency = 100;// ...