Python3.x 发送各种形式的告警邮件内容

DevOps技术栈

共 7545字,需浏览 16分钟

 ·

2020-09-16 04:19

在写脚本时,放到后台运行,想知道执行情况,会通过邮件、短信、微信等方式通知管理员,邮件目前用的最多的通知方式。在linux下,Shell脚本发送邮件告警是件很简单的事,有现成的邮件服务软件或者调用运营商邮箱服务器,对于Python来说,需要编写脚本调用邮件服务器来发送邮件。

Python分别提供了收发邮件的库,smtplib、poplib和imaplib。

本文主要学习如何使用smtplib库发送各种形式的邮件内容。该库主要用smtplib.SMTP()类,使用这个类封装一个SMTP连接,语法如下:

smtplib.SMTP(host ='',port = 0,local_hostname = None,[ timeout,] source_address = None )

SMTP实例后有以下常用方法:

方法

描述

SMTP.connect([host[,  port]])

连接到指定的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服务器连接

为更好学习smtplib模块,我们下面写几个具体的示例来熟悉它的用法。

示例1:发送文本邮件

先通过本地SMTP服务器发送邮件。

本地SMTP服务器,可以通过安装sendmail、postfix等服务提供。

例如安装sendmail:

yum install sendmail –ysystemctl start sendmail

smtp默认25端口,查看是否监听:

ss -anpt|grep 25

sendmail服务运行,就可以使用了:

from smtplib import SMTPs = SMTP("localhost")to_mail = ["baojingtongzhi@163.com"] #收件人列表,可以写多个# 内容必须靠左,否则邮件头不识别msg = '''\ From: aliang@ctnrs.comSubject: test这是一份测试邮件'''.encode("utf8")   s.sendmail("aliang@ctnrs.com",to_mail,msg)s.quit()

msg对象里From表示发件人,Subject是邮件标题,换行后输入的是邮件内容。



上面示例使用本地SMTP服务器发送的邮件,这种自建的SMTP服务器容易被当做垃圾邮件,甚至大部分公有云也不允许自建(禁止25端口),所以一般情况下都采用个人邮箱或者企业邮箱发邮件。

例如,使用163邮箱发邮件:

from smtplib import SMTP    email_account = "baojingtongzhi@163.com"account_password = "VCGXTBHXFPVDVLGZ"  #授权密码s = SMTP("smtp.163.com")s.login(email_account, account_password)to_mail = ["1121267855@qq.com"]msg = f'''\ From: {email_account}Subject: 测试这是一封测试邮件'''.encode("utf8")s.sendmail("baojingtongzhi@163.com",to_mail,msg)s.quit()

现在一般个人邮箱需要授权码才可以在客户端收发邮件,设置-> POP3/SMTP/IMAP->授权密码:


运行结果:

smtplib.SMTPDataError: (554, b'DT:SPM 163 smtp12,EMCowAC312M29l5fNpBQAw--.41693S2 1600058934,please see http://mail.163.com/help/help_spam_16.htm?ip=27.189.225.231&hostid=smtp12&time=1600058934')
访问给出的163网址,SMTP554错误是:"554 DT:SUM 信封发件人和信头发件人不匹配"

在上面第一个示例中你会发现收件人是空的,看这样163的SMTP服务器拒绝的原因应该就是这里收件人没指定。

重新修改下msg对象,添加收件人:

msg = f'''\ From: {email_account}To: {','.join(to_mail)} Subject:测试这是一封测试邮件'''.encode("utf8")
  • ','.join(to_mail)转成字符串,以逗号分隔元素。

  • 如果msg对象含带中文需要编码encode("utf8")



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

示例2:发送邮件并抄送

import smtplibdef sendMail(body):    smtp_server = 'smtp.163.com'    email_account = 'baojingtongzhi@163.com'    account_password = 'VCGXTBHXFPVDVLGZ'    to_mail = ["1121267855@qq.com"]    cc_mail = ["xxx@163.com"]    from_name = 'monitor'    subject = '监控'    """    msg = '''\From: {email_account}To: {','.join(to_mail)}Subject: 测试'''    """    # 或者写成列表再拼接,相比上面顶头写更美化些    mail = [        "From: %s <%s>" % (from_name, account_password),        "To: %s" % ','.join(to_mail),        "Subject: %s" % subject,        "Cc: %s" % ','.join(cc_mail),        "",        body        ]    msg = '\n'.join(mail).encode("utf8")
try: s = smtplib.SMTP() s.connect(smtp_server, '25') s.login(email_account, account_password) s.sendmail(email_account, to_mail+cc_mail, msg) s.quit() except smtplib.SMTPException as e: print("Error: %s" %e)if __name__ == "__main__":    sendMail("这是一封测试邮件")



s.sendmail(from_mail,to_mail+cc_mail, msg) 这里看到,收件人和抄送人为什么放一起发送呢?

其实无论是收件人还是抄送人,它们收到的邮件都是一样的,SMTP服务器也是认为发件人这样一封一封的发出。所以实际上并没有抄送这个概念,只是在邮件头加了抄送人的信息罢了!

示例3:发送邮件带附件

由于SMTP.sendmail()方法不支持添加附件,所以需要借助email模块来实现。email模块是一个构造邮件和解析邮件的模块。

import smtplibfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom email import encodersfrom email.mime.base import MIMEBasefrom 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' email_account = 'baojingtongzhi@163.com' account_password = 'VCGXTBHXFPVDVLGZ' to_mail = ["1121267855@qq.com"]
# 构造一个MIMEMultipart对象代表邮件本身 msg = MIMEMultipart() # Header对中文进行转码 msg['From'] = formatAddr('管理员 <%s>' % email_account) msg['To'] = ','.join(to_mail) msg['Subject'] = Header('监控', 'utf-8')
# plain代表纯文本 msg.attach(MIMEText(body, 'plain', 'utf-8'))
# 二进制方式模式文件 with open(attachment, 'rb') as f: # MIMEBase表示附件的对象 mime = MIMEBase('text', 'txt', filename=attachment) # 使用MIMEBase类构造附件并添加到msg对象 # 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(email_account, account_password) s.sendmail(email_account, 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')



示例4:发送HTML邮件

import smtplibfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom 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' email_account = 'baojingtongzhi@163.com' account_password = 'VCGXTBHXFPVDVLGZ' to_mail = ["1121267855@qq.com"]
# 构造一个MIMEMultipart对象代表邮件本身 msg = MIMEMultipart() # Header对中文进行转码 msg['From'] = formatAddr('管理员 <%s>' % email_account) msg['To'] = ','.join(to_mail) msg['Subject'] = Header('监控', 'utf-8') msg.attach(MIMEText(body, 'html', 'utf-8'))
try: s = smtplib.SMTP() s.connect(smtp_server, "25") s.login(email_account, account_password) s.sendmail(email_account, to_mail, msg.as_string()) # as_string()把MIMEText对象变成str s.quit() except smtplib.SMTPException as e: print("Error: %s" % e)if __name__ == "__main__": body = """

测试邮件

这是一封HTML测试邮件

"""    sendMail(body)


示例5:发送图片邮件

import smtplibfrom email.mime.text import MIMETextfrom email.mime.image import MIMEImagefrom email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom 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' email_account = 'baojingtongzhi@163.com' account_password = 'VCGXTBHXFPVDVLGZ' to_mail = ["1121267855@qq.com"]
# 构造一个MIMEMultipart对象代表邮件本身 msg = MIMEMultipart() # Header对中文进行转码 msg['From'] = formatAddr('管理员 <%s>' % email_account) msg['To'] = ','.join(to_mail) msg['Subject'] = Header('监控', 'utf-8') msg.attach(MIMEText(body, 'html', 'utf-8'))
# 二进制模式读取图片 with open(image, 'rb') as f: msgImage = MIMEImage(f.read()) # 使用MIMEImage类构造图片并添加到msg对象 # 定义图片ID,根据ID在HTML里获取图片 msgImage.add_header('Content-ID', '') msg.attach(msgImage)
try: s = smtplib.SMTP() s.connect(smtp_server, "25") s.login(email_account, account_password) s.sendmail(email_account, to_mail, msg.as_string()) # as_string()把MIMEText对象变成str s.quit() except smtplib.SMTPException as e: print("Error: %s" % e)if __name__ == "__main__": body = """

测试图片

"""    sendMail(body, "123.jpg")



动手试试吧~ 代码复制粘贴就行。


- END -

 推荐阅读 
Python 自动创建 Grafana 仪表板
Python 调用 Kubernetes API 自动化管理资源
支付宝架构师眼中的高并发架构
SpringCloud微服务项目运维必知必会
Java 应用最常见的3个问题排查思路
一篇漫画带你了解 Linux 内核长啥样!



点亮,服务器三年不宕机

浏览 20
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报