python--邮件告警

一、了解SMTP协议

  • 目前用于发送邮件的协议是SMTP(简单文本传输协议)

  • python内置的smtplib模块提供了便捷的邮件发送方法,可以发送纯文本邮件、HTML邮件及带附件的邮件。

  • Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件

  • python创建SMTP对象的语法如下

    import smtplib
    smtpobj = smtplib.SMTP([host [, port [, local_hostname] ] ])

    参数说明:

    • host :SMTP 服务器主机,可以指定主机的IP地址或域名,是可选参数
    • port :如果提供了host参数,就需要指定SMTP服务使用的端口号,一般情况下SMTP的端口号是 25
    • local_hostname :如果SMTP在你的本机上,那么只需要指定服务器地址为localhost即可。
  • pythonSMTP随想使用sendmail方法发送邮件,其语法如下:

    SMTP.sendmail(from_addr, to_addr, msg[, mail_options, rcpt_options] )

    参数说明:

    • from_addr :邮件发送者地址
    • to_addr :字符串列表,邮件发送地址
    • msg :发送消息(这个参数msg是字符串,表示邮件本身。发邮件时一定要注意格式,一般是由标题、发信人、收件人、邮件内容、附件等组成,因此发邮件时要注意msg的格式。这个格式需要是SMTP定义的格式)
    • 简单文本邮件模板

      from email.mime.text import MIMEText
      message = MIMEText(‘Python 邮件测试…’, ‘plain’, ‘utf-8’)
      ----------------------------------------------------------------------------------------------------------
      # 构造MIMEText对象时 ,第一个参数就是邮件正文,第二个参数是MIMEText的subtype,传入palin,最终MIMEText就是’text/plain’,最后一定要用’utf-8’编码,保证语言的兼容性

二、编写发送邮件代码

网易邮箱服务器发送邮件常见问题:http://help.163.com/09/1224/17/5RAJ4LMH00753VB8.html

1.文本格式邮件

邮件代码:

import smtplib
from email.mime.text import MIMEText

# 第三方SMTP服务
mail_host = "smtp.qq.com"             # 设置服务器(smtp.163.com是网易邮箱服务器,smtp.qq.com是QQ地址)
mail_user = "xxxxxxxx@qq.com"         # 用户名
mail_pass = "aydzptaydrdpched"        # 密码(注意,这里的密码指的是邮箱客户端授权码)


# 发送者邮箱
sender = "xxxxx@qq.com"

# 接收者邮箱
receivers = ['xxxx@163.com', 'xxxxx@qq.com']                 # 邮件接受者,可设置多个

# 构造正文
message = MIMEText('这是正文:python test。。。', 'plain', 'utf-8')       # 构造正文

# 构造发件人
message["From"] = sender                                                 # 发件人,这个必须构造,也可以使用Header来构造

# 收件人列表,这个不是必须的
message["To"] = ";".join(receivers)

# 定义邮件主题
message["Subject"] = "这是主题:SMTP 邮件测试"

try:
    smtpObj = smtplib.SMTP()                                            # 建立和SMTP邮件服务器的连接
    smtpObj.connect(mail_host, 25)                                      # 25 为端口号
    smtpObj.login(mail_user, mail_pass)
    smtpObj.sendmail(sender, receivers, message.as_string())
    print('send mail Successfully')
    smtpObj.quit()                                                       # 结束会话
except smtplib.SMTPException as e:
    print(f"发送失败,错误原因:{e}")

执行结果:

[root@localhost MSTP]# ./sendmail.py 
send mail Successfully

在这里插入图片描述

2.html正文格式邮件

  • 只需要将正文message部分进行修改即可
    例如:
message = MIMEText(
    '<html><body><h1>这是正文标题</h1>\
    <p>正文内容<a href="#">https://blog.csdn.net/CN_LiTianpeng?spm=1001.2014.3001.5343 #《超链接》</a>...</p>\
    </html></body>',
    "html",
    "utf-8"
)

3.添加附件发送邮件

  • 同样需要将正文message部分进行修改即可
[root@localhost MSTP]# vim sendmail.py 
#!/bin/env python3
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

# 第三方SMTP服务
mail_host = "smtp.qq.com"             # 设置服务器(smtp.163.com是网易邮箱服务器,smtp.qq.com是QQ地址)
mail_user = "xxxxxxxx@qq.com"         # 用户名
mail_pass = "aydzptaydrdpched"        # 密码(注意,这里的密码指的是邮箱客户端授权码)


# 发送者邮箱
sender = "xxxxx@qq.com"

# 接收者邮箱
receivers = ['xxxx@163.com', 'xxxxx@qq.com']                 # 邮件接受者,可设置多个

# 构造正文
# # -------------------- 文本类邮件 -------------------------------------------------
# message = MIMEText('这是正文:python test。。。', 'plain', 'utf-8')       # 构造正文
# 构造正文
# # ------------------- html类邮件 -------------------------------------------------
# message = MIMEText(
#     '<html><body><h1>这是正文标题</h1>\
#     <p>正文内容<a href="#">https://blog.csdn.net/CN_LiTianpeng?spm=1001.2014.3001.5343 #《超链接》</a>...</p>\
#     </html></body>',
#     "html",
#     "utf-8"
# )
# 构造正文
# ---------------------可添加附件的邮箱--------------------------------------------------
message = MIMEMultipart()
# 邮件正文部分
message.attach(MIMEText('<p>这是正文:图片及附件发送测试</p><p>图片演示</p><p><img src="cid:image1"></p>', 'html', 'utf-8'))

# 指定图片路径
fp = open("baidu2.jpg", 'rb')
msgImage = MIMEImage(fp.read())
fp.close()
# 定义图片ID,在Html中引用
msgImage.add_header("Content_ID", "<image1>")
message.attach(msgImage)

# 添加附件1,传送当前目录下的test.txt文件
att1 = MIMEText(open("test.txt", "rb").read(), "base64", "utf-8")
att1["Content-Type"] = "application/octet-stream"
# 这里的filename可以任意写,写什么名称,在邮件中就会显示什么名称
att1["Content-Dispostion"] = "attachment; filename='测试文件' "
message.attach(att1)
# --------------------------------------------------------------------

# 构造发件人
message["From"] = sender                                                 # 发件人,这个必须构造,也可以使用Header来构造

# 收件人列表,这个不是必须的
message["To"] = ";".join(receivers)

# 定义邮件主题
message["Subject"] = "这是主题:SMTP 邮件测试"

try:
    smtpObj = smtplib.SMTP()                                            # 建立和SMTP邮件服务器的连接
    smtpObj.connect(mail_host, 25)                                      # 25 为端口号
    smtpObj.login(mail_user, mail_pass)
    smtpObj.sendmail(sender, receivers, message.as_string())
    print('send mail Successfully')
    smtpObj.quit()                                                       # 结束会话
except smtplib.SMTPException as e:
    print(f"发送失败,错误原因:{e}")

三、利用poplib模块来收取邮件

1.收取步骤

  • 第一步:用poplib模块将邮件的原始文本下载到本地
  • 第二步:用email模块解析原始文本,还原邮件对象

2.应用示例


四、实时邮箱告警

监控示例

监控要求:

  • 文本文件txt约定格式:第一行为收件人列表,以分号隔开;第二行为主题,第三行至最后为正文。如最后一行是文件,则作为附件发送,支持发送多个附件,以逗号隔开

    xxx@163.com;xxx@qq.com
    xxx 程序告警
    告警信息:…


    /home/log/xxx.log,/tmp/yyy.log

  • 持续监控一个目录下的txt文件,如果有新增或者修改,则读取文本中的内容并发送邮件
  • 涉及的知识点:文件编码。读文件操作、watchdog模块应用及邮件发送

告警代码:

import smtplib
import chardet
import codecs
import os
from email.mime.text import MIMEText
from email.header import Header
from email.mime.multipart import MIMEMultipart

# 接收告警的邮箱列表
recipient_list = ['xxx@163.com', 'xxx@qq.com']
# 第三方SMTP服务
class TxtMali(object):
    def __init__(self, host=None, auth_user=None, auth_pass=None):
        # 设置发送告警的邮件服务器
        self.host = "smtp.qq.com" if host is None else host
        # 设置专用告警账户的用户名
        self.auhe_user = "xxx@qq.com" if auth_user is None else auth_user
        # 设置专用告警账户的用户的密码
        self.auth_pass = "xxxxxxxxxxxx" if auth_pass is None else auth_pass
        self.sender = "xxxxxx@qq.com"

    def send_mail(self, subject, msg_str, recipient_list, attachment_list=None):
        messgae = MIMEMultipart()
        messgae["From"] = self.sender
        messgae["To"] = Header(';'.join(recipient_list), "utf-8")
        messgae["Subject"] = Header(subject, 'utf-8')
        messgae.attach(MIMEText(msg_str, 'plain', 'utf-8'))

        # 如果有附件,则添加附件
        if attachment_list:
            for att in attachment_list:
                attachment = MIMEText(open(att, "rb").read(), "base64", "utf-8")
                attachment["Content-Type"] = "application/octet-stream"
                # 这里的filename可以任意写,会在邮件中显示
                # attname = att.split("/")[-1]
                filename = os.path.basename(att)
                # attm["Content-Disposition"] = 'attachment;filename=%s'%attname
                attachment.add_header(
                    "Content_Disposition",
                    "attachment",
                    filename=('utf-8', "", filename)
                )
        smptObj =smtplib.SMTP_SSL()
        smptObj.connect(self.host, smtplib.SMTP_SSL_PORT)
        smptObj.login(self.auhe_user, self.auth_pass)
        smptObj.sendmail(self.sender, recipient_list, messgae.as_string())
        smptObj.quit()
        print("邮件发送成功")

    def guess_chardet(self, filename):
        """
        :param filename: 传入一个文本文件
        :return: 返回文本文件的编码格式
        """
        encoding = None
        try:
            # 由于本需求解析的文件不大,可以一次性读入内存
            # 如果是大文件,则读取固定字节数
            raw = open(filename, 'rb').read()
            if raw.startswith(codecs.BOM_UTF8):                 # 处理UTF-8 with BOM
                encoding = "utf-8-fig"
            else:
                result = chardet.detect(raw)
                encoding = result["encoding"]
        except:
            pass
        return encoding

    def txt_sen_dmail(self, filename):
        """
        :param filename:
        :return:
        将指定格式的txt文件发送到邮箱,txt文件样式如下:
        xxx@163.com;xxx@qq.com   # 收件人
        xxx 程序告警              # 主题
        告警信息:......          # 正文
        ......
        file1,file2             # 附件
        """
        with open(filename, encoding=self.guess_chardet(filename)) as f:
            lines = f.readlines()
        recipient_list = lines[0].strip().split(",")
        subject = lines[1].strip()
        msg_str = "".join(lines[2:])
        attachment_list = []
        for file in lines[-1].strip().split(","):
            if os.path.isfile(file):
                attachment_list.append(file)
            # 如果没有这个附件,则为None
            if attachment_list == []:
                attachment_list = None

            self.send_mail(
                subject=subject,
                msg_str=msg_str,
                recipient_list=recipient_list,
                attachment_list=attachment_list
            )

if __name__ == '__main__':
    mymail = TxtMali()
    mymail.txt_sen_dmail(filename="./test.txt")

监控文件脚本:

# ----------------------------
#文件监控

import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from test_alert_mail import TxtMail

class FileEventHandler(FileSystemEventHandler):
    def __init__(self):
        FileSystemEventHandler.__init__(self)

    def on_created(self, event):
        if event.is_directory:
            print("directory is created:{0}".format(event.src_path))
        else:
            print("file created:{0}".format(event.src_path))
            if event.src_path.endswith(".txt"):
                time.sleep(0.5)
                mail = TxtMail()
                try:
                    mail.txt_send_mail(filename=event.src_path)
                except:
                    print("文本文件格式不正确")

if __name__ == '__main__':
    observer = Observer()
    event_handler = FileEventHandler()
    dir = "./"
    observer.schedule(event_handler, dir, False)
    print(f"当前监控的目录:{dir}")
    observer.start()
    observer.join()

邮箱附件名ATT0001.bin问题解决:
修改 att1.add_header('Content-Disposition', 'attachment', filename='需要接收为的文件名.后缀')

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值