python--邮件告警

  • 一、了解SMTP协议
  • 二、编写发送邮件代码
      • 1.文本格式邮件
      • 2.html正文格式邮件
      • 3.添加附件发送邮件
  • 三、利用poplib模块来收取邮件
      • 1.收取步骤
      • 2.应用示例
  • 四、实时邮箱告警
      • 监控示例

一、了解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 = "[email protected]"         # 用户名
mail_pass = "aydzptaydrdpched"        # 密码(注意,这里的密码指的是邮箱客户端授权码)


# 发送者邮箱
sender = "[email protected]"

# 接收者邮箱
receivers = ['[email protected]', '[email protected]']                 # 邮件接受者,可设置多个

# 构造正文
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

python--邮件告警_第1张图片

2.html正文格式邮件

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

\
</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 = "[email protected]"         # 用户名
mail_pass = "aydzptaydrdpched"        # 密码(注意,这里的密码指的是邮箱客户端授权码)


# 发送者邮箱
sender = "[email protected]"

# 接收者邮箱
receivers = ['[email protected]', '[email protected]']                 # 邮件接受者,可设置多个

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

这是正文标题

\
#

正文内容https://blog.csdn.net/CN_LiTianpeng?spm=1001.2014.3001.5343 #《超链接》...

\
# ', # "html", # "utf-8" # ) # 构造正文 # ---------------------可添加附件的邮箱-------------------------------------------------- message = MIMEMultipart() # 邮件正文部分 message.attach(MIMEText('

这是正文:图片及附件发送测试

图片演示

'
, 'html', 'utf-8')) # 指定图片路径 fp = open("baidu2.jpg", 'rb') msgImage = MIMEImage(fp.read()) fp.close() # 定义图片ID,在Html中引用 msgImage.add_header("Content_ID", "") 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约定格式:第一行为收件人列表,以分号隔开;第二行为主题,第三行至最后为正文。如最后一行是文件,则作为附件发送,支持发送多个附件,以逗号隔开

    [email protected];[email protected]
    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 = ['[email protected]', '[email protected]']
# 第三方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 = "[email protected]" if auth_user is None else auth_user
        # 设置专用告警账户的用户的密码
        self.auth_pass = "xxxxxxxxxxxx" if auth_pass is None else auth_pass
        self.sender = "[email protected]"

    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文件样式如下:
        [email protected];[email protected]   # 收件人
        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()

你可能感兴趣的:(Python)