SMTP Submission 协议深度解析 — RFC 6409 与 RFC 8314:端口 587/465 的投稿与加密演进

SMTP 协议从诞生之初(RFC 821, 1982)就未区分"终端用户投递"与"MTA 间中继"两个截然不同的场景。端口 25 承担了从 MUA 到 MTA、从 MTA 到 MTA 的所有角色。这种设计缺陷在 1990 年代末随着垃圾邮件的爆发而暴露——任何互联网上的主机都可以直接连接端口 25 投递邮件,MTA 无法有效区分合法用户的中继请求与第三方的滥发请求。RFC 2476(后被 RFC 4409 取代,RFC 4409 又被 RFC 6409 取代)提出了 Submission 端口的解决方案:一个专门用于 MUA → MSA 投稿的 SMTP 协议子集。它的核心创新是将「中继授权」从「邮件递送」中解耦。本文系统阐述 Submission 协议的设计演进、端口 587 与 465 的恩怨史,以及 Postfix 的完整部署配置。

1. MSA 与 MTA 的角色分离

RFC 6409 §2 明确定义了 Message Submission Agent (MSA) 的角色 [1]。MSA 与 MTA 的关键区别在于:

表1:MSA vs MTA 角色对比
属性MTA(端口 25)MSA(端口 587)
RFCRFC 5321 §2.3.8RFC 6409 §2
认证要求不强制(开放中继已禁用)MUST 要求 AUTH(RFC 4954)
连接来源对方 MTA(出站端口 25)终端用户 MUA
策略执行反垃圾/反病毒筛选合成检查(From/Date/Message-ID)、配额检查、域名验证
修改权限不得修改信头可自动补全缺失的信头
默认端口25587(STARTTLS)或 465(隐式 TLS)

MSA 通常位于网络边界内部(如公司内网),或通过 SMTP AUTH 接受来自外部的经过认证的连接。成功认证后,MSA 会将经过筛选和修订的邮件转发给同一台机器(或内网中)的 MTA,由 MTA 负责后续的 MX 路由和出站投递。

2. 端口 587 与 465 的演进

2.1 端口 587:RFC 6409 的标准 Submission 端口

RFC 6409 (2011) 将 Submission 端口标准化为 587,协议约束如下 [1]:

2.2 端口 465:隐式 TLS 的前世今生

端口 465 有一段曲折的历史。1997 年,多个邮件客户端供应商(Netscape、Microsoft、Eudora)非标准地注册了 smtps 端口 465,用于以隐式 TLS(Implicit TLS)模式封装整个 SMTP 会话——即建立 TCP 连接后立即开始 TLS 握手,而非 STARTTLS 式的协议升级 [2]。

1998 年,IANA 撤销了对 smtps 的端口分配,转为分配给 urd(一个未使用的协议)。但供应商实现已经固化——大量邮件客户端将 465 视为隐式 TLS submission 端口。这种事实标准与 IANA 官方分配之间的拉锯持续了整整 20 年。

2018 年,RFC 8314 正式承认了这一事实状态,按已实际用法的相反方向做出了明确裁决:不仅承认 465 为隐式 TLS 的 SMTP Submission 端口,还将隐式 TLS 列为 MUA→MTA 通信的推荐加密模式 [3]。

RFC 8314 的核心结论 [3, §3]:

3. RFC 6409 的 MSA 行为规范

3.1 信头处理规则

RFC 6409 §5 定义了 MSA 对 RFC 5322 信头的处理规则 [1]:

3.2 命令限制

Submission 场景下,MSA 不对以下 SMTP 扩展负责:

4. Postfix Submission 配置实战

4.1 端口 587(STARTTLS)配置

# /etc/postfix/master.cf
# submission 服务定义(端口 587)
submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_wrappermode=no
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=
      permit_sasl_authenticated,reject_unauth_destination
  -o milter_macro_daemon_name=ORIGINATING
  -o smtpd_client_connection_count_limit=10
  -o smtpd_client_message_rate_limit=60
  -o strict_rfc821_envelopes=yes

# SASL 配置
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes

4.2 端口 465(隐式 TLS)配置

# /etc/postfix/master.cf
# smtps 服务(端口 465,隐式 TLS)
smtps     inet  n       -       y       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=
      permit_sasl_authenticated,reject_unauth_destination
  -o milter_macro_daemon_name=ORIGINATING
  -o smtpd_client_connection_count_limit=10
  -o smtpd_client_message_rate_limit=60
  -o strict_rfc821_envelopes=yes

# master.cf 中 smtps 的 TLS 配置
# 隐式 TLS 无需 smtpd_tls_security_level=encrypt 或 may
# wrappermode=yes 自动接管 TLS

4.3 信头补全配置(现代 Postfix)

# 自动补全缺失的 Date、Message-ID 等信头
smtpd_header_checks = pcre:/etc/postfix/submission_header_checks

# /etc/postfix/submission_header_checks
/^Received:.*/                  IGNORE
/^$/ ADD Received: from [auth_user] with SUBMISSION (Postfix)
/^$/ ADD Date: <time>
/^$/ ADD Message-ID: <unique>

以上实现较为基础。更完整的信头补全可借助始终开启的 milter(如 OpenDKIM 和 OpenDMARC)实现。

5. 4444 端口与其他非标准端口

除了 587 和 465,部分服务商使用非标准端口(2525、4444、5870 等)作为 Submission 端口。这些端口主要用于以下场景:

非标准端口的使用建议:

6. Submission 场景的常见问题

6.1 认证失败

客户端端口 587 连接正常但发送邮件被拒:

# 日志定位
$ grep "submission" /var/log/mail.log | grep "SASL" | tail -5
postfix/submission[12345]: warning: SASL authentication failure:
  no mechanism available for user@example.com
postfix/submission[12345]: lost connection after AUTH from
  [192.0.2.1]

# 常见原因:
# 1. Dovecot SASL socket 权限问题
# 2. 客户端使用了不支持的认证机制(如 CRAM-MD5 但服务器未开启)
# 3. 密码中包含了 SMTP 协议的冲突字符(如空格、冒号)

# 排查
$ ls -la /var/spool/postfix/private/auth  # 确认 socket 存在且权限 666

6.2 中继拒绝

# submission 端口上的中继拒绝
postfix/submission[12346]: NOQUEUE: reject:
  RCPT from [192.0.2.1]:55545: 554 5.7.1 Relay access denied

# 检查 relay_restrictions 策略:
# permit_sasl_authenticated 必须在 reject 之前

6.3 TLS 版本不匹配

某些老旧客户端仅支持 TLS 1.0/1.1。RFC 8996 已弃用这两者,但如需兼容:

# 仅在 Submission 端口上同时启用 TLS 1.0/1.1/1.2/1.3
# 用于老旧客户端兼容
submission ... smtpd
  -o smtpd_tls_protocols=!SSLv2,!SSLv3

但强烈建议在兼容期过后立即移除 TLS <1.2 支持。

7. 隐式 TLS vs STARTTLS 的工程争议

RFC 8314 的发布在工程社区中引发了一场持续至今的辩论。STARTTLS 的优势在于端口号复用和渐进式升级——同一端口(587)可同时处理 TLS 和非 TLS 连接(虽然在 Submission 场景中必须要求 STARTTLS)。隐式 TLS 的优势在于协议栈清晰——一旦 TCP 连接建立,立即开始 TLS 握手,不存在 STRIPTLS 中间人攻击的可能 [2]。

IMAP 和 POP3 的隐式 TLS 端口(993/995)从 1990 年代起就一直稳定运行,RFC 8314 将同一模式应用到 SMTP Submission。目前主流邮件客户端的默认行为是:优先尝试 465(隐式 TLS),失败后回退到 587(STARTTLS)。Postfix 的双端口部署是最佳实践。

对于服务端引擎来说,隐式 TLS 的实现更简单——没有 STARTTLS 命令的解析阶段,TLS 状态机与 TCP 连接状态直接绑定。这减少了协议实现中因状态转换错误导致的安全漏洞。

参考文献

  1. IETF RFC 6409 (2011) — Message Submission for Mail, R. Gellens, J. Klensin
  2. IETF RFC 8314 (2018) — Cleartext Considered Obsolete: Use of TLS for Email Submission and Access, P. Hoffman, C. Newman
  3. IETF RFC 4954 (2007) — SMTP Service Extension for Authentication, R. Siemborski, A. Melnikov
  4. IETF RFC 5321 (2008) — Simple Mail Transfer Protocol, J. Klensin
  5. IETF RFC 8996 (2021) — Deprecating TLS 1.0 and TLS 1.1
  6. Postfix Documentation — SASL_README, https://www.postfix.org/SASL_README.html
  7. Postfix Documentation — master(5), https://www.postfix.org/master.5.html