电子邮件标头的剖析
电子邮件中的每个重要标题字段都有解释——它的含义、谁设置它以及为什么重要。包括一个完整注释的真实示例。
完整示例
以下是真实电子邮件的标题,从上到下,如收件人邮箱中所示。我们将逐一分析。
Delivered-To: bob@example.net
Received: from mx1.example.net (mx1.example.net [203.0.113.10])
by final-mda.example.net with LMTP id abc123
for <bob@example.net>; Tue, 11 Mar 2026 14:00:12 +0000
Received: from sender.mailertogo.com (sender.mailertogo.com [198.51.100.42])
by mx1.example.net (Postfix) with ESMTPS id 4F3A21C8
for <bob@example.net>; Tue, 11 Mar 2026 14:00:10 +0000
Authentication-Results: mx1.example.net;
spf=pass (sender SPF authorized) smtp.mailfrom=sender.mailertogo.com;
dkim=pass header.d=example.com header.s=mtg header.b=AuUoFE;
dmarc=pass (policy=reject) header.from=example.com
DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=mtg;
c=relaxed/relaxed; q=dns/txt;
h=from:to:subject:date:message-id:mime-version:content-type;
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk...
From: Alice <alice@example.com>
To: Bob <bob@example.net>
Subject: Your March invoice is ready
Date: Tue, 11 Mar 2026 14:00:00 +0000
Message-ID: <inv-7842@example.com>
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="----=_Part_001"
List-Unsubscribe: <https://example.com/unsub?t=abc123>,
<mailto:unsub@example.com?subject=unsubscribe-abc123>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
现在让我们逐一查看每个标题。
身份标题
发件人
消息的作者,由 RFC 5322 定义。这是收件人在其邮件客户端中看到的内容。它包括可选的显示名称(Alice)和邮箱地址(alice@example.com)。DMARC 对齐检查针对此标题中的域执行。
发件人与信封发件人不同。信封发件人(SMTP 中的 MAIL FROM)可能完全不同。发件人:标题由消息作者设置;信封发件人由发送系统设置。
收件人、抄送、密件抄送
To: 和 Cc: 是显示标题——它们指示预期的收件人但不控制交付。实际收件人由 SMTP RCPT TO 命令确定,可能包括任何标题中未列出的密件抄送收件人。一条消息可以有一个 To: 标题,列出 不 在 RCPT TO 中的地址,反之亦然(这是密件抄送的工作方式)。
回复地址
我们的示例中没有显示,但很常见。指定回复应导向的位置(如果与 From: 不同)。通常在邮件从无回复地址发送但回复应转到支持团队时使用:
发件人
当负责发送的实体与作者不同时使用。如果 Alice 的助手代表她发送消息,标题可能显示 From: Alice 和 Sender: Assistant。大多数消息省略此标题。
消息识别
消息 ID
此消息的全局唯一标识符,由发件人生成。格式为 <unique-part@domain>。这对线程、重复数据删除和退信关联至关重要。每条消息都应该有一个。如果您的发送系统未设置,第一个 MTA 将生成一个——但随后您将失去将退信与特定已发送消息关联的能力。
回复和参考
用于线程。In-Reply-To 包含正在回复的消息的 Message-ID。References 包含线程中 Message-ID 值的完整链。邮件客户端使用这些来分组对话:
References: <inv-7842@example.com> <reply-001@example.net>
日期和主题
日期
消息撰写的日期和时间,由发件人设置。格式在 RFC 5322 中指定。它 不是 交付时间。消息可能在队列中停留数小时或数天后才交付。始终包括时区偏移。
主题
总结消息的自由格式文本。规范中没有长度限制,但邮件客户端会在不同长度处截断。保持在 60 字符以下以获得一致的显示效果。非 ASCII 字符必须使用 RFC 2047 编码进行编码(例如,=?UTF-8?Q?...?=),尽管大多数现代邮件系统可以透明地处理这个问题。
Received 链
by final-mda.example.net with LMTP id abc123
for <bob@example.net>; Tue, 11 Mar 2026 14:00:12 +0000
Received: from sender.mailertogo.com (sender.mailertogo.com [198.51.100.42])
by mx1.example.net (Postfix) with ESMTPS id 4F3A21C8
for <bob@example.net>; Tue, 11 Mar 2026 14:00:10 +0000
处理消息的每个服务器都会前置一个 Received: 标题。它们从 下到上 阅读——最旧的跳转在底部,最新的在顶部。每个标题记录:
- from — 发送消息的服务器(主机名和 IP)
- by — 接收消息的服务器
- with — 使用的协议(ESMTP、ESMTPS 用于 TLS、LMTP 用于本地交付)
- id — 接收服务器的队列 ID
- for — 收件人(为了隐私可能对多个收件人省略)
- 时间戳 — 此跳转接收消息的时间
Received 链对于调试交付延迟非常宝贵。比较跳转之间的时间戳以找到时间损失的位置。注意:发件人端的 Received: 标题可能是伪造的。仅信任您自己的基础设施添加的标题。
Return-Path
由最终交付 MTA 设置,此记录 SMTP 信封发件人(MAIL FROM)。这是退信的发送位置。在此示例中,使用 VERP 编码——原始收件人(alice@example.com)被编码到退信地址的本地部分中。
Return-Path 不由消息作者设置;它从 SMTP 会话中提取并由交付服务器添加。已交付的消息中应该恰好有一个 Return-Path 标题。
身份验证标题
DKIM 签名
c=relaxed/relaxed; q=dns/txt;
h=from:to:subject:date:message-id:mime-version:content-type;
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk...
由发送服务器添加。d= 字段标识签名域(用于 DMARC 对齐)。s= 字段是用于在 DNS 中查找公钥的选择器。h= 字段列出哪些标题已签名。有关完整的验证流程,请参阅 电子邮件身份验证解释。
身份验证结果
spf=pass (sender SPF authorized) smtp.mailfrom=sender.mailertogo.com;
dkim=pass header.d=example.com header.s=mtg header.b=AuUoFE;
dmarc=pass (policy=reject) header.from=example.com
由接收服务器添加(RFC 8601)。这是此跳转中对此消息进行身份验证检查的权威记录。authserv-id(mx1.example.net)标识执行检查的服务器。它记录 SPF、DKIM 和 DMARC 结果,包括检查的标识符。
安全说明:来自外部源的伪造 Authentication-Results 标题应该被边界 MTA 删除。仅当您自己的基础设施添加此标题时才信任它。
MIME 标题
MIME 版本
指示消息使用 MIME(RFC 2045)。这总是 1.0 并且应该出现在每条消息上。没有它,消息被解释为纯 US-ASCII 文本。
内容类型
描述消息正文的媒体类型。常见值:
-
text/plain— 纯文本 -
text/html— HTML 内容 -
multipart/alternative— 同一内容的多个版本(通常是文本和 HTML)。邮件客户端选择最佳版本。 -
multipart/mixed— 带附件的消息 -
multipart/related— 带内联图像的 HTML
boundary 参数定义 MIME 部分之间的分隔符。详见 RFC 2046。
内容传输编码
正文如何编码以安全传输。常见值:7bit、quoted-printable、base64。附件使用 base64。HTML 电子邮件正文通常使用 quoted-printable 来处理非 ASCII 字符,同时保持大部分可读性。
列表管理标题
<mailto:unsub@example.com?subject=unsubscribe-abc123>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
RFC 2369 定义 List-Unsubscribe,它提供用于取消订阅的 URL 和/或 mailto 地址。RFC 8058 添加 List-Unsubscribe-Post,允许直接从邮件客户端的 UI 进行一键取消订阅,无需打开浏览器。Gmail 和其他主要提供商要求批量和营销电子邮件同时提供这两个标题。
不应该看到但有时会的标题
X-Mailer / User-Agent
标识邮件客户端或发送软件。有时被垃圾邮件过滤器用作信号。现代发送系统通常会省略这个以减少指纹识别表面。
X-Priority / Importance
试图设置消息优先级的非标准标题。大多数邮件客户端忽略它们。某些垃圾邮件过滤器将高优先级标记视为负信号。
X-Spam-Status / X-Spam-Score
由垃圾邮件过滤系统(如 SpamAssassin)添加。不标准化,但内部广泛使用。这些不应该出现在传出邮件上——它们由接收基础设施添加。
可能出错的地方
缺少消息 ID
如果您未设置 Message-ID,第一个 MTA 会添加一个。但您失去关联已发送消息与退信和交付通知的能力。发送前始终生成您自己的 Message-ID。
发件人和信封发件人的混淆
这是可交付性问题的常见根源。From: 标题显示 alice@example.com,但信封发件人是 bounce@esp.com。SPF 验证 ESP 域,而不是您的域。如果您的 DKIM 签名也使用 d=esp.com,则 DMARC 对齐对两个机制都失败。修复方法:使用 d=example.com 签名以便 DKIM 对齐。
重复或冲突的标题
RFC 5322 规定某些标题(如 From:、Date:、Message-ID:)必须恰好出现一次。重复可能导致不可预测的行为——不同的邮件客户端可能选择不同的值。某些垃圾邮件过滤器将重复的 From: 标题视为可疑。
缺少日期标题
没有 Date: 标题,接收 MTA 或邮件客户端将替换其自己的时间戳,这可能差异很大。某些垃圾邮件过滤器会对没有 Date 标题的消息进行处罚。
Received 链伪造
任何人都可以在发送消息前向其前置虚假 Received: 标题。接收 MTA 只能信任它自己添加的标题。调试时,从顶部(最新)开始向下工作,一旦您到达您的基础设施与外部世界之间的边界,就停止信任。
关键要点
- 标题是关于消息的元数据。信封(MAIL FROM / RCPT TO)控制交付;标题用于显示和处理。
-
From:是收件人看到的。Return-Path:是退信的发送位置。它们通常不同。 -
Received:标题形成从下到上的链,显示消息的路径。仅信任来自您自己的基础设施的标题。 -
Authentication-Results:是接收服务器对 SPF、DKIM 和 DMARC 的判决。 - 始终设置
Message-ID、Date、From、MIME-Version和Content-Type。 - 对于批量/营销电子邮件,包括
List-Unsubscribe和List-Unsubscribe-Post。