术语 · SMTP 邮件协议

SMTP 邮件协议是什么?它对应用邮件有什么影响?

SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)是邮件系统用于提交、中继和移交外发邮件的标准协议。应用通常把一封组装好的邮件交给经过身份验证的提交服务;随后,邮件服务器使用 SMTP 命令和 DNS 路由把它传向每个收件人。SMTP 响应可以说明某一跳是接受还是拒绝了某个收件人,但被接受并不等于进入收件箱。应用仍然需要持久化队列、安全的重试、邮件标识符、身份验证和退信处理。

SMTP 在负责投递的系统之间传递邮件

SMTP 是一种存储转发式的传输协议。客户端与服务器建立会话,表明自己的身份,提供信封发件人,提出一个或多个信封收件人,并在服务器同意接收后传输邮件内容。服务器可以接受部分收件人而拒绝其他收件人,因此状态属于某个收件人和某次邮件事务,而不只属于整封邮件。服务器一旦接受了投递责任,就可以在本地投递,或者把邮件中继到通过 DNS 邮件交换(MX)记录选出的另一个系统。正是这种逐跳的设计,决定了应用不应把邮件状态简化为一个“已发送”布尔值。应用、提交服务、中继、收件服务器和邮箱过滤系统各自只掌握结果的一部分。SMTP 负责在系统之间传递邮件,而产品层的记录和服务商事件让用户和运维人员能够理解这一过程。

提交和中继是不同的协议角色

RFC 6409 将邮件提交与邮件中继区分开来。提交是指由获得授权的用户或应用向邮件提交代理(MSA)进行的第一次移交,通常使用 587 端口。中继是邮件传输代理(MTA)之间的传递,按惯例使用 25 端口。提交服务可以要求身份验证、校验或补全邮件字段,并执行发件人策略,因为它知道是谁在引入新邮件。公共中继服务器则必须与其他域名互通,遵循不同的信任规则。因此,应用代码应连接服务商文档中的提交端点或使用其 HTTP API,而不是随意与目标服务器建立 25 端口连接。这种划分也让凭据的含义更清晰:SMTP 用户名或令牌授权的是向某个特定服务提交邮件,并不赋予对目标域名的任何权限。请把提交凭据保存在服务器端,在服务商支持时将其作用域限定到发信工作负载,并在不嵌入邮件内容或客户端软件的前提下进行轮换。

SMTP 信封不同于可见的邮件头

SMTP 会话携带一个信封,其中包含 `MAIL FROM` 和一条或多条 `RCPT TO` 命令。传输的内容则单独遵循 RFC 5322 定义的互联网邮件格式,包含 From、To、Date、Subject 和 Message-ID 等字段以及正文。MIME 标准对这些内容进行了扩展,以支持 HTML、alternative 部件、附件和非 ASCII 数据。信封发件人是用于接收传输失败通知的地址,可以与可见的 From 作者不同。信封收件人也可能与可见的 To 和 Cc 字段不同,例如密送(Bcc)。不要通过拼接不可信的字符串来构造这些结构。请使用持续维护的邮件库,校验地址,阻止向邮件头字段注入换行符,并保持稳定的 Message-ID。排查问题时,请同时检查这两层:正确的可见 From 字段无法修复未经授权的信封身份,而有效的信封也不能让格式错误的 MIME 正确显示。

把会话当作状态机来理解

一个基本的扩展 SMTP(ESMTP)会话从服务器问候开始,然后客户端发送 `EHLO`,让服务器公布其支持的扩展。在提交场景中,客户端可以协商 TLS 和身份验证。随后的邮件会话依次使用 `MAIL FROM`、每个目标地址一条 `RCPT TO`、`DATA`、按照 SMTP 帧格式结束的完整邮件,以及 `QUIT`。不要因为这个示例就去手动实现线路协议;成熟的 SMTP 库能更安全地处理换行符、点透明、能力协商、身份验证和 TLS 状态。请在命令类别和响应码层面对库进行埋点,但不要记录凭据或完整的邮件正文。记录哪个收件人在哪个阶段失败,以及服务器在收到邮件数据后是否已接受投递责任。这个边界决定了是否适合重试、是否可能产生重复,以及失败会通过即时响应还是之后的投递状态通知来报告。

先对回复码分类,再决定是否重试

SMTP 回复类别传达了应采取的行动。2xx 响应表示该命令已成功完成。4xx 响应是暂时性的否定完成,因此排队的发送方可以在延迟后重试。5xx 响应表示所尝试的命令永久性否定完成,通常需要修正问题、加入抑制列表或进行人工调查,而不是反复重试。增强状态码为地址、邮箱、系统、路由、协议、内容或安全与策略等情况增加了结构化的 `X.Y.Z` 诊断。请同时保留数字状态码和服务器文本,因为两者都可能提供诊断价值,但不要大范围公开包含收件人数据的原始响应。对暂时性失败采用带抖动的指数退避,并设置最长队列存活时间。重试切勿过于激进,以免把目标方的暂时性问题变成滥发流量。对于永久性的地址失败,请停止向该目标地址自动发信并更新抑制状态。对于策略或身份验证失败,请先修正身份、DNS、凭据或内容,再进行下一次尝试。

使用加密且经过身份验证的提交方式

SMTP 最初是一种在信任假设各不相同的网络之间传输邮件的协议,因此安全提交依赖于扩展和部署策略。STARTTLS 可以把 SMTP 连接升级为 TLS,之后客户端必须丢弃在握手之前获得的能力信息,并重新发送 `EHLO`。RFC 8314 更新了提交方面的指导,将明文访问和明文提交视为已过时,并描述了用于提交的隐式 TLS。在 RFC 4954 中标准化的 SMTP AUTH,让提交服务器可以通过其公布的机制对客户端进行身份验证。请使用服务商当前给出的主机名、端口、TLS 模式和身份验证说明,而不是自行猜测组合。验证服务器证书,并且当工作负载要求受保护的提交时,不要悄悄回退到明文。把密码或令牌保存在机密信息管理器中,按环境使用不同的凭据,并禁用过时的身份验证机制。TLS 保护的是某一跳连接;它并不能向下游的每个收件方证明邮件作者的身份,也不能替代 SPF、DKIM 和 DMARC 的身份对齐。

逐跳诊断应用邮件故障

从应用持久化的出站记录开始:这个产品事件是否经过授权?是否只有一个排队任务认领了它?接着检查提交环节:DNS 解析、TCP 连接、TLS 协商、证书验证、身份验证、信封发件人授权、每个收件人的响应以及最终的 DATA 响应。如果提交服务已经受理了邮件,就不要再盲目重放请求,而应根据其邮件标识符和事件流进行跟踪。区分“服务商已处理”状态和“收件服务器已接收”状态。即使最初已被受理,之后的退信仍可能报告永久性失败。如果收件服务器已经接收了邮件,请调查身份验证结果、信誉、收件人策略、内容和邮箱分类,而不是把它称为 SMTP 传输故障。同时检查信封身份和邮件头身份,并保留时间戳、响应码、队列尝试次数和服务商标识符。测试时请使用受控的收件人。切勿把生产环境的 SMTP 凭据或完整的客户邮件粘贴到工单、提示词、终端历史或公开的诊断工具中。

区分受理、投递和进入收件箱

在产品界面中,协议层面的准确性很重要。应用受理表示本地系统记录了一个请求。提交受理表示第一个邮件服务接受了处理该邮件的责任。收件服务器投递表示目标 SMTP 服务器对这次移交返回了成功。进入收件箱则是收件环境内部之后做出的策略和分类决定。一封邮件可能通过了某个状态,却在下一个状态失败或被归入其他类别。SMTP 能为当前会话提供直接证据,也可能在之后产生投递状态通知,但它不会透露收件人最终的文件夹。请分别存储这些状态,而不是把每个 250 响应都标记为“已送达收件箱”。包含目标服务器 SMTP 成功响应的服务商事件,可以支持“已送达服务器”状态。退信可以支持失败处理或抑制处理。但两者都不能支持对可见性、阅读或互动的任何承诺。这个模型能让状态保持真实,并防止在投递责任已经转移之后进行不安全的重试。

使用 SendHQ 文档中说明的 API

应用可通过服务商库使用 SMTP,也可调用 HTTP 邮件 API,由其服务商在该接口之下处理 Internet 邮件传输。SendHQ 提供限定工作区作用域的邮件 API,包含已验证域名检查、出站和入站邮件资源、事件、抑制记录、收件箱及工作区资源边界。其 HTTP API 可与直接 SMTP 提交并行提供结构化请求、标识符和事件。它不会改变目标服务器行为,也不会确立 SMTP 受理、收件箱送达率或收件人互动。

常见问题

SMTP 是什么的缩写?

SMTP 是 Simple Mail Transfer Protocol(简单邮件传输协议)的缩写。它定义了邮件客户端和服务器如何通过命令、回复、信封、邮件数据以及身份验证和 TLS 等能力扩展来提交和传输外发邮件。

SMTP 用于从收件箱读取邮件吗?

不是。SMTP 主要用于提交和传输外发邮件。访问收件箱需要使用其他接口,例如 IMAP、POP、服务商专用的邮箱 API,或者提供已存储入站邮件的应用邮件 API。

25、587 和 465 端口有什么区别?

25 端口按惯例用于服务器之间的中继。587 端口是标准的邮件提交服务端口,通常会协商 TLS。465 端口注册用于基于隐式 TLS 的邮件提交。请遵循服务商文档中给出的端点和安全模式,而不是反复尝试更换端口。

SMTP 返回成功能证明邮件进入了收件箱吗?

不能。成功的回复只能证明响应的 SMTP 服务器接受了相应的命令或邮件投递责任。收件系统之后仍可能执行策略、生成延迟的失败通知,或将已接收的邮件归类到主收件箱之外。

应用应该重试每一个 4xx SMTP 响应吗?

4xx 状态码表示暂时性的否定结果,但重试应使用持久化队列、带抖动的指数退避、有限的存活时间以及按收件人计算的尝试次数上限。对于反复出现的暂时性失败,请进行调查,而不是无限期重试。

HTTP 邮件 API 能替代 SMTP 吗?

在应用代码中可以替代 SMTP,但服务商通常仍然使用 SMTP 与收件方邮件系统通信。API 在传输层之上增加了结构化的身份验证、请求体、资源作用域、标识符和事件处理。

参考来源