一问一答的文本协议
SMTP 是邮件传输的通用语言,建立在 TCP 之上的文本行协议:客户端发一条命令,服务器回一条应答,每一行都以回车换行结束。服务器之间传信用 25 端口,客户端提交邮件常用 587(STARTTLS)或 465(隐式 TLS)。应答由三位数字加说明文字组成,第一位数字表示结果类别:2xx 成功、3xx 需要继续输入、4xx 临时失败可重试、5xx 永久失败不应重试。
基本信息
| 交互模型 | 请求应答式,一问一答,命令行与应答行都以回车换行结束 |
|---|---|
| 应答格式 | 三位数字状态码加可读文本,例如 250 OK |
| 多行应答 | 状态码后跟连字符表示还有下一行,最后一行用空格分隔 |
| 正文编码 | 默认 7bit ASCII,发送 UTF-8 内容需要服务端支持 SMTPUTF8 扩展 |
| 常用端口 | 服务器间用 25;客户端提交用 587 配 STARTTLS,或 465 隐式 TLS |
| 身份校验 | 提交阶段需要认证,收信服务器之间靠 SPF、DKIM、DMARC 判断身份 |
最小一发与应答
最小一发与应答
220 mail.example.com ESMTP ready # 服务端就绪
EHLO client.example.com # 打招呼并获取扩展能力列表
250-mail.example.com # 多行应答:250 后跟连字符表示还有下一行
MAIL FROM:<a@example.com> # 声明发件人,得到 250 才继续
RCPT TO:<b@example.net> # 声明收件人,收件人不存在时回 550
DATA # 服务端回 354,开始输入正文
Subject: hi
hello
. # 单独一行英文句点表示正文结束
250 OK: queued as 4A1B2C # 已入队,注意这只代表已接收
QUIT应答码读法
| 应答码 | 含义 | 处理方式 |
|---|---|---|
| 220 | 服务就绪 | 连接成功,可以开始发命令 |
| 250 | 命令被接受 | 继续下一步;提交结束时表示已入队 |
| 354 | 可以开始输入正文 | DATA 之后的正常应答 |
| 421 | 服务不可用,即将关闭连接 | 稍后重试,通常伴随限流或维护 |
| 450 与 451 与 452 | 临时失败,如邮箱忙或磁盘暂时不足 | 可以退避后重试 |
| 550 与 551 与 553 | 永久失败,如收件人不存在 | 不要重试,直接生成退信 |
SMTP 只保证把邮件交给对方的 MTA 或者本地投递代理,用户最终在哪台信箱里看到由收件方系统决定。日志里的 queued 表示已接收,不等于已送达。
SMTP 命令关键字大小写不敏感,但邮箱地址的本地部分理论上可能区分大小写,自动化脚本应当原样透传地址,不要做统一转小写之类的处理。