Skip to main content

Appendix D. SPF/Mediator Interactions (SPF/中介交互)

Appendix D. SPF/Mediator Interactions (SPF/中介交互)

本附录讨论 SPF 与邮件中介(如邮件列表和转发服务)之间的交互及其影响。

D.1 Originating ADMDs (发起 ADMD)

发起 ADMD 是最初发送邮件的管理域。在存在中介的情况下, 发起 ADMD 需要考虑其邮件可能经过的转发和列表服务。

D.1.1 问题识别

SPF 的基本假设:

  • 邮件直接从授权服务器发送到接收方
  • MAIL FROM 标识保持不变
  • 发送 IP 地址在 SPF 记录中授权

中介打破的假设:

  • 邮件经过中间系统
  • 可能从不同的 IP 地址重新发送
  • MAIL FROM 可能被修改或保持原样

D.1.2 发起方的选择

选项 1: 使用宽松的 SPF 策略

example.com IN TXT "v=spf1 mx ~all"

优点:

  • 允许合法转发
  • 减少误报

缺点:

  • 削弱了 SPF 的保护
  • 容易被伪造

选项 2: 依赖其他认证方法

发布 DKIM 签名:
- DKIM 在转发时仍然有效
- 不依赖发送 IP 地址
- 与 DMARC 配合使用

选项 3: 接受 SPF 失败

example.com IN TXT "v=spf1 mx -all"
  • 接受某些合法邮件可能被标记或拒绝
  • 依赖用户使用正确的发送方法
  • 建议用户不要转发, 而是使用"发送副本"功能

D.1.3 最佳实践

建议配置:

1. 发布严格的 SPF 记录(-all)
2. 同时实施 DKIM 签名
3. 发布 DMARC 策略
4. 教育用户关于转发的问题

DMARC 配置示例:

_dmarc.example.com IN TXT "v=DMARC1; p=quarantine; sp=quarantine; adkim=r; aspf=r; pct=100; rua=mailto:[email protected]"

参数说明:

  • adkim=r: DKIM 宽松对齐
  • aspf=r: SPF 宽松对齐
  • p=quarantine: 失败时隔离邮件

D.2 Mediators (中介)

中介是在邮件传输链中修改或重新发送邮件的系统。常见的中介包括邮件列表、转发服务和自动回复系统。

D.2.1 邮件列表

问题:

传统邮件列表保留原始 MAIL FROM:

原始: MAIL FROM:<[email protected]>
经过列表: MAIL FROM:<[email protected]>
发送 IP: list-server.mailinglist.org

SPF 检查:

查询 example.com 的 SPF 记录
检查 list-server.mailinglist.org 的 IP
结果: fail(IP 不在 example.com 的 SPF 记录中)

D.2.2 解决方案

方案 1: 重写 MAIL FROM(推荐)

重写后: MAIL FROM:<[email protected]>
Reply-To: [email protected]

优点:

  • SPF 检查通过
  • 退信返回到列表服务器
  • 接收方可以正确识别

缺点:

  • 改变了原始发件人信息
  • 用户需要适应 Reply-To

实现示例(Mailman):

# Mailman 配置
from_is_list = 2 # Munge From, add Reply-To

方案 2: 使用 SRS (Sender Rewriting Scheme)

SRS 是一种更复杂的重写方案:

SRS 格式:

SRS0=<hash>=<timestamp>=<domain>=<localpart>@<forwarder>

示例:
[email protected]

优点:

  • 保留原始发件人信息(在 local-part 中)
  • SPF 检查通过
  • 可以追踪和验证

缺点:

  • 实现复杂
  • 需要 SRS 数据库
  • local-part 变得难以阅读

方案 3: 使用 DKIM 而不依赖 SPF

配置:

1. 原始发件人使用 DKIM 签名
2. 列表服务器保留原始签名
3. 列表服务器添加自己的 DKIM 签名
4. 接收方验证 DKIM(忽略 SPF 失败)

DMARC 配置:

_dmarc.example.com IN TXT "v=DMARC1; p=none; adkim=r; aspf=r"
  • p=none: 不强制执行(允许 SPF 失败)
  • adkim=r: DKIM 宽松对齐(允许列表签名)

D.2.3 邮件转发服务

类型 1: 简单转发

用户配置: [email protected][email protected]
转发服务保持: MAIL FROM:<[email protected]>
从转发服务器的 IP 发送

SPF 问题:

Gmail 检查 original.com 的 SPF
转发服务器的 IP 不在 SPF 记录中
结果: fail

解决方案 A: SRS 重写

转发服务使用 SRS:
MAIL FROM:<[email protected]>

解决方案 B: 使用 ~all 而不是 -all

original.com IN TXT "v=spf1 mx ~all"

转发的邮件会得到 softfail 而不是 fail, 更可能被接受。

类型 2: .forward 文件

# ~/.forward
[email protected]

问题同简单转发

最佳实践:

1. 转发服务应该实施 SRS
2. 原始发件人应该使用 DKIM
3. 接收方应该考虑 DKIM 结果, 不仅仅依赖 SPF

D.2.4 自动回复和通知系统

问题:

原始邮件: [email protected][email protected]
自动回复: MAIL FROM:<[email protected]>
(从 company.com 的服务器发送)

SPF 检查会失败

解决方案:

使用空 MAIL FROM 发送通知:
MAIL FROM:<>
From: Mail Delivery System <[email protected]>

或者:

使用本地地址:
MAIL FROM:<[email protected]>
From: Automatic Reply <[email protected]>
Reply-To: [email protected]

D.3 Receiving ADMDs (接收 ADMD)

接收 ADMD 需要处理来自中介的邮件, 并做出适当的决策。

D.3.1 识别中介邮件

标识符:

1. Received 标头中的中间跳数
2. List-* 标头(邮件列表)
3. Precedence: bulk 或 list
4. SRS 格式的 MAIL FROM
5. DKIM 签名来自已知列表服务

示例检测逻辑:

def is_mailing_list(message):
# 检查 List-* 标头
list_headers = [
'List-Id', 'List-Post', 'List-Unsubscribe',
'List-Help', 'List-Subscribe', 'List-Owner'
]

for header in list_headers:
if message.get(header):
return True

# 检查 Precedence
if message.get('Precedence') in ['bulk', 'list']:
return True

# 检查 SRS
mail_from = message.get('Return-Path', '')
if mail_from.startswith('SRS0=') or mail_from.startswith('SRS1='):
return True

return False

D.3.2 策略建议

策略 1: 宽松对待列表邮件

if is_mailing_list(message):
if spf_result == 'fail':
# 检查 DKIM
if dkim_result == 'pass':
accept_message()
else:
# 检查列表声誉
if list_is_trusted(list_id):
accept_message()
else:
quarantine_message()

策略 2: 依赖 DMARC

if dmarc_result == 'pass':
accept_message()
elif spf_result == 'fail' and dkim_result == 'fail':
reject_message()
else:
# SPF 或 DKIM 之一通过
if is_mailing_list(message):
accept_message()
else:
apply_content_filtering()

策略 3: 用户特定规则

用户可以配置白名单:
- 信任的邮件列表
- 已知的转发地址
- 特定域的宽松处理

D.3.3 实现建议

SpamAssassin 配置:

# 对邮件列表宽松处理
header LIST_ID exists:List-Id
score LIST_ID -0.1

# SPF fail 但有 List-Id 标头
meta SPF_FAIL_LIST (SPF_FAIL && LIST_ID)
score SPF_FAIL_LIST 0.5

# 正常 SPF fail(无列表标头)
score SPF_FAIL 5.0

Postfix 配置:

# smtpd_recipient_restrictions
reject_unauth_destination,
check_policy_service unix:private/spf-policy,
permit

# SPF 策略服务可以识别列表邮件并相应调整

rspamd 配置:

-- SPF 模块配置
spf {
-- 对邮件列表应用不同的权重
symbol_fail = "R_SPF_FAIL";
symbol_softfail = "R_SPF_SOFTFAIL";

-- 自定义规则
custom_symbols = {
R_SPF_FAIL_LIST = {
score = 2.0,
description = "SPF failed but from mailing list",
condition = function(task)
local spf = task:get_symbol('R_SPF_FAIL')
local list_id = task:get_header('List-Id')
return spf and list_id
end
}
}
}

D.4 [互操作性建议]

D.4.1 标准化

使用标准标头:

邮件列表应该添加:
- List-Id: <list-name.domain.com>
- List-Post: <mailto:[email protected]>
- List-Unsubscribe: <mailto:[email protected]>
- Precedence: bulk

DKIM 签名:

列表服务器应该:
1. 保留原始 DKIM 签名(如果有)
2. 添加自己的 DKIM 签名
3. 不修改已签名的标头

D.4.2 通信

发件人通知:

列表服务应该通知订阅者:
- 邮件将从列表服务器重新发送
- MAIL FROM 将被重写
- 建议使用 Reply-To 回复列表

接收方文档:

记录接收方策略:
- 如何处理列表邮件
- 白名单机制
- 用户可配置的选项

D.5 [未来发展方向]

D.5.1 ARC (Authenticated Received Chain)

RFC 8617 引入了 ARC:

ARC 允许中介添加认证信息:
- ARC-Seal: 中介的签名
- ARC-Message-Signature: 消息签名
- ARC-Authentication-Results: 认证结果

示例:

ARC-Seal: i=1; a=rsa-sha256; t=1234567890; cv=none;
d=mailinglist.org; s=arc-seal; b=...
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed;
d=mailinglist.org; s=arc-msg; h=from:to:subject; b=...
ARC-Authentication-Results: i=1; mailinglist.org;
spf=pass [email protected];
dkim=pass header.d=example.com

优势:

  • 保留原始认证结果
  • 允许链式验证
  • 接收方可以信任中介

D.5.2 建议

对于新部署:

  1. 实施 DKIM 和 SPF
  2. 发布 DMARC 策略
  3. 考虑支持 ARC(如果是中介)
  4. 测试与常见邮件列表的互操作性

对于现有系统:

  1. 审查 SPF 策略的严格程度
  2. 监控 DMARC 报告
  3. 识别问题的来源(列表、转发等)
  4. 调整策略或实施 SRS