如何按 RFC 3463 增强状态码区分硬退与软退并分别处理?
RFC 3463 定义的增强状态码形如 class.subject.detail,三段均为十进制数字:
status-code = class "." subject "." detail
class = "2" / "4" / "5"
subject = 1*3digit
detail = 1*3digitclass 只有三种取值,其语义是整个退信处理逻辑的地基:
2.X.X成功——所请求的动作已成功完成。4.X.X持久性暂时失败(persistent transient failure)——规范的原话含义是:所发送的消息本身是有效的,只是某个临时状况的持续存在导致投递尝试被放弃或延迟。若该码出现在投递失败报告中,将来重发有可能成功。5.X.X永久失败——以当前形式重发不太可能解决问题;必须对消息本身或目标做出某种改变,投递才可能成功。
这两句定义就是「软退 / 硬退」唯一严谨的判据:4 = 软退,5 = 硬退。任何基于退信正文关键词的判定都是启发式近似,会随对端措辞变化而失效。
subject 给出失败的大类,是定位问题归属的关键。RFC 3463 定义了 0 至 7 共八类:
X.0.X其他或未定义状态X.1.X地址状态——与收件人或发件人地址本身相关X.2.X信箱状态——地址有效但信箱当前不可用X.3.X邮件系统状态——目标系统层面的问题X.4.X网络与路由状态——连接、DNS、路由、超时X.5.X邮件投递协议状态——SMTP 命令与协议交互层面X.6.X消息内容或媒体状态——内容、编码、转换X.7.X安全或策略状态——认证、授权、加密、策略拒绝
规范另有两条对解析器的重要约束:即使不认识 detail 所描述的细节,只要 subject 被识别就必须报告 subject;发送方实现无法确定具体细节时,detail 应取 0。这意味着一个健壮的退信解析器必须能在只识别到前两段时正常工作,并对未知 detail 优雅降级。RFC 5248 进一步为增强状态码建立了 IANA 注册表,新码通过注册扩展,因此「未见过的 detail」是常态而非异常。
结合 class 与 subject,可以把日常最高频的退信归入清晰的处置分支:
- 地址无效类(应移除):
X.1.1目标信箱地址错误、X.1.2目标系统地址错误、X.1.3目标信箱地址语法错误、X.1.6信箱已迁移且无转发地址。这些以 5 开头时指向地址本身不再有效。 - 信箱状态类(视 class 而定):
X.2.1信箱已禁用、不接收消息;X.2.2信箱已满;X.2.3消息长度超出管理限制。其中「信箱已满」在不同实现下既可能以 4 表达(等待用户清理)也可能以 5 表达(长期废弃),必须以实际收到的 class 为准,不能按 subject 一刀切。 - 系统与网络类(通常重试):
X.3.1邮件系统已满、X.4.1主机无应答、X.4.2连接质量差、X.4.5邮件系统拥塞、X.4.7投递时间已过期。 - 安全与策略类(不要当地址问题处理):
X.7.1投递未授权、消息被拒。这类拒绝几乎总是指向认证失败、信誉不足或策略命中,从名单里删掉这个收件人毫无帮助——正确动作是排查 SPF/DKIM/DMARC 与发送信誉。把 X.7.x 计入「无效地址」是可送达性统计中最常见的自欺。
增强状态码不取代 SMTP 基础三位回复码,而是对它的细化。RFC 5321 第 4.2.1 节规定了基础码首位数字的语义:2 表示肯定完成,3 表示肯定中间态,4 表示暂时性否定完成,5 表示永久性否定完成。RFC 3463 的 class 与之保持一致——一条 550 应答不可能携带 4.x.x 增强码。
工程含义很直接:第一判据永远是基础码首位数字,第二判据才是增强码的 subject 与 detail。当两者出现矛盾(存在实现缺陷的 MTA 会这样),应以基础码为准并单独告警,而不是静默采信其中之一。
退信正文的自然语言千差万别,正则匹配是不可维护的。正确做法是解析 RFC 3464 定义的投递状态通知(DSN)结构:报文为 multipart/report 且 report-type=delivery-status,其中 message/delivery-status 部分承载机器可读字段:
Action:取值为failed、delayed、delivered、relayed、expanded。这是判断「是否真的失败」的首要字段——delayed只是延迟通知,不应触发任何名单变更,而现实中大量系统把它误计为退信。Status:承载 RFC 3463 增强状态码。Diagnostic-Code:承载远端 MTA 返回的原始应答文本,用于人工排查与归因。Final-Recipient、Original-Recipient:确定这条状态对应哪个收件人,在一封信多收件人时不可或缺。Reporting-MTA、Remote-MTA、Last-Attempt-Date、Will-Retry-Until:定位报告来源与重试窗口。
解析顺序应为:先尝试 DSN 结构化字段 → 取不到再退化到 Diagnostic-Code 中的三位码 → 最后才考虑文本启发式,并对走到最后一步的样本单独记录,作为解析器改进的输入。
基于上述判据,可落地的处置规则是:
Action=failed且Status为5.1.x或5.2.1—— 地址无效或信箱禁用,立即从发送名单移除,不再重试。Action=failed且Status为5.7.x—— 策略或安全拒绝,保留地址,转入认证与信誉排查工单。Action=delayed—— 仅记录,不做任何名单变更。4.x.x—— 按 RFC 5321 第 4.5.4.1 节的重试策略处理:重试必须有延迟,一般不宜短于 30 分钟;放弃时间通常需要至少 4 至 5 天。持续软退的地址应先进入抑制列表观察,而不是直接删除。
需要特别说明的是:「连续几次软退后转硬退」这个次数,没有任何 RFC 或服务商官方文档给出规定值。它是各实现自定的运营参数,必须由自己的数据确定并留下决策依据,任何声称存在标准次数的说法都缺乏出处。
参考:IETF RFC 3463《Enhanced Mail System Status Codes》(Draft Standard,2003-01);注册表见 RFC 5248;退信报文格式见 RFC 3464;基础回复码见 RFC 5321
