用 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 代理,并在生产环境中获得稳定可靠的运行效果。祝你部署顺利!
相关文章:
用 NGINX 构建高效 SMTP 代理`ngx_mail_smtp_module`
一、模块定位与作用 协议代理 NGINX 监听指定端口(如 25、587、465 等),接收客户端的 SMTP 会话请求。代理层在会话中透明转发客户端的 EHLO、MAIL FROM、RCPT TO、DATA 等命令到后端 MTA。 认证控制 通过 smtp_auth 指令指定允许的 SASL 认…...
【前端】常用组件的CSS
1. button的样式修改 每个环节有五个不同的状态:link,hover,active,focus和visited. Link是正常的外观,hover当你鼠标悬停时,active是单击它时的状态,focus跟随活动状态,visited是你在最近点击的链接未聚焦时结束的状态。 纯CSS 以下为例子,按下后从浅紫到深紫。注…...
【华为云学习与认证】以华为云物联网为基座的全栈开发(从物联网iot平台模块到应用展示、数据分析、机器学习、嵌入式开发等)的系统性学习与认证路线
总目标 学习以华为云物联网为基座的全栈开发(从物联网iot平台模块到应用展示、数据分析、机器学习、嵌入式开发等)的系统性学习与认证路线。计划包含阶段学习、技术文档、实操实际操作、开发路径与考证规划,提供职业生涯基础性规划。 注意&…...
OpenCV 键盘响应来切换图像
一、知识点 1、int waitKey(int delay 0); (1)、等待按键。 等待指定的毫秒数,返回按键的ASCII码。 (2)、返回值: int型,表示按键ASCII码。 若没有按键,指定时间过去,返回-1。 (3)、参数delay: 等待时间,单位毫…...

ARM SMMUv3简介(一)
1.概述 SMMU(System Memory Management Unit,系统内存管理单元)是ARM架构中用于管理设备访问系统内存的硬件模块。SMMU和MMU的功能类似,都是将虚拟地址转换成物理地址,不同的是MMU转换的虚拟地址来自CPU,S…...
C#提取CAN ASC文件时间戳:实现与性能优化
C#提取CAN ASC文件时间戳:实现与性能优化 在汽车电子和工业控制领域,CAN总线是最常用的通信协议之一。而ASC(ASCII)文件作为CAN总线数据的标准日志格式,广泛应用于数据记录和分析场景。本文将深入探讨如何高效地从CAN…...

hadoop集群datanode启动显示init failed,不能解析hostname
三个datanode集群,有一个总是起不起来。去查看log显示 Initialization failed for Block pool BP-1920852191-192.168.115.154-1749093939738 (Datanode Uuid 89d9df36-1c01-4f22-9905-517fee205a8e) service to node154/192.168.115.154:8020 Datanode denied com…...
Android 视图系统入门指南
1. View:界面的最小单位 本质:屏幕上的一个矩形区域,能显示内容或接收触摸。比喻:就像乐高积木,是组成界面的最小单位。常见子类: TextView(文字积木)、Button(按钮积木…...

浏览器工作原理05 [#] 渲染流程(上):HTML、CSS和JavaScript是如何变成页面的
引用 浏览器工作原理与实践 一、提出问题 在上一篇文章中我们介绍了导航相关的流程,那导航被提交后又会怎么样呢?就进入了渲染阶段。这个阶段很重要,了解其相关流程能让你“看透”页面是如何工作的,有了这些知识,你可…...
青少年编程与数学 01-011 系统软件简介 03 NetWare操作系统
青少年编程与数学 01-011 系统软件简介 03 NetWare操作系统 一、历史背景二、核心架构三、关键功能四、管理工具五、客户端支持六、版本演变七、衰落原因八、遗产与影响总结 摘要:NetWare 是早期网络操作系统的巅峰之作,其高性能文件服务、目录管理和容错…...
AI编程提示词
你是 IDE 的 AI 编程助手,遵循核心工作流(研究 -> 构思 -> 计划 -> 执行 -> 评审)用中文协助用户,面向专业程序员,交互应简洁专业,避免不必要解释。[沟通守则] 1. 响应以模式标签 [模式&#…...
Android学习总结-GetX库常见问题和解决方案
GetX库的常见问题 路由管理:Get.to() 后页面不跳转或卡顿? 问题: 明明调用了 Get.to(NextPage()),但页面没反应,或者感觉有延迟卡顿。这可能发生在较复杂的页面树或低端设备上。原因: …...

|从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面
🐑 |从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面 🐑 文章目录 🐑 |从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面 🐑♈前言♈♈调取Deepseek大模型♈♒准备工作♒♒调用API♒ ♈将模型嵌入到ui界面中♈♈…...
React 中 HTML 插入的全场景实践与安全指南
在 React 开发过程中,我们常常会遇到需要插入 HTML 内容的场景。比如将服务端返回的富文本渲染到页面,还有处理复杂的 UI 结构,正确的 HTML 插入方式不仅影响页面展示效果,更关乎应用的安全性。 本文将详细探讨 React 中插入 HTM…...
一键更新依赖全指南:Flutter、Node.js、Kotlin、Java、Go、Python 等主流语言全覆盖
在现代软件开发中,依赖项扮演着至关重要的角色。保持依赖的最新状态不仅可以获得新特性和性能优化,还能修复已知安全漏洞。但在不同语言和框架中,依赖管理的方式差异很大。本篇文章将系统性讲解如何在各主流语言中实现“一键更新依赖”。 &am…...
Java异步编程难题拆解技术
异步编程基础与核心概念 异步编程模型与同步模型的对比 Java中异步编程的常见场景(IO密集型、高并发任务等) 关键术语:Future、CompletableFuture、回调、事件循环 Java异步编程的核心API与框架 Future接口的局限性及基本用法 Completable…...
NoSQL 之 Redis 配置与优化
目录 一、 前置知识点 1. 关系数据库与非关系型数据库 (1)关系型数据库 (2)非关系型数据库 (3)非关系型数据库产生背景 (4)两者对比 2. Redis 基础 (1࿰…...

pikachu靶场通关笔记20 SQL注入03-搜索型注入(GET)
目录 一、SQL注入 二、搜索型注入 三、源码分析 1、渗透思路1 2、渗透思路2 四、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入百分号单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取…...

产品笔试专业名词梳理
目录 产品常识 四种常见广告形式 贴片广告 中插广告 信息流广告 横幅广告 BAT和TMD BAT TMD 付费渗透率 蓝海市场、红海市场 蓝海市场 红海市场 竞品研究 SWOT分析 SWOT分析的核心目的: SWOT分析的优点: SWOT分析的局限与注意事项&…...

【前端】es6相关,柯里化
0. 严格模式 严格模式的概念从ES6引进。通过严格模式,可以在函数内部选择进行较为严格的全局或局部的错误条件检测。 MDN中严格模式的描述 严格模式通过抛出错误来消除了一些原有静默错误严格模式修复了一些导致 JavaScript引擎难以执行优化的缺陷:有时…...

51单片机基础部分——矩阵按键检测
前言 上一节,我们说到了独立按键的检测以及使用,但是独立按键每一个按键都要对应一个IO口进行检测,在一些需要多按键的情况下,使用过多的独立按键会过多的占用单片机的IO资源,为了解决这个问题的出现,我们…...
onSaveInstanceState() 和 ViewModel 在数据保存能力差异
一、设计目标差异 维度onSaveInstanceState()ViewModel核心目的保存 瞬态 UI 状态(如用户输入、滚动位置),应对进程意外终止或配置变更。管理 业务逻辑相关数据,在配置变更时保留数据࿰…...

SpringBoot2.3.1集成Knife4j接口文档
首先要查看项目中pom文件里面有没有swagger和knife4j的依赖,如果有的话删除,加入以下依赖 <!-- swagger --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-spring-boot-starter</…...
Java Fork/Join框架:三大核心组件深度解析
ForkJoinTask、ForkJoinWorkerThread 和 ForkJoinPool 构成了 Java 中 Fork/Join 框架的三个核心组件,它们之间形成了紧密的协作关系,共同提供了高效的并行计算能力。 三者关系概述 ForkJoinPool:执行环境,管理工作线程和任务调…...
【envoy】-1.安装与下载源码
1.安装 建议使用ubuntu2004,对glibc有要求。上个ti子更快。 wget -O- https://apt.envoyproxy.io/signing.key | sudo gpg --dearmor -o /etc/apt/keyrings/envoy-keyring.gpg $ echo "deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/envo…...
B站的视频怎么下载下来——Best Video下载器
B站(哔哩哔哩)作为国内最受欢迎的视频平台之一,聚集了无数优质内容:动漫番剧、游戏实况、学习课程、纪录片、Vlog、鬼畜剪辑……总有那么些视频让人想反复观看、离线观看,甚至剪辑创作。 但你是否遇到过这样的烦恼&am…...
Mysql-定时删除数据库中的验证码
Moudle 1 使用调度器定时删除事件 数据库实现验证码自动删除的解决方案 -- 删除旧事件(如果存在) DROP EVENT IF EXISTS delete_expired_captchas;-- 创建新事件(每分钟执行一次) CREATE EVENT delete_expired_captchas ON SCHE…...

容器安全最佳实践:云原生环境下的零信任架构实施
📋 目录 引言:容器安全的重要性零信任架构基础理论云原生环境的安全挑战容器安全威胁模型分析零信任架构在容器环境中的实施关键技术组件与工具安全策略与最佳实践监控与响应机制案例研究与实施路径未来发展趋势 引言 随着容器技术和云原生架构的快速…...

[BIOS]VSCode zx-6000 编译问题
前提:Python 3.6.6及以上版本安装成功,Python 3.6.6路径加到了环境变量# DEVITS工具包准备好 问题:添加环境变量 1:出现环境变量错误,“py -3” is not installed or added to environment variables #先在C:\Windows里…...
MySQL连接报SSL错误
问题(cmd) C:\Users>mysql -h xx.xx.xx.xx -u root -p Enter password: ERROR 2026 (HY000): SSL connection error: error:0A000102:SSL routines::unsupported protocol 解决方案 1. 临时禁用 SSL 连接(不推荐生产环境使用࿰…...