python中的标准库提供自动发送邮件的功能。标准库email库可以完成邮件的创建和解析,标准库smtplib库完成连接邮箱服务器并发送邮件。

 标准库email:

创建邮件并解析,遵循RFC标准。RFC(Requests For Comments,请求评论,是一系列互联网相关的资料和技术文档)。官网:» RFC Editor

python3.6之前的email库,需要创建多个MIME对象(正文内容 MIMEText,附件文件 MIMEApplication,附件图片 MIMEImage等),并且手动调整header(email.header),繁琐而又易出错。注:MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展),是一种标准、协议、规范。

python3.6之后的email库,引入了email.message.EmailMessage,仍然会创建完整的MIME对象树,但只需声明所需内容,python会自动完成所有底层的MIME结构、header信息、编码等,更方便更简洁,而且默认使用更国际化的策略policy。

python3.6之前的email库 python3.6之后的email库
邮件实例化

from email.mime.multipart import MIMEMultipart

mm=MIMEMultipart('related')

from email.message import EmailMessage

mm = EmailMessage()

主题

from email.header import Header

mm["Subject"] = Header("主题", 'utf-8').encode()

mm["Subject"] = "主题"
发送人

mm["From"] = '发件人'

mm["From"] = '发件人'
接收人

mm["To"] = f"收件人1, 收件人2"

mm["To"] = f"收件人1, 收件人2"

正文

(文本)

from email.mime.text import MIMEText

text = MIMEText('正文文本内容', "plain", "utf-8")

mm.attach(text)

mm.set_content('正文文本内容')

正文

(html)

html_text = MIMEText('正文html内容', "html", "utf-8")

mm.attach(html_text)

mm.add_alternative('''正文html内容''', subtype='html')

附件

(txt文件)

from email.mime.application import MIMEApplication

attach = MIMEApplication(open(f'txt文件路径', 'rb').read(), 'utf-8')

attach.add_header('Content-Disposition', 'attachment', filename='文件名')

mm.attach(attach)

with open(f'txt文件路径', 'rb') as f:

    mm.add_attachment(f.read(), maintype='application', subtype='octet-stream', filename='文件名')

附件

(png图片)

from email.mime.image import MIMEImage

image = MIMEImage(open(f'png图片路径', 'rb').read())

image.add_header('Content-Disposition', 'attachment', filename='图片名')

mm.attach(image)

with open(f'png图片路径', 'rb') as f:

    mm.add_attachment(f.read(), maintype='image', subtype='png', filename='图片名')

python3.6之后的email库,三个主要组件和一个控制组件:

  • email.messasge:核心组件,其中主要是email.messasge.EmailMessage类。 创建邮件。邮件对象模型是对象树结构,即邮件及其MIME子组件组成树状结构,其中每一个节点都是EmailMessage对象,每个EmailMessage对象都符合MIME标准,也可以说每个EmailMessage对象都是MIME组件。
  • email.parser:解析器。将邮件的序列化字节流转为EmailMessage对象树。
  • email.generator:生成器。将EmailMessage对象转为序列化的字节流。
  • email.policy:策略模块。每个EmailMessage、每个parser、每个generator都有对应的策略对象控制其行为。默认策略是更国际化的邮件标准(如 RFC5322 或6532)。

主要类:email.message.EmailMessage(...)

类 email.message.EmailMessage(policy=default)

注:不指定策略,则使用默认策略。

每一个EmailMessage对象都由头部header和有效负载payload即内容组成,

  • 邮件头部:包括主题、收件人、接收人等,头部的结构类似于有序字典。
  • 有效负载(内容):包括正文、附件等,结构是字符串或字节对象或EmailMessage对象列表(复合邮件,比如文本、附件)。

EmailMessage实例化对象(例如):mm=EmailMessage()

邮件各个部分:

1、邮件头部信息

邮件头部信息类似于有序字典。树结构的各个节点都有头部信息。

邮件主题:EmailMessage['Subject']

例如:mm["Subject"] = '邮件主题'

注:mm为EmailMessage实例化对象。

邮件发送人:EmailMessage['From']

例如:mm["From"] = '发件人'

注:mm为EmailMessage实例化对象。

邮件接收人:EmailMessage['To']

例如:mm["To"] = '收件人'

注:mm为EmailMessage实例化对象。若多个收件人则中间以逗号", "隔开。

2、有效负载(邮件正文内容)
邮件正文:

(文本内容):EmailMessage.set_content(...)

EmailMessage.set_content(*argscontent_manager=None**kw)

邮件的正文为文本内容。

例如:mm.set_content(f'邮件正文文本内容')

注:mm为EmailMessage实例化对象。

(html内容):EmailMessage.add_alternative(...)

EmailMessage.add_alternative(*argscontent_manager=None**kw)

邮件的正文为html格式的内容。

若邮件是复合邮件(邮件类型是multipart/alternative),则自动创建子节点,自动执行set_content()和attach()到子节点。

例如:mm.add_alternative(f''''邮件正文html内容'', subtype='html')

注:mm为EmailMessage实例化对象。

附件:EmailMessage.add_attachment(...)

EmailMessage.add_attachment(*argscontent_manager=None**kw)

给邮件添加附件。若邮件类型是multipart/alternative,则自动创建子节点,自动执行set_content()和attach()到子节点。

例如:(附件:TXT文件)

mm.add_attachment(打开的txt文件.read(), maintype='application', subtype='octet-stream', filename=文件名')

(附件:png图片)

mm.add_attachment(打开的图片.read(), maintype='image', subtype='png', filename='图片名')

注:mm为EmailMessage实例化对象。

查看树的对象结构:

方法一:遍历树EmailMessage.walk(),使用get_content_type方法查看每个节点的内容类型。

EmailMessage.walk()

以深度优先的顺序遍历树的所有节点。

例如:for part in mm.walk()

               print(part.get_content_type())   # 打印节点的内容类型(message’s content type)

注:mm为EmailMessage实例化对象。

方法二:使用 email.iterators._structure(EmailMessage)

from email.iterators import _structure

_structure(mm)

注:mm为EmailMessage实例化对象。

 其他参考:email.message: Representing an email message — Python 3.13.7 documentation

标准库smtplib:

定义了SMTP客户会话对象(简称SMTP对象),向具有SMTP或ESMTP监听守护进程的计算机发送邮件。

SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)。

本文以163邮箱为例。需开启POP3/SMTP服务并获取邮箱授权码(不是邮箱登录密码)。发送邮件需知道邮箱服务器主机地址和端口。

准备工作:

开启POP3/SMTP服务,获取邮箱授权码,获取邮箱服务器主机地址。均在邮箱界面的设置下的“POP3/SMTP/IMAP”中。

0、进入163邮箱 --> 点击:设置 --> 点击:POP3/SMTP/IMAP

1、开启POP3/SMTP服务

2、获取邮箱授权码

开启POP3/SMTP服务后,会提示授权码,需记住该授权码,有效期180天。

3、获取邮箱服务器主机地址

设置中POP3/SMTP/IMAP界面最下方提示中就有SMTP服务器地址。

4、服务器端口

很多邮箱都使用常用端口,SSL端口一般为465,TLS/STARTTLS端口一般为587,而端口25也是163邮箱支持的端口但不推荐(据说端口25经常被ISP封锁以防止垃圾邮件).。

注:SSL和TLS都是加密端口为了增强安全性。而SSL端口连接需要使用子类smtplib.SMTP_SSL。

涉及类:smtplib.SMTP(...)

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

管理连接SMTP或ESMTP服务器。

注:host 邮箱服务器主机,port 邮箱服务器端口。

若使用加密端口(TLS/STARTTLS端口),需注意使用SMTP.starttls()方法。

子类:smtplib.SMTP_SSL(...)

子类:smtplib.SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, certfile=None, [timeout, ]context=None, source_address=None)

管理连接SSL端口的SMTP服务器。

注:host 邮箱服务器主机,port 邮箱服务器端口。

若port未指定,则默认使用标准SSL端口465。

类的主要方法:

1、登录:SMTP.login(...)

SMTP.login(user, password, *, initial_response_ok=True)

在需要认证的SMTP服务器上登录邮箱。

注:user 邮箱,password 邮箱授权码(不是邮箱登录密码)。

2、发送邮件:SMTP.sendmail(...)

SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())

参数:from_addr 发送邮箱。to_addrs 接收邮箱(多个邮箱使用列表)。 msg 发送内容(需是字符串含字节字符串)。

3、退出邮箱服务器:SMTP.quit()

SMTP.quit()

终止SMTP回话,关闭连接。

帮助:

标准库可以使用以下方法获取类和方法的使用说明文档。

1、官方文档:The Python Standard Library — Python 3.13.7 documentation

2、开始--> Python --> Python Manuals --> 搜索(例如):smtplib。

3、python解释器 --> 导入库(例如):import smtplib --> 使用help(...)获取类或方法的文档说明。

举例:

python3.6之后的email库 + smtplib 实现简单的邮件发送。

import smtplib
from datetime import datetime
from email.message import EmailMessage

def send_email():
    mail_server = "smtp.163.com"
    mail_receivers = ["收件人邮箱1", "收件人邮箱2"]       # 自行修改
    mail_sender = "发件人邮箱"                          # 自行修改
    # 邮箱授权码(POP3/SMTP服务的授权码,有效期180天)
    mail_password = "发件人邮箱授权码"                  # 自行修改 

    mm = EmailMessage()
    # 邮件主题
    mm["Subject"] = "新email库,邮件发送"
    # 发件人
    mm["From"] = mail_sender
    # 收件人
    mm["To"] = ", ".join(mail_receivers)
    # # 邮件的文本内容
    # now = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')
    # text_content = f"正文文本 {now}"
    # mm.set_content(text_content)
    # 邮件的HTML内容
    html_content = f"""
    <html>
    <body>
        <h1 style="color:blue;">正文html</h1>
        <p>时间: {now}</p>
        </body>
    </html>
    """
    mm.add_alternative(html_content, subtype='html')
    # 附件1,传送文件:data.txt
    with open(f'G:/Python/my_modules/data.txt', 'rb') as f:
        mm.add_attachment(f.read(), maintype='application', subtype='octet-stream', filename='data.txt')
    # 附件2,传送图片:do.png
    with open(f'G:/Python/my_modules/do.png', 'rb') as f:
        mm.add_attachment(f.read(), maintype='image', subtype='png', filename='do.png')

    # # 查看邮件结构
    # for part in mm.walk():
    #     print(part.get_content_type())
    # # 或者
    # from email.iterators import _structure
    # _structure(mm)

    # 发送邮件
    try:
        # 连接邮箱服务器
        smtp = smtplib.SMTP_SSL(mail_server, 465)
        # 登录邮箱
        smtp.login(mail_sender, mail_password)
        # 发送邮件
        smtp.sendmail(mail_sender, mail_receivers, mm.as_string())
        print("邮件发送成功")
        # 关闭服务器
        smtp.quit()
    except Exception as e:
        print("邮件发送失败")
        print(e)

if __name__ == "__main__":
    send_email()

python3.6之前的email库 + smtplib 实现简单的邮件发送。

import smtplib
from datetime import datetime
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.header import Header

def send_email():
    mail_server = "smtp.163.com"
    mail_receivers = ["收件人邮箱1", "收件人邮箱2"]       # 自行修改
    mail_sender = "发件人邮箱"                          # 自行修改
    # 邮箱授权码(POP3/SMTP服务的授权码,有效期180天)
    mail_password = "发件人邮箱授权码"                  # 自行修改

    # 邮件头部内容
    mm = MIMEMultipart('related')
    # 邮件主题
    mm["Subject"] = Header("Python SMTP 邮件发送", 'utf-8').encode()
    # 发件人
    mm["From"] = mail_sender
    # 收件人
    mm["To"] = f"{mail_receivers[0]}, {mail_receivers[1]}"
    # # 邮件的正文内容
    # now = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')
    # mail_content = f"邮件正文文本: {now}"
    # text = MIMEText(mail_content, "plain", "utf-8")
    # mm.attach(text)
    # html内容
    now = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')
    html_content = f"""
    <html>
        <body>
            <h1 style="color:blue;">邮件html内容</h1>
            <p>时间: {now}</p>
        </body>
    </html>
    """
    html_text = MIMEText(html_content, "html", "utf-8")
    mm.attach(html_text)
    # 附件1,传送文件:data.txt
    attach = MIMEApplication(open(f'G:/Python/my_modules/data.txt', 'rb').read(), 'utf-8')
    attach.add_header('Content-Disposition', 'attachment', filename='data.txt')
    mm.attach(attach)
    # 附件2,传送图片:do.png
    image = MIMEImage(open(f'G:/Python/my_modules/do.png', 'rb').read())
    image.add_header('Content-Disposition', 'attachment', filename='do.png')
    mm.attach(image)
  
    # 发送邮件
    try:
        # 连接邮箱服务器
        smtp = smtplib.SMTP_SSL(mail_server, 465)
        # # 不报错,但不推荐,端口25经常被ISP封锁以防止垃圾邮件
        # smtp = smtplib.SMTP(mail_server, 25)
        # 使用587失败,Connection unexpectedly closed
        # smtp = smtplib.SMTP(mail_server, 587)
        # smtp.starttls()    # 启用加密
        # 登录邮箱
        smtp.login(mail_sender, mail_password)
        # 发送邮件
        smtp.sendmail(mail_sender, mail_receivers, mm.as_string())
        print("邮件发送成功")
        # 关闭服务器
        smtp.quit()
    except Exception as e:
        print("邮件发送失败")
        print(e)

if __name__ == "__main__":
    send_email()

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐