SMTP 各命令的超时应该设成多少?投递卡住怎么按超时定位?
RFC 5321 §4.5.3.2 对客户端提出了强制要求:SMTP 客户端必须提供超时机制,并且必须使用逐命令超时,而不是设法给整个邮件事务计时。实现方式是为每一条 SMTP 命令、以及数据传输的每一个缓冲区分别设置定时器。
规范同时解释了这样设计的原因:按缓冲区计时意味着整体超时天然与报文大小成正比。一封几十兆的附件邮件本来就需要更长的传输时间,如果用一个固定的事务总超时去卡它,大邮件会被系统性地误杀,而小邮件在某个阶段真正卡死时又迟迟不被发现。
规范还要求超时应当易于重新配置,最好不需要重新编译。这条常被忽视,但它在故障处置时价值极高——面对一个响应缓慢的对端,能否在不重启服务的前提下临时调整超时,直接决定了故障处置的手段空间。
RFC 5321 基于繁忙邮件中继主机的大量实践经验,给出了逐命令超时的最小建议值:
- 初始 220 问候:5 分钟。客户端需要区分「TCP 连接失败」与「连接已建立但服务端延迟发送 220」两种情况。许多 SMTP 服务端会先接受 TCP 连接,再等到系统负载允许时才送出 220。
- MAIL 命令:5 分钟。
- RCPT 命令:5 分钟。规范特别注明:如果邮件列表与别名的展开处理没有推迟到报文被接受之后,这一阶段就需要更长的超时。
- DATA 起始:2 分钟。这是等待 DATA 命令的「354 Start Input」响应的时间。
- 数据块:3 分钟。这是等待每一次 TCP 发送调用完成的时间。
- DATA 终止:10 分钟。这是发出结束标记后等待「250 OK」的时间,是全部阶段中最长的。
- 服务端超时:至少 5 分钟。SMTP 服务端在等待发送方的下一条命令时应当有至少 5 分钟的超时。
注意这些是最小值,不是推荐值也不是上限。把任何一项调到比它更短,都是在偏离规范,其后果是可预期的:与处理较慢但完全合规的对端之间产生间歇性投递失败。
10 分钟这个值在七项里格外突出,RFC 5321 给出了明确的理由,而这个理由正是排错时最需要理解的一环。
当接收方收到报文数据的最后一个句点时,它通常要执行一系列处理才能把邮件投进用户信箱——写入存储、更新索引、执行过滤规则、触发钩子。这一刻发生的超时代价极大:报文其实已经成功送达,服务端也已经承担了投递责任,只是那句 250 还没回来。发送方如果此时超时并重试,结果就是收件人收到多份重复邮件。
由此得到一条重要的运维判据:用户报告「同一封邮件收到好几份」时,应当优先怀疑 DATA 终止阶段的超时被调短了,或者接收侧的落盘处理慢于发送侧的等待时间,而不是先去怀疑发送程序循环发送。检查方向是发送侧的 DATA 终止超时设置,以及接收侧在最终句点之后的处理耗时。
把超时按阶段拆开的最大收益,是让「投递卡住」这个模糊现象变成可定位的问题。日志里记录的是哪个阶段超时,指向的原因就完全不同:
- 卡在初始 220:对端在接受 TCP 连接后迟迟不问候。常见于对端过载、对端有意做延迟问候式的反垃圾策略,或链路上有设备完成了 TCP 握手却没有真正转发数据。先用
telnet或openssl s_client手工连一次,确认是 TCP 层不通还是应用层不应答。 - 卡在 RCPT:对端在收件人校验上耗时过长。典型原因是同步查询目录服务、同步展开邮件列表、或对每个收件人做实时的外部信誉查询。发往同一对端的多收件人邮件更容易触发。
- 卡在数据块:链路吞吐问题。检查路径 MTU、TCP 窗口、中间设备的流量整形,以及是否有内容检测设备在做全量缓冲。
- 卡在 DATA 终止:见上一节,接收侧落盘或后处理慢。
- TLS 握手期间卡住:注意 RFC 3207 的规定——TLS 握手完成后 SMTP 协议状态复位到服务端刚发出 220 问候后的初始状态,双方必须丢弃握手前获得的全部信息,客户端需要重新发起 EHLO。因此「STARTTLS 之后的第一次 EHLO 超时」与「首次 EHLO 超时」是两个不同的故障点,日志里必须能区分。
- 不要为了「快速失败」而全线调短。超时的作用是在对端确实无响应时释放资源,不是用来提升投递速度的。全线调短的直接后果是与慢速合规对端之间产生间歇性失败,而这类失败在监控上表现为随机抖动,极难归因。
- 可以针对特定对端单独放宽。多数 MTA 支持按目标域设置传输参数。对已知处理较慢的对端单独放宽,比全局放宽更安全。
- 把超时与重试策略一起考虑。RFC 5321 §4.5.4 讨论了重试策略,其要点是重试间隔应当随尝试次数增长,且需要为报文设定一个总的放弃时限。超时过短会让本可成功的投递进入重试队列,而重试放大又会加重对端负载,形成恶性循环。
- 为每个阶段单独打点。日志里只写「投递超时」等于没写。至少要记录:目标主机、超时发生在哪个阶段、该阶段实际等待了多久、该报文此前已重试几次。这四项齐备,绝大多数投递故障可以在一次查询内定位。
- 变更后做回归验证。调整超时属于影响面很广的改动,应在变更后观察一个完整的业务周期,重点看重复投递、退信率与队列深度三项指标的走向。
参考:RFC 5321《Simple Mail Transfer Protocol》§4.5.3.2 Timeouts、§4.5.4 Retry Strategies、§6.1,J. Klensin,2008 年 10 月,Standards Track,DOI 10.17487/RFC5321,https://www.rfc-editor.org/rfc/rfc5321.html ;RFC 1123《Requirements for Internet Hosts - Application and Support》,R. Braden 编,1989 年 10 月,STD 3,https://www.rfc-editor.org/rfc/rfc1123.html ;RFC 3207《SMTP Service Extension for Secure SMTP over Transport Layer Security》,P. Hoffman,2002 年 2 月,https://www.rfc-editor.org/rfc/rfc3207.html ;RFC 3463《Enhanced Mail System Status Codes》,G. Vaudreuil,2003 年 1 月,https://www.rfc-editor.org/rfc/rfc3463.html
