Python mailbox.get_bytes 怎样控制是否保留信封头
来源:17golang原创
时间:2026-11-10 07:50:39 309浏览 收藏
如果你用 Python 读取 mbox 邮件,关键不是改写返回结果,而是在调用 mbox.get_bytes() 时选择 from_ 参数:from_=False(默认值)会去掉每条记录最前面的 Unix From 信封行,from_=True 则把它保留下来。邮件头里的 From: 与这条信封行不是同一个字段。
官方地址:https://docs.python.org/3/library/mailbox.html
本文用一个最小 mbox 项目生成测试邮件、读取同一个 key,并打印两种字节结果。需要保留原始 mbox 记录边界时选 True;只想交给 email 解析器处理标准邮件头和正文时,通常选默认的 False。
先分清 mbox 信封行和邮件头
mbox 文件中的一条记录通常以 Unix “From ” 行开始,例如 From alice@example.com Tue Nov 10 10:00:00 2026。它是 mbox 存储格式用来分隔记录的信封信息,不是 RFC 5322 邮件头;真正的邮件头从 Subject:、Date:、From: 这类字段开始。
mailbox.Mailbox.get_bytes(key) 返回邮件的字节表示。对 mailbox.mbox 来说,方法多了一个 from_ 参数:默认不返回首行,传入 True 才保留首行。这个差异适合用字节首行直接观察,而不要用邮件头字典去判断。

准备一个可重复运行的小项目
先创建一个临时目录,再用 mailbox.mbox 写入一封测试邮件。示例显式调用 lock()、flush() 和 close(),这样不会把“正在写入”和“正在读取”的状态混在一起。
from email.message import EmailMessage
from pathlib import Path
import mailbox
# 使用项目目录中的 mbox 文件,重复运行前先清理旧测试数据。
mbox_path = Path("demo-mailbox.mbox")
if mbox_path.exists():
mbox_path.unlink()
# 组装一封最小邮件,便于后面比较返回字节的首行。
message = EmailMessage()
message["From"] = "alice@example.com"
message["To"] = "bob@example.com"
message["Subject"] = "mailbox get_bytes demo"
message.set_content("保留或去掉 mbox 信封行都不应改变正文。")
# 写入 mbox 后刷新并关闭,确保读取阶段看到完整记录。
box = mailbox.mbox(mbox_path, create=True)
box.lock()
try:
box.add(message)
box.flush()
finally:
box.close()
print(f"测试文件:{mbox_path}")
这段代码只负责准备输入。mbox.add() 返回的 key 会在读取阶段重新从 mailbox 中取得,不要假设 key 永远是字符串或从零开始的整数。
用 from_=False 去掉信封行
读取时先使用默认值。这里把返回结果按行拆开,只展示前几行并标出首行;由于 from_=False,第一行应该已经是邮件头,而不是以大写 From 开头的 mbox 分隔行。
import mailbox
from pathlib import Path
# 以只读方式打开准备好的 mbox,key 从实际内容中取得。
box = mailbox.mbox(Path("demo-mailbox.mbox"), create=False)
try:
key = next(iter(box))
# 默认 from_=False:去掉 mbox 记录顶部的 Unix From 信封行。
raw_without_envelope = box.get_bytes(key, from_=False)
first_line = raw_without_envelope.splitlines()[0].decode("ascii", "replace")
print(f"首行:{first_line}")
finally:
# 读取完成后关闭文件句柄;不需要写锁时不要额外修改 mailbox。
box.close()
首行:From: alice@example.com
这里打印的 From: 是邮件头,保留它是解析发件人信息所需要的;被去掉的是 mbox 存储层的 From 信封行。若你的下游代码使用 email.parser.BytesParser,通常把默认结果交给解析器就够了。
用 from_=True 保留原始信封行
当目标是导出 mbox 原始记录、保留记录边界,或者把字节交给仍然期待 Unix From 行的下游工具时,传入 from_=True。下面把两种结果的首行放在一起比较。
import mailbox
from pathlib import Path
# 同一个 key 读取两次,只改变 from_,方便比较存储层首行。
box = mailbox.mbox(Path("demo-mailbox.mbox"), create=False)
try:
key = next(iter(box))
raw_without_envelope = box.get_bytes(key, from_=False)
raw_with_envelope = box.get_bytes(key, from_=True)
# 用 replace 处理不可见的回车换行,输出只承担验收作用。
line_without = raw_without_envelope.splitlines()[0].decode("ascii", "replace")
line_with = raw_with_envelope.splitlines()[0].decode("ascii", "replace")
print("from_=False:", line_without)
print("from_=True :", line_with)
finally:
# get_bytes 不会替代 mailbox 的生命周期管理,读取结束仍要关闭对象。
box.close()
from_=False: From: alice@example.com
from_=True : From alice@example.com Tue Nov 10 10:00:00 2026
两份结果的邮件头和正文内容相同,区别集中在最前面的信封行。实际时间字符串由 mbox 写入过程决定,示例输出只用于说明形状,不应把时间当成业务字段。

按场景选择参数,不要混淆邮件格式
| 场景 | 建议调用 | 原因 |
|---|---|---|
| 解析邮件头和正文 | get_bytes(key) | 默认去掉存储层信封行,输入更接近标准邮件内容。 |
| 导出一条完整 mbox 记录 | get_bytes(key, from_=True) | 保留记录分隔所需的 Unix “From ” 首行。 |
| 使用 Maildir、MH 等 mailbox | get_bytes(key) | 不要把 mbox 的额外参数直接套到所有 Mailbox 子类。 |
官方文档把 from_ 标为 mbox.get_bytes() 的额外参数;mailbox.MMDF 也提供同类控制。其他 mailbox 类型的 get_bytes() 签名并不保证接受这个参数,所以跨格式代码应把是否保留信封行作为 mbox/MMDF 分支处理。
运行验收和常见问题
把前面的代码保存为 mailbox_get_bytes_demo.py 后,在空目录运行:
# 运行最小项目,先生成 mbox,再比较两种 from_ 结果。 python3 mailbox_get_bytes_demo.py
验收只看两个事实:from_=False 的首行应是 From: 等邮件头,from_=True 的首行应是以 From 开头的信封行。如果调用的 key 不存在,官方 API 会抛出 KeyError,这说明读取对象和 key 生命周期需要重新对应,不是 from_ 参数失效。
为什么看到两个 From?
From: 是邮件头字段,From (没有冒号)是 mbox 记录的 Unix 信封行。它们可以同时存在,不能只按单词相同就认为是重复字段。
能不能把 from_ 传给 mailbox.Maildir?
不要这样写。from_ 是 mbox/MMDF 针对存储格式提供的额外参数;对 Maildir 使用通用的 get_bytes(key),需要原始格式时再按对应 mailbox 类型的文档设计处理。
读取后还要 flush 吗?
纯读取不需要为了 get_bytes() 额外调用 flush(),但打开对象应在结束时 close()。只有在你对 mailbox 做了新增、删除或修改并希望落盘时,才按写入流程加锁、刷新和关闭。
小结
Python mailbox.get_bytes() 控制信封头的答案就是 mbox 的 from_ 参数:默认 False 去掉 Unix “From ” 行,True 保留它。把这个选择放在“标准邮件解析”与“原始 mbox 记录导出”的边界上,就能避免把存储格式信息误当成邮件头,也能让跨 mailbox 类型的代码更稳妥。
-
346 收藏
-
235 收藏
-
442 收藏
-
387 收藏
-
447 收藏
-
433 收藏
-
361 收藏
-
271 收藏
-
486 收藏
-
494 收藏
-
118 收藏
-
476 收藏
-
167 收藏
-
195 收藏
-
161 收藏
-
127 收藏
-
474 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习