当前位置:首页 > 文章列表 > 文章 > python教程 > Python email.message.EmailMessage 怎样添加 MIME 附件

Python email.message.EmailMessage 怎样添加 MIME 附件

来源:17golang原创 2026-10-28 12:41:45 0浏览 收藏

Python 里添加邮件附件,推荐把“消息构造”和“邮件发送”分开:用 EmailMessage 组织正文与 MIME 附件,用 as_bytes() 生成消息字节,最后再交给 SMTP 或其他发送层。这样不会把本地文件读取、附件类型和服务器连接混在一个函数里。

官方地址:https://docs.python.org/3/library/email.message.html

最小做法是先用 set_content() 写入正文,再调用 add_attachment() 追加附件。二进制附件通常传入 bytes,并显式提供 maintype、subtype 和 filename;这些信息决定 MIME 部件怎样被描述和还原。

先分清 EmailMessage 与 SMTP

email 包负责邮件对象模型、头部、正文、MIME 子消息和序列化;它本身不负责连接 SMTP 服务器。EmailMessage 可以看成一个有序的消息容器,简单消息的 payload 可以是文本或字节,multipart 消息则由多个子消息组成。

因此,本文的函数只返回一个 EmailMessage。调用方可以选择 as_bytes() 得到完整字节,也可以把对象交给支持现代邮件 API 的发送代码。

先添加纯文本正文

没有附件时,消息可以保持为普通文本部件。set_content() 负责把字符串放入正文,并根据消息的 policy 完成必要的内容头处理。

from email.message import EmailMessage


def build_message(subject: str, sender: str, recipient: str) -> EmailMessage:
    # 先建立消息头;EmailMessage 只描述消息,不负责 SMTP 连接。
    message = EmailMessage()
    message["Subject"] = subject
    message["From"] = sender
    message["To"] = recipient
    # 正文使用字符串,后续追加附件时会自动进入 multipart 结构。
    message.set_content("这是正文,附件将在下一步加入。")
    return message

这里的三个头部字段只是消息内容的一部分,不代表已经完成投递。尤其不要把服务器地址、账号密码或重试策略塞进这个构造函数。

EmailMessage 包含正文和 MIME 附件的静态结构关系
图1:EmailMessage 正文与 MIME 附件的静态结构关系;这是结构说明图,不是运行截图。

用 add_attachment 添加二进制附件

二进制附件的关键是把“字节内容”和“媒体类型”同时交给 add_attachment()。例如 PDF 可以写成 maintype="application"、subtype="pdf",文件名放在 filename 中。

from email.message import EmailMessage


def attach_pdf(message: EmailMessage, pdf_bytes: bytes, filename: str) -> None:
    # bytes 表示附件内容;MIME 类型描述接收方应如何理解这些字节。
    message.add_attachment(
        pdf_bytes,
        maintype="application",
        subtype="pdf",
        filename=filename,
    )


message = EmailMessage()
message["Subject"] = "月度报告"
message["From"] = "report@example.test"
message["To"] = "reader@example.test"
message.set_content("请查看附件中的月度报告。")
attach_pdf(message, b"%PDF-demo", "monthly-report.pdf")

添加后,消息会从单一正文变成包含多个部件的 MIME 结构。filename 是附件对外显示的名称,不是服务器上的路径;不要把 /Users/... 这类本地路径直接作为文件名。

处理文本附件与字节附件

add_attachment() 可以处理不同类型的 payload,但调用者仍要明确数据类型。文本附件适合传入字符串并指定字符集,二进制内容则应保持为 bytes,不要先用错误的编码转换成字符串。

def add_text_note(message: EmailMessage, text: str, filename: str) -> None:
    # 文本附件保留字符集信息,接收方才能按文本而不是二进制理解它。
    message.add_attachment(
        text,
        subtype="plain",
        charset="utf-8",
        filename=filename,
    )


def add_binary(message: EmailMessage, payload: bytes, filename: str) -> None:
    # 二进制内容不做隐式 decode,类型由 maintype/subtype 明确给出。
    message.add_attachment(
        payload,
        maintype="application",
        subtype="octet-stream",
        filename=filename,
    )

如果附件是图片、压缩包或自定义格式,maintype 和 subtype 应来自实际媒体类型,而不是一律写成 PDF。类型写错时,邮件可能仍能发送,但接收端的预览和下载行为会变得不可靠。

序列化并交给发送层

当消息结构完成后,用 as_bytes() 生成完整的 MIME 字节。序列化可能补齐边界等结构信息,所以应在内容不再变化时调用,并把返回值交给后续发送层。

from email.message import EmailMessage


def make_payload() -> bytes:
    # 构造阶段只负责消息树,发送阶段只接收最终字节。
    message = EmailMessage()
    message["Subject"] = "数据导出"
    message["From"] = "export@example.test"
    message["To"] = "ops@example.test"
    message.set_content("导出任务已完成,请下载附件。")
    message.add_attachment(
        b"id,name\n1,Alice\n",
        maintype="text",
        subtype="csv",
        filename="users.csv",
    )
    # as_bytes() 返回要交给发送组件的消息内容,不会主动发送邮件。
    return message.as_bytes()

如果要用 smtplib 发送,连接、认证、超时和重试应在调用方处理。这样单元测试可以只检查消息对象或序列化结果,而不必每次都连接真实邮件服务器。

文本正文和附件 bytes 经过 EmailMessage 构造并序列化到发送层的边界图
图2:从内容输入到消息字节的职责边界;这是操作示意图,不是邮件客户端截图。

常见边界与排查顺序

现象优先检查处理方向
附件能发出但文件类型不对maintype、subtype按真实媒体类型填写,不用文件扩展名猜测全部语义
中文文本附件乱码传入值是否为字符串、charset 是否明确文本附件保留 UTF-8 字符集,二进制附件保持 bytes
只看到正文没有附件是否调用了 add_attachment()、是否在序列化前修改对象先完成所有部件,再调用 as_bytes()
把本地路径暴露给收件人filename 是否误用了完整路径只传递收件人需要看到的文件名

排查时可以先看 message.is_multipart(),再按消息树读取各个部件。判断结构比直接搜索序列化字符串更稳定,因为 MIME 边界可能由序列化阶段补齐。

小结

Python 添加 MIME 附件的核心组合只有三步:用 EmailMessage 创建消息,用 set_content() 设置正文,用 add_attachment() 追加带类型和文件名的 payload。内容完成后再调用 as_bytes(),把“构造消息”和“发送消息”保持为两个职责。

这套写法适合报告、导出文件和通知类邮件。如果需求涉及 SMTP 连接池、认证、重试或投递状态,应在发送层单独设计,不要继续向消息构造函数堆参数。

相关问题

EmailMessage 添加附件后为什么会变成 multipart?
因为正文和附件是多个 MIME 部件,EmailMessage 需要用 multipart 容器表达它们之间的层级关系。

add_attachment 一定要写 maintype 和 subtype 吗?
对 bytes 附件应显式提供,避免接收端无法判断内容类型;文本附件则应至少明确文本类型和字符集。

as_bytes() 会不会发送邮件?
不会。它只把消息对象序列化为字节,连接服务器和实际投递由 SMTP 或其他发送组件负责。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python argparse.parse_intermixed_args 怎样处理混合位置参数Python argparse.parse_intermixed_args 怎样处理混合位置参数
上一篇
Python argparse.parse_intermixed_args 怎样处理混合位置参数
Python ipaddress.IPv4Network 怎样判断地址是否属于网段
下一篇
Python ipaddress.IPv4Network 怎样判断地址是否属于网段
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    755次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    753次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    834次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    800次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    634次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码