2.7 邮件提醒
邮件是互联网上应用非常广泛的服务,几乎所有的编程语言都支持发送和接收电子邮件,使用Python发送邮件和接收邮件也是非常简单易学的。现在几乎每个人的手机上都自带邮件客户端,多数邮箱都支持短信提醒,因此,在运维场景中将程序报错的信息发送到相应人员的邮箱可以及时感知程序的报错,尽早处理从而避免更多的损失。当然,使用程序发送邮件还有许多应用场景,如网站的密码重置等,在此不再一一列举。
2.7.1 发送邮件
关于如何写代码发送邮件,我们应首先想到发送邮件使用什么协议。目前发送邮件的协议是SMTP(Simple Mail Transfer Protocol,简单邮件传输协议),是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。我们编写代码,实际上就是将待发送的消息使用SMTP协议的格式进行封装,再提交SMTP服务器进行发送的过程。
Python内置的smtplib提供了一种很方便的途径发送电子邮件,可以发送纯文本邮件、HTML邮件及带附件的邮件。Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。
我们来看一下如何创建SMTP对象。Python创建SMTP对象语法如下:
import smtplib smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )
参数说明:
host:SMTP服务器主机,可以指定主机的IP地址或域名,是可选参数。
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协议中定义的格式。
【示例2-29】构造简单的文本邮件。
from email.mime.text import MIMEText message = MIMEText('Python 邮件发送测试...', 'plain', 'utf-8')
注意构造MIMEText对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入plain,最终的MIME就是'text/plain',最后一定要用UTF-8编码保证多语言兼容性。
在使用SMTP发送邮件之前,请确保所用邮箱的SMTP服务已开启,例如163邮箱,如图2.23所示。
图2.23 SMTP设置方法
【示例2-30】下面使用Python发送第一封简单的邮件(sendmail1.py)。
执行以上程序,屏幕上显示“发送成功”的信息后,即可看到收件箱里的邮件,如图2.24所示。
图2.24 运行结果
读者可能会问,可以发送HTML格式的邮件吗?当然可以,构造正文部分修改如下:
message = MIMEText( '<html><body><h1>这是正文标题</h1>\ <p>正文内容 <a href="#">超链接</a>...</p>\ </body></html>', "html", "utf-8", ) # 构造正文
执行后邮件内容如图2.25所示。
图2.25 运行结果
到这里读者可能会问,如何添加附件呢?请看下面的代码:
执行以上代码后,验证邮箱如图2.26所示。
图2.26 运行结果
2.7.2 接收邮件
接收邮件的协议有POP3(Post Office Protocol)和IMAP(Internet Message Access Protocol),Python内置poplib模块实现了POP3协议,可以直接用来接收邮件。
与SMTP协议类似,POP3协议收取的不是一个已经可以阅读的邮件本身,而是邮件的原始文本,要把POP3收取的文本变成可以阅读的邮件,还需要用email模块提供的各种类来解析原始文本,变成可阅读的邮件对象。收取邮件分以下两步。
第一步:用poplib模块把邮件的原始文本下载到本地。
第二步:用email模块解析原始文本,还原为邮件对象。
【示例2-31】编写get_mail.py来演示如何使用poplib模块接收邮件。代码如下:
在代码的第64行,我们使用part0.get_content_charset()编码来解码邮件正文。执行上面的代码得到如下结果。
对应的邮件截图如图2.27所示。
图2.27 运行结果
2.7.3 将报警信息实时发送至邮箱
在日常运维中经常用到监控,其常用的是短信报警、邮件报警等。相比短信报警,邮件报警是一个非常低成本的解决方法,无须付给运营商短信费用,一条短信有字数限制,而邮件无此限制,因此邮件报警可以看到更多警告信息。
下面使用Python发送邮件的功能来实现报警信息实时发送至邮箱,具体需求说明如下。
(1)文本文件txt约定格式:第一行为收件人列表,以逗号分隔;第二行为主题,第三行至最后一行为正文内容,最后一行如果是文件,则作为附件发送,支持多个附件,以逗号分隔。
下面是一个完整的例子。
xxx@163.com,yyy@163.com xxx程序报警 报警信息….. ….. …… /home/log/xxx.log,/tmp/yyy.log
(2)持续监控一个目录A下的txt文件,如果有新增或修改,则读取文本中的内容并发送邮件。
(3)有报警需求的程序可生成(1)中格式的文本文件并传送至目录A即可。任意程序基本都可以实现本步骤。
现在我们就使用Python来实现上述需求,涉及的Python知识点有:文件编码、读文件操作、watchdog模块应用及发送邮件。
【示例2-32】首先编写一个发送邮件的类,其功能是解析文本文件内容并发送邮件。
文件txt2mail.py内容如下:
上述代码实现了自定义的邮件类,功能是解析指定格式的文本文件并发送邮件,支持多个附件上传。
接下来我们实现监控目录的功能,使用前面学习的watchdog模块。
文件watchDir.py内容如下:
watchdir使用watchdog模块监控指定目录是否有后缀为txt的文本文件,如果有新增或修改的文本文件,则调用txt2mail中的txtmail类的txt_send_mail方法;如果发送不成功则表明文本文件格式错误,捕捉异常是为了避免程序崩溃退出。下面我们运行测试一下。
执行python watchdir.py后的结果如图2.28所示。
图2.28 运行结果
在./目录下创建一个test.txt文件,文件内容如图2.29所示。
保存后看到运行结果如图2.30所示。
图2.29 运行结果
图2.30 运行结果
登录邮件可看到如图2.31所示的收件信息。
图2.31 实时邮件发送
以上基本满足我们的日常监控需求,实际的生产环境中大家完全可以依据具体需求具体分析,这个例子也许不是最好的解决方案,但希望能起到抛砖引玉的作用。