简介
本篇文章与前边没有多大关联,就是对前边有关发邮件的总结和梳理。在写脚本时,放到后台运行,想知道执行情况,会通过邮件、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服务器连接 |
看下官方给的示例:
我们根据示例给自己发一个邮件测试下:
我这里测试使用本地的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是邮件标题,换行后输入的是邮件内容。
1.1 Python发送邮件并抄送
#!/usr/bin/python # -*- coding: utf-8 -*- import smtplib def sendMail(body): smtp_server = 'smtp.163.com' from_mail = 'hongge@163.com' mail_pass = 'xxx' to_mail = ['xxx@qq.com', 'xxx@163.com'] cc_mail = ['hongge@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的信息去掉即可。
另外以上代码发送的邮件会出现主题中文乱码:
解决方案:三行代码即可,修改成红色框代码即可
1.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('邮件内容')
基本的格式就是这样的!
继续回到主题,发送邮件带附件:
# coding=utf-8 #1.先设置编码,utf-8可支持中英文,如上,一般放在第一行 #2.注释:包括记录创建时间,创建人,项目名称。 ''' Created on 2019-5-9 @author: 北京-宏哥 Project:学习和使用邮箱发带有附件邮件 ''' #3.导入模块 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 def send_mail(file_new): #-----------1.跟发件相关的参数------ smtpserver = 'smtp.mxhichina.com' #发件服务器 port = 0 #端口 username = 'noreply@cxx.cn' #发件箱用户名 password = 'xx@@123' #发件箱密码 sender = 'noreply@cxx.cn' #发件人邮箱 receiver = ['hongge@cedex.cn','1918991791@qq.com'] #收件人邮箱 # ----------2.编辑邮件的内容------ #读文件内容 f = open(file_new, 'rb') mail_body = f.read() f.close() # 邮件正文是MIMEText body = MIMEText(mail_body, 'html', 'utf-8') # 邮件对象 msg = MIMEMultipart() msg['Subject'] = Header("自动化测试报告", 'utf-8').encode()#主题 msg['From'] = Header(u'测试机 <%s>'%sender) #发件人 msg['To'] = Header(u'测试负责人 <%s>'%receiver) #收件人 msg['To'] = ';'.join(receiver) msg.attach(body) # # MIMEBase表示附件的对象 att = MIMEText(mail_body, "base64", "utf-8") att["Content-Type"] = "application/octet-stream" # filename是显示附件名字 att["Content-Disposition"] = 'attachment; filename="test_report.html"' msg.attach(att) # ----------3.发送邮件------ try: smtp = smtplib.SMTP() smtp.connect(smtpserver) # 连服务器 smtp.login(sender, password) except: smtp = smtplib.SMTP_SSL(smtpserver, port) smtp.login(sender, password) # 登录 smtp.sendmail(sender, receiver, msg.as_string()) # 发送 smtp.quit() if __name__ == "__main__": #本地文件的路径 att_path= r'E:\pythontest\text.txt' send_mail(att_path)
1.3 Python发送HTML邮件
# coding=utf-8 #1.先设置编码,utf-8可支持中英文,如上,一般放在第一行 #2.注释:包括记录创建时间,创建人,项目名称。 ''' Created on 2019-5-9 @author: 北京-宏哥 Project:学习和使用邮箱发HTML邮件 ''' #3.导入模块 #"-*- coding: utf-8 -*-" import smtplib from email.mime.text import MIMEText mail_user="XXX@163.com" mail_password="******q1125" mailto_list=["1918991791<1918991791@qq.com>","2014816656@qq.com"] mail_host="smtp.163.com" mail_postfix="163.com" def sendmail(to_list,sub,content): me="北京-宏哥"+"<"+mail_user+"@"+mail_postfix+">" msg=MIMEText("<a href='https://www.cnblogs.com/du-hong'><font color='red'>北京-宏哥</font></a>","html","utf-8") msg['Subject']=sub msg['From']=me msg['To']=",".join(to_list) try: server=smtplib.SMTP() server.connect(mail_host) server.login(mail_user,mail_password) server.sendmail(me,to_list,msg.as_string()) server.close() return True except Exception as e: print (str(e)) return False if sendmail(mailto_list,"标题:发送的是html格式","<a href='https://www.cnblogs.com/du-hong'>北京-宏哥</a>"): print ("done!") else: print ("falsed!")
1.4 Python发送图片邮件
# coding=utf-8 #1.先设置编码,utf-8可支持中英文,如上,一般放在第一行 #2.注释:包括记录创建时间,创建人,项目名称。 ''' Created on 2019-5-9 @author: 北京-宏哥 Project:学习和使用1邮箱发HTML邮件 ''' #3.导入模块 #"-*- coding: utf-8 -*-" import smtplib from email.mime.text import MIMEText mail_user="@@@@@163.com" mail_password="@@@@" mailto_list=["1918991791<1918991791@qq.com>","2014816656@qq.com"] mail_host="smtp.163.com" mail_postfix="163.com" def sendmail(to_list,sub,content): me="北京-宏哥"+"<"+mail_user+"@"+mail_postfix+">" msg=MIMEText('<html><body><img hidefocus="true" class="index-logo-src" src="//www.baidu.com/img/bd_logo1.png" width="270" height="129" usemap="#mp"></body></html>', 'html', 'utf-8') msg['Subject']=sub msg['From']=me msg['To']=",".join(to_list) try: server=smtplib.SMTP() server.connect(mail_host) server.login(mail_user,mail_password) server.sendmail(me,to_list,msg.as_string()) server.close() return True except Exception as e: print (str(e)) return False if sendmail(mailto_list,"标题:发送的是HTML格式","<a href='https://www.cnblogs.com/du-hong'>北京-宏哥</a>"): print ("done!") else: print ("falsed!")
上面发邮件的几种常见的发邮件方法基本满足日常需求了。
小结
1、linux环境下提示AttributeError: module 'smtplib' has no attribute 'SMTP',Windows环境运行代码也报如下错误:
2、原因当然不是模块的问题,检查了一下拼写也没有出问题,最后在这个帖子(链接)的启发下发现,发现自己的文件命名为email.py,和模块中的函数有冲突,改名之后Linux环境邮件正常发送。