用 NGINX 构建高效 SMTP 代理`ngx_mail_smtp_module`
一、模块定位与作用
-
协议代理
- NGINX 监听指定端口(如 25、587、465 等),接收客户端的 SMTP 会话请求。
- 代理层在会话中透明转发客户端的 EHLO、MAIL FROM、RCPT TO、DATA 等命令到后端 MTA。
-
认证控制
- 通过
smtp_auth
指令指定允许的 SASL 认证方式(例如PLAIN
、LOGIN
、CRAM-MD5
、EXTERNAL
); - 也可设置为
none
,直接跳过代理层认证,让后端 MTA 完成验证。
- 通过
-
功能协商(EHLO 扩展)
- 使用
smtp_capabilities
定义代理层响应给客户端的 SMTP 扩展列表; - NGINX 会自动在扩展列表中添加
AUTH=...
、STARTTLS
(若启用)等,使客户端知道可用功能。
- 使用
-
性能与安全优化
smtp_client_buffer
控制读取客户端命令的缓冲区大小,避免大命令时分段造成性能抖动;smtp_greeting_delay
可在发送 220 欢迎消息前加入延迟,用于拦截不等待问候就发送命令的恶意客户端。
二、核心指令详解
2.1 smtp_auth
smtp_auth method ...;
默认值:
smtp_auth plain login;
上下文:mail, server
功能
- 指定允许客户端使用的 SASL 身份验证机制。
- 如果未包含
plain
或login
,则AUTH PLAIN
与AUTH LOGIN
仍可执行,但不会自动列入EHLO
扩展列表。
支持的认证方式
方法 | 说明 |
---|---|
plain | AUTH PLAIN :客户端以 Base64 传输 \0username\0password 。需 TLS 加密,否则存在明文风险。 |
login | AUTH LOGIN :分两步传输用户名与密码,也需 TLS 加密才能保证安全。 |
cram-md5 | AUTH CRAM-MD5 :质询-响应式验证,后端需保存明文或可生成 MD5 摘要。更安全,但需后端支持。 |
external | AUTH EXTERNAL (1.11.6+):使用客户端 TLS 证书进行外部认证。 |
none | 禁用代理层认证,让后端 MTA 或其他机制处理身份验证;客户可直接继续后续 SMTP 对话。 |
示例
mail {server {listen 587; # SMTP Submission (STARTTLS)protocol smtp;# 只允许 AUTH PLAIN、AUTH LOGIN 和 AUTH CRAM-MD5smtp_auth plain login cram-md5;# 后端 MTA 地址proxy_pass smtp_backend:25;}
}
- 客户端在执行
EHLO example.com
后会看到250-AUTH PLAIN LOGIN CRAM-MD5
; - 如果用户发送
AUTH CRAM-MD5 <response>
,NGINX 会将验证请求转发到后端 MTA。
2.2 smtp_capabilities
smtp_capabilities extension ...;
默认值:无(若不配置,则仅显示后端默认 EHLO 响应,并附加
AUTH
和STARTTLS
)
上下文:mail, server
功能
- 定义 NGINX 代理在客户端
EHLO
响应中通告的 SMTP 扩展列表; - NGINX 会自动添加当前
smtp_auth
中定义的AUTH=...
,以及STARTTLS
(如果启用starttls
); - 建议将后端 MTA 实际支持的扩展在此列出,例如
SIZE
、PIPELINING
、8BITMIME
、ENHANCEDSTATUSCODES
等。
常见扩展选项
扩展 | 含义 |
---|---|
SIZE | 通告客户端最大邮件大小(如 SIZE 10485760 表示最大 10MB)。 |
PIPELINING | 支持 SMTP 管道式命令,允许一次发送多个命令减少网络往返。 |
8BITMIME | 支持 8 位传输编码(允许直接发送 8 位字符)。 |
ENHANCEDSTATUSCODES | 支持扩展状态码格式 250 2.1.0 OK ,提高错误信息的可读性。 |
DSN | 支持传输状态通知(Delivery Status Notification)。 |
STARTTLS | 支持在 587/25 端口上升级到 TLS 加密通道;若启用 starttls on; ,NGINX 会自动添加此扩展。 |
AUTH=PLAIN LOGIN CRAM-MD5 | 由 smtp_auth 自动补充,通知客户端可用的 SASL 机制。 |
示例
mail {server {listen 587; # SMTP Submissionprotocol smtp;# 启用 STARTTLSstarttls on;# 允许 PLAIN、LOGIN、CRAM-MD5 三种认证方式smtp_auth plain login cram-md5;# 明确通告客户端支持的扩展;NGINX 会自动附加 AUTH 和 STARTTLSsmtp_capabilities SIZE PIPELINING 8BITMIME ENHANCEDSTATUSCODES DSN;proxy_pass smtp_backend:25;}
}
-
客户端
EHLO mail.example.com
时,NGINX 返回:250-mail.example.com Hello [192.0.2.1] 250-SIZE 250-PIPELINING 250-8BITMIME 250-ENHANCEDSTATUSCODES 250-DSN 250-AUTH PLAIN LOGIN CRAM-MD5 250-STARTTLS 250 HELP
2.3 smtp_client_buffer
smtp_client_buffer size;
默认值:与系统内存页大小相当(4K 或 8K)
上下文:mail, server
功能
- 指定 NGINX 在读取客户端发送的 SMTP 命令时所使用的缓冲区大小;
- 当客户端发出长字符串、Base64 编码凭证或大型邮件头时,可能超过默认缓冲区,需要适当放大;
- 过小会导致分段读取、性能抖动;过大则占用更多内存。
示例
mail {server {listen 25; # 普通 SMTPprotocol smtp;# 将缓冲区增大到 16K,以一次性消费大型输入smtp_client_buffer 16k;smtp_auth plain login;smtp_capabilities SIZE PIPELINING 8BITMIME;proxy_pass smtp_backend:25;}
}
- 当客户端发送长
AUTH PLAIN <base64-credentials>
时,16K 缓冲可一次读取完整凭证,避免折行或多次读取增加延迟。
2.4 smtp_greeting_delay
smtp_greeting_delay time;
默认值:
0
(无延迟)
上下文:mail, server
功能
- 在向客户端发送 SMTP 220 欢迎消息之前延迟指定时间;
- 主要用于防御“恶意客户端”或“探测脚本”——它们可能不会等待 220,再立刻发送
EHLO
或其他命令; - 若客户端在延迟期内提前发送命令,NGINX 可以直接拒绝或丢弃连接,节省后端资源。
示例
mail {server {listen 25;protocol smtp;# 在发送 220 欢迎前延迟 3 秒smtp_greeting_delay 3s;smtp_auth plain;smtp_capabilities SIZE PIPELINING;proxy_pass smtp_backend:25;}
}
- 攻击脚本若不等待延迟直接发命令,将收到连接重置或拒绝;
- 合法客户端会在 3 秒后收到标准 220 欢迎并继续会话。
三、综合示例:部署 SMTP 代理(Submission 与 SMTPS)
下面给出一个完整的生产环境示例,包含 Submission(587)和 SMTPS(465)两种监听方式,以及启动 STARTTLS、SASL 认证、协议扩展等配置。
worker_processes auto;
events { worker_connections 2048; }mail {# 全局缓冲区,可根据实际负载调整smtp_client_buffer 8k;# 587 端口:支持 STARTTLSserver {listen 587; # Submissionprotocol smtp;starttls on; # 启用 STARTTLS# 在发送 220 欢迎前延迟 2 秒,拦截恶意探测smtp_greeting_delay 2s;# 允许明文登录(PLAIN/LOGIN)及质询式 CRAM-MD5smtp_auth plain login cram-md5;# 声明支持的扩展;NGINX 会自动附加 AUTH=PLAIN LOGIN CRAM-MD5 和 STARTTLSsmtp_capabilities SIZE PIPELINING 8BITMIME ENHANCEDSTATUSCODES DSN;# 转发到后端 MTAproxy_pass smtp_backend:25;proxy_timeout 2m;proxy_pass_error_message on;}# 465 端口:直接 SMTPS(TLS 加密)server {listen 465 ssl; # SMTPSprotocol smtp;# 无需 STARTTLS,因为连接一开始即为 TLSsmtp_auth plain login cram-md5;smtp_capabilities SIZE PIPELINING 8BITMIME ENHANCEDSTATUSCODES DSN;# TLS 配置ssl_certificate /etc/nginx/ssl/smtp.crt;ssl_certificate_key /etc/nginx/ssl/smtp.key;ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers HIGH:!aNULL:!MD5;ssl_session_cache shared:mail_ssl:10m;ssl_session_timeout 10m;proxy_pass smtp_backend:25;proxy_timeout 2m;proxy_pass_error_message on;}
}
核心解析
-
Submission(587)与 SMTPS(465)并行
- Submission:587 端口支持明文连接后升级到 TLS(
starttls on;
); - SMTPS:465 端口直接强制 TLS 加密,无需
STARTTLS
。
- Submission:587 端口支持明文连接后升级到 TLS(
-
延迟问候
smtp_greeting_delay 2s;
:在发送220 example.com ESMTP
前等待 2 秒,以拦截不等待问候的恶意连接。
-
认证方式
smtp_auth plain login cram-md5;
:允许AUTH PLAIN
、AUTH LOGIN
、AUTH CRAM-MD5
,保证兼容大多数客户端;- 若后端 MTA 支持客户端证书验证,可改用
smtp_auth external;
。
-
通告扩展
smtp_capabilities size pipelining 8bitmime enhancedstatuscodes dsn;
:明确告诉客户端后端支持的功能;- NGINX 会自动在 EHLO 响应中加入
AUTH=PLAIN LOGIN CRAM-MD5
以及STARTTLS
。
-
缓冲区与超时
smtp_client_buffer 8k;
:保证一次性读取大部分 SMTP 命令,避免多次系统调用;proxy_timeout 2m;
:如果后端在 2 分钟内未响应,则关闭连接。
-
错误透传
proxy_pass_error_message on;
:当后端返回错误(如认证失败、邮箱满等),直接将错误信息转发给客户端,方便客户端做相应处理。
四、最佳实践与注意事项
-
TLS 与明文认证绝配
- 当启用
plain
/login
,务必使用 TLS(Submission 或 SMTPS),否则用户名和密码会以 Base64 明文形式在网络中传输。 - 可结合
ssl_verify_client on;
强制客户端出示证书并使用smtp_auth external;
进行双向认证。
- 当启用
-
通告与后端保持一致
- 在
smtp_capabilities
中仅列出后端 MTA 真实支持的扩展; - 如果后端不支持
DSN
或ENHANCEDSTATUSCODES
,切勿在代理层通告,以免客户端发送不受支持的命令。
- 在
-
缓冲区大小调整
- 默认
4k/8k
缓冲适配大多数场景; - 若观察到大型
AUTH PLAIN
字符串或大邮件标头导致分段读取,可将smtp_client_buffer
调至16k
或更高; - 注意内存占用与并发量的平衡。
- 默认
-
延迟问候谨慎使用
smtp_greeting_delay
可拦截那些“不等待 220 就发命令”的垃圾邮件机器或探测脚本;- 但若延迟过长会让合法客户端感觉连通性不佳,一般设为
1s
~3s
即可。
-
日志与调试
- 通过
mail_log
记录 SMTP 会话关键日志(认证成功/失败、邮件投递状态等); - 通过
error_log
捕获代理层错误与连接异常。 - 在调试阶段,可将
proxy_pass_error_message on;
打开,观察后端具体的错误响应。
- 通过
五、总结
ngx_mail_smtp_module
为 NGINX 增加了强大的 SMTP 代理能力,让你能够:
- 灵活控制 SASL 认证方式(PLAIN、LOGIN、CRAM-MD5、EXTERNAL 或跳过),
- 自定义 EHLO 扩展通告,与后端 MTA 完美协同,
- 优化客户端缓冲与超时,提升并发与稳定性,
- 通过问候延迟拦截恶意探测,减少垃圾邮件源头连接。
结合 NGINX 在并发、TLS 加速与日志收集方面的优势,你可以轻松搭建安全、高效且易于扩展的 SMTP 代理网关,为企业级邮件系统保驾护航。希望本文的指令详解与配置示例,能够帮助你快速上线 SMTP 代理,并在生产环境中获得稳定可靠的运行效果。祝你部署顺利!