python之smtplib模块发送邮件

虽然一般自动化持续集成中都用Jenkins来发送邮件,但了解掌握一下python的smtplib模块发送邮件也是必要的。

先明确一下发邮件的步骤:

1.确定邮件服务商:网易、qq等

2.登录邮箱:用户名/密码(密码一般是授权码)

3.编辑邮件主题、内容、附件

4.发送邮件

最简单的实现:

server = smtplib.SMTP('smtp.163.com',25)
server.login(emailname,emailpwd)    # 登录
# 邮件内容
msg = '''\From: xia
           Subject: Hello World           
           This is a test '''
# 发送邮件
server.sendmail(emailname,'18551052425@163.com',msg)

  如上代码创建一个实例化对象server,调用SMTP类下的login方法,采用163邮件服务,默认端口是25,emailname和emailpwd分别为发送邮件的用户名和授权码。

实际在发邮件的时候,我们通常使用加密模式。简单的两种加密方法:

1.tls模式加密

server = smtplib.SMTP('smtp.163.com',25)

server.login(emailname,emailpwd)    # 登录
context = ssl.create_default_context()
server.starttls(context=context)
# 邮件内容 msg = '''\ From: xia 
             Subject: Hello World 
             This is a test ''' 
# 发送邮件 
server.sendmail(emailname,'18551052425@163.com',msg)
server.quit()

2.ssl加密,默认加密端口是465

server = smtplib.SMTP_SSL('smtp.163.com',465)
server.login(emailname,emailpwd)    # 登录
# 邮件内容
msg = '''\
             From: xia
             Subject: Hello World           
             This is a test '''
# 发送邮件
server.sendmail(emailname,'18551052425@163.com',msg)
server.quit()

创建server后,要记得quit关闭。也可以使用上下文管理器,防止忘记关闭邮件:

with smtplib.SMTP_SSL('smtp.163.com',465) as server:
    server.login(emailname,emailpwd)    # 登录
    # 邮件内容
    msg = '''\
             From: xia
             Subject: Hello World           
             This is a test '''
    # 发送邮件
    server.sendmail(emailname,'18551052425@163.com',msg)

 但是实际应用中,不可能会发送这么简单的邮件。我们需要丰富邮件主题、内容和附件。

这就需要引入3个模块:

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

 首先创建一个带附件的实例MIMEMultipart(),设置邮件主题,from,to信息:

msg_total = MIMEMultipart()
msg_total['subject'] = Header(self.subject,'utf-8')
msg_total['From'] = emailname
msg_total['To'] = tolist 

 添加邮件正文内容,这里添加html格式的内容:

content = '''<p style="color:red">你好,我是一份测试邮件。</p>'''
msg_total.attach(MIMEText(content, 'html','utf-8')) 

 也可以读取某个文件内容作为邮件正文:

with open(file, 'rb') as f:
    content = f.read()
    msg_total.attach(MIMEText(content, 'html', 'utf-8')) 

 添加附件的话,MIMEText模块和MIMEAplication模块都可以添加,只不过看源码发现,MIMEApplication比MIMEText要简单一些,需要配置的参数少一些。

MIMEText模块添加附件:

with open(file, 'rb') as f:
    mail_attach = f.read()
    att = MIMEText(mail_attach, 'base64', 'utf-8')
    att["Content-Type"] = 'application/octet-stream'
    # 这里的filename可以任意写,写什么名字,邮件中显示什么名字
    att["Content-Disposition"] = 'attachment; filename="测试报告"'
    msg_total.attach(att)

MIMEApplication模块添加附件:

with open(file_new, 'rb') as f:
     mail_attach = f.read()
     att2 = MIMEApplication(mail_attach)
     # 添加附件的头信息
     att2.add_header('content-disposition', 'attachment', filename='{}'.format(file_name))
     msg_total.attach(att2)

 对比代码也可以发现,MIMEapplication模块添加附件更方便一些。

上面邮件正文和附件文件都是写死的,一般在应用中,我们可以获取当前最新的测试执行报告作为附件:

file = os.listdir(report_path)  # 列出目录的下所有文件和文件夹
file.sort(key=lambda fn: os.path.getmtime(report_path + "\" + fn))  # 按时间排序
file_name = file[-1]
file_new = os.path.join(report_path, file[-1])  # 获取最新的文件保存到file_new

# 添加文件内容作为正文模块
with open(file_new, 'rb') as f:
    content = f.read()
    msg_total.attach(MIMEText(content, 'html', 'utf-8'))

# 附件模块
with open(file_new, 'rb') as f:
    mail_attach = f.read()
    att = MIMEText(mail_attach, 'base64', 'utf-8')
    att["Content-Type"] = 'application/octet-stream'
    # 这里的filename可以任意写,写什么名字,邮件中显示什么名字
    att["Content-Disposition"] = 'attachment; filename="{}"'.format(file_name)
    msg_total.attach(att)

 整合以上邮件主题、内容、附件,加上异常处理,并封装成一个类,便于后续调用。完整代码如下:

  

import smtplib
from python15.class_email.conf import *
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.header import Header
import os

class MyEmail:

    def __init__(self,host,port,tolist,subject,content=None):
        self.host = host    #邮件服务地址
        self.port = port    # 邮件服务端口
        self.tolist = tolist # 接收人
        self.subject = subject  # 邮件主题
        self.content = content  # 邮件内容

    def send_email(self):

        # 总的邮件内容,创建一个带附件的实例
        msg_total = MIMEMultipart()
        msg_total['subject'] = Header(self.subject,'utf-8')
        msg_total['From'] = emailname
        msg_total['To'] = self.tolist

        # 添加普通正文模块
        # msg_total.attach(MIMEText(self.content, 'html','utf-8'))

        file = os.listdir(report_path)  # 列出目录的下所有文件和文件夹
        file.sort(key=lambda fn: os.path.getmtime(report_path + "\" + fn))  # 按时间排序
        file_name = file[-1]
        file_new = os.path.join(report_path, file[-1])  # 获取最新的文件保存到file_new

        # 添加文件内容作为正文模块
        with open(file_new, 'rb') as f:
            content = f.read()
            msg_total.attach(MIMEText(content, 'html', 'utf-8'))

        # 附件模块1 MIMEText添加附件
        with open(file_new, 'rb') as f:
            mail_attach = f.read()
            att1 = MIMEText(mail_attach, 'base64', 'utf-8')
            att1["Content-Type"] = 'application/octet-stream'
            # 这里的filename可以任意写,写什么名字,邮件中显示什么名字
            att1["Content-Disposition"] = 'attachment; filename="{}"'.format(file_name)
            msg_total.attach(att1)

        # 附件模块2 MIMEApplication模块添加附件
        with open(file_new, 'rb') as f:
            mail_attach = f.read()
            att2 = MIMEApplication(mail_attach)
            # 添加附件的头信息
            att2.add_header('content-disposition', 'attachment', filename='{}'.format(file_name))
            msg_total.attach(att2)

        try:
            self.server = smtplib.SMTP_SSL(self.host, self.port)
            self.server.login(emailname, emailpwd)
            self.server.sendmail(emailname, self.tolist, msg_total.as_string())
            print("邮件发送成功")
        except smtplib.SMTPException as e:
            print("邮件发送失败",e)
        finally:
            self.server.quit()

  

原文地址:https://www.cnblogs.com/Dahlia/p/10639916.html