当前位置: 首页 > news >正文

用 NGINX 构建高效 SMTP 代理`ngx_mail_smtp_module`

一、模块定位与作用

  1. 协议代理

    • NGINX 监听指定端口(如 25、587、465 等),接收客户端的 SMTP 会话请求。
    • 代理层在会话中透明转发客户端的 EHLO、MAIL FROM、RCPT TO、DATA 等命令到后端 MTA。
  2. 认证控制

    • 通过 smtp_auth 指令指定允许的 SASL 认证方式(例如 PLAINLOGINCRAM-MD5EXTERNAL);
    • 也可设置为 none,直接跳过代理层认证,让后端 MTA 完成验证。
  3. 功能协商(EHLO 扩展)

    • 使用 smtp_capabilities 定义代理层响应给客户端的 SMTP 扩展列表;
    • NGINX 会自动在扩展列表中添加 AUTH=...STARTTLS(若启用)等,使客户端知道可用功能。
  4. 性能与安全优化

    • smtp_client_buffer 控制读取客户端命令的缓冲区大小,避免大命令时分段造成性能抖动;
    • smtp_greeting_delay 可在发送 220 欢迎消息前加入延迟,用于拦截不等待问候就发送命令的恶意客户端。

二、核心指令详解

2.1 smtp_auth

smtp_auth method ...;

默认值smtp_auth plain login;
上下文mail, server

功能
  • 指定允许客户端使用的 SASL 身份验证机制。
  • 如果未包含 plainlogin,则 AUTH PLAINAUTH LOGIN 仍可执行,但不会自动列入 EHLO 扩展列表。
支持的认证方式
方法说明
plainAUTH PLAIN:客户端以 Base64 传输 \0username\0password。需 TLS 加密,否则存在明文风险。
loginAUTH LOGIN:分两步传输用户名与密码,也需 TLS 加密才能保证安全。
cram-md5AUTH CRAM-MD5:质询-响应式验证,后端需保存明文或可生成 MD5 摘要。更安全,但需后端支持。
externalAUTH 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 响应,并附加 AUTHSTARTTLS
上下文mail, server

功能
  • 定义 NGINX 代理在客户端 EHLO 响应中通告的 SMTP 扩展列表;
  • NGINX 会自动添加当前 smtp_auth 中定义的 AUTH=...,以及 STARTTLS(如果启用 starttls);
  • 建议将后端 MTA 实际支持的扩展在此列出,例如 SIZEPIPELINING8BITMIMEENHANCEDSTATUSCODES 等。
常见扩展选项
扩展含义
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-MD5smtp_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;}
}

核心解析

  1. Submission(587)与 SMTPS(465)并行

    • Submission:587 端口支持明文连接后升级到 TLS(starttls on;);
    • SMTPS:465 端口直接强制 TLS 加密,无需 STARTTLS
  2. 延迟问候

    • smtp_greeting_delay 2s;:在发送 220 example.com ESMTP 前等待 2 秒,以拦截不等待问候的恶意连接。
  3. 认证方式

    • smtp_auth plain login cram-md5;:允许 AUTH PLAINAUTH LOGINAUTH CRAM-MD5,保证兼容大多数客户端;
    • 若后端 MTA 支持客户端证书验证,可改用 smtp_auth external;
  4. 通告扩展

    • smtp_capabilities size pipelining 8bitmime enhancedstatuscodes dsn;:明确告诉客户端后端支持的功能;
    • NGINX 会自动在 EHLO 响应中加入 AUTH=PLAIN LOGIN CRAM-MD5 以及 STARTTLS
  5. 缓冲区与超时

    • smtp_client_buffer 8k;:保证一次性读取大部分 SMTP 命令,避免多次系统调用;
    • proxy_timeout 2m;:如果后端在 2 分钟内未响应,则关闭连接。
  6. 错误透传

    • proxy_pass_error_message on;:当后端返回错误(如认证失败、邮箱满等),直接将错误信息转发给客户端,方便客户端做相应处理。

四、最佳实践与注意事项

  1. TLS 与明文认证绝配

    • 当启用 plain/login,务必使用 TLS(Submission 或 SMTPS),否则用户名和密码会以 Base64 明文形式在网络中传输。
    • 可结合 ssl_verify_client on; 强制客户端出示证书并使用 smtp_auth external; 进行双向认证。
  2. 通告与后端保持一致

    • smtp_capabilities 中仅列出后端 MTA 真实支持的扩展;
    • 如果后端不支持 DSNENHANCEDSTATUSCODES,切勿在代理层通告,以免客户端发送不受支持的命令。
  3. 缓冲区大小调整

    • 默认 4k/8k 缓冲适配大多数场景;
    • 若观察到大型 AUTH PLAIN 字符串或大邮件标头导致分段读取,可将 smtp_client_buffer 调至 16k 或更高;
    • 注意内存占用与并发量的平衡。
  4. 延迟问候谨慎使用

    • smtp_greeting_delay 可拦截那些“不等待 220 就发命令”的垃圾邮件机器或探测脚本;
    • 但若延迟过长会让合法客户端感觉连通性不佳,一般设为 1s~3s 即可。
  5. 日志与调试

    • 通过 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 代理,并在生产环境中获得稳定可靠的运行效果。祝你部署顺利!

相关文章:

  • 数据库三范式设计---小白初学+案例引入
  • 数据分析实战2(Tableau)
  • SpringCloud-基于SpringAMQP实现消息队列
  • 矩阵分解相关知识点总结(二)
  • 使用 C/C++ 和 OpenCV 添加图片水印
  • 接IT方案编写(PPT/WORD)、业务架构设计、投标任务
  • DAY 21 常见的降维算法
  • OpenAI技术路线急转:从TypeScript到Rust的Codex CLI重构内幕
  • Spring WebFlux 整合AI大模型实现流式输出
  • Python-内置函数
  • MCP协议在LLM系统中的架构与实现原理研究
  • Cursor 集成 Figma MCP 实现阅读理解原型图生成方案
  • SQL Server相关的sql语句
  • PPT转图片拼贴工具 v2.0
  • 《EDA学习地图:从入门到进阶的通关秘籍》
  • [10-2]MPU6050简介 江协科技学习笔记(22个知识点)
  • Git的由来与应用详解:从Linux内核到现代开发的革命性工具
  • C++学习-入门到精通【14】标准库算法
  • AI应用工程师面试
  • Spring Boot 常用注解面试题深度解析
  • 大学生建设网站/网站关键词seo优化公司
  • 无经验可以做网站编辑吗/seo关键词优化是什么意思
  • django做的网站安全吗/营销型网站
  • 淄博微信网站建设/国外网站排行
  • 网站做的自适应体验差/品牌策划是做什么的
  • 本人找做钢筋笼的活网站/网络营销顾问招聘