我正在尝试了解 Postfix 究竟如何处理电子邮件 - 以及 SMTP 邮件事务的一些细节。我的短期目标是调试专有(二进制、闭源)SMTP 客户端,但我首先想到的是检查成功的 SMTP 事务中会发生什么。
我计划在我们的 LAN 防火墙上阻止传出的 SMTP(端口 25),因此我将 Postfix 配置为内部邮件服务器,以接受来自(原始)本地客户端软件的邮件,该软件只能通过未经身份验证的 SMTP(通过端口 25)发送电子邮件。
smtpd
我通过附加-v
详细标志来打开 Postfix 进程的调试,master.cf
如中所述使用 Postfix 日志进行故障排除。然后我使用 Cygwin Mutt 从我自己的工作站发送了一封电子邮件SMTP协议(的最小实现sendmail
)。
Postfix 日志显示,在RCPT TO:
成功处理该行并且收件人地址可以接受后,Postfix 为该smtpd
事务分配了一个队列 ID,并使用 响应 SMTP 客户端(sSMTP)250 OK
。
但是,DATA
SMTP 客户端并没有发出命令,而是发出了RSET
重置/中止当前邮件事务的命令,而 Postfix 则回复了250 OK
。
我研究了一下这个命令的作用,不出所料,简单邮件传输协议,RFC 2821提供最全面的信息:
此命令指定将中止当前邮件事务。必须丢弃所有存储的发件人、收件人和邮件数据,并清除所有缓冲区和状态表。接收方必须向 RSET 命令发送不带参数的“250 OK”回复。客户端可以随时发出重置命令。如果在 EHLO 之后立即发出,在会话中发出 EHLO 之前发出,在发送和确认数据结束指示符之后发出,或在 QUIT 之前立即发出,则它实际上相当于 NOOP(即,如果它无效)。SMTP 服务器不得在收到 RSET 后关闭连接;该操作保留用于 QUIT(参见第 4.1.1.10 节)。
由于 EHLO 意味着服务器进行一些额外的处理和响应,因此 RSET 通常比重新发出该命令更有效,即使形式语义相同。
在某些情况下,与本规范的意图相反,SMTP 服务器可能会收到底层 TCP 连接已关闭或重置的指示。为了保持邮件系统的稳健性,SMTP 服务器应该为这种情况做好准备,并且应该将其视为在连接消失之前已收到 QUIT。
以上所有情况都在一秒钟之内发生,因此不应该出现超时问题。
在下一秒,客户端发送了另一个RSET
,但客户端随后等待了整整 10 秒才重新启动MAIL FROM:
,RCPT TO:
但这一次它会执行并发出DATA
命令并且事务完成(根据日志,所有这些都在同一秒内完成)。
本质上,我想知道为什么 SMTP 客户端会通过发出RSET
命令而不是DATA
命令来中断其自己的交易。
笔记:
我可以编辑问题以包含来自邮件日志文件的摘录,但通过调试
-v
,它们非常冗长,我不想用大量不相关的数据淹没人们。我搜索了 sSMTP 源代码,但没有发现任何提及
RSET
。
答案1
结论
我一直想知道为什么 SMTP 客户端会通过发出 RSET 命令而不是 DATA 命令来中断自己的事务。简而言之,它不会;这是 SMTP 连接被防病毒软件拦截的症状。
客户端日志
我在 sSMTP 的配置中启用了“调试”选项,但我花了一些时间才弄清楚如何在 Cygwin 中安装和配置 syslog,以便将来自 Cygwin 进程的消息记录到/var/log/messages
Windows 事件查看器中。
但是,它只记录了第一个MAIL FROM:
和第二个RCPT TO:
命令;没有迹象表明这些命令被发送了多次 – 或者曾经sSMTP
发送过RSET
命令。
正如我的问题中提到的,我检查了 sSMTP 源代码,但没有发送RSET
命令的代码。
赛门铁克拦截 SMTP 流量
用户 masegaloeh 表示,防病毒软件可能正在修改 SMTP 数据包——他是对的:我暂时禁用了赛门铁克端点保护在我的计算机上,SMTP 交易正常进行。
重新启用 Symantec Endpoint Protection 后,我使用TCP查看器实用工具Windows 系统内部我可以看到 SymantecccSvcHst.exe
进程正在代理所有目标端口为 25 的 TCP 流量。
我通过 telnet 连接到邮件服务器的 25 端口(netcat 无法正常工作,可能是由于 Symantec 拦截)以手动输入 SMTP 命令发送测试邮件。同时,我在运行时打开另一个终端窗口,通过 SSH 连接到邮件主机,以sudo tail -F /var/log/maillog
同时监控 SMTP 服务器看到的内容。
Symantec 代理执行的拦截非常隐蔽。从邮件客户端的角度来看,几乎没有迹象表明它没有直接与 SMTP 服务器通信。大多数命令在发送时都会传递到邮件服务器,并且响应符合您的预期。直到我输入命令后DATA
,Symantec 代理才开始改变情况:它响应如下:
354 Please start mail input.
这看起来很正常,但实际上,我的 Postfix 服务器的响应应该是
354 End data with <CR><LF>.<CR><LF>
DATA
另外:直到我完成邮件正文并在其后添加QUIT
.之后,它才真正将命令传递给 Postfix。
注意:当我输入测试消息的内容时,Symantec 代理通过发出NOOP
命令保持与 Postfix 服务器的连接。
处理有问题的 SMTP 客户端
我在问题中提到,我最终的目标是排除我所在组织使用的专有(二进制、闭源)邮件客户端的故障。我发现这个客户端确实存在问题:它发送了一个无效HELO
命令(没有任何主机名),然后在 SMTP 服务器礼貌地通知它其语法错误后,它就放弃并退出了——尽管我已将 Postfix 配置为不需要HELO
(有效或其他)。
我通过安装 CentOS 7 的新服务器解决了这个问题,该服务器附带的 Postfix 版本足够新,这样我就可以完全禁用 postfix HELO 检查(类似于 MS Exchange 如何简单地忽略无效的 HELO 命令)。
RSET 的一般用途
我也一直在想RSET
在 SMTP 事务中的一般用法,我在原始文件中找到了以下内容RFC 821对于 SMTP:
此命令指定要中止当前邮件事务。必须丢弃所有存储的发件人、收件人和邮件数据,并清除所有缓冲区和状态表。接收方必须发送 OK 回复。
RSET
如果收件人电子邮件地址不是现有用户,则将使用 SMTP 事务。以下 SMTP 事务是中止 SMTP 事务场景。
R: 220 MIT-Multics.ARPA Simple Mail Transfer Service Ready
S: HELO ISI-VAXA.ARPA
R: 250 MIT-Multics.ARPA
S: MAIL FROM:<[email protected]>
R: 250 OK
S: RCPT TO:<[email protected]>
R: 250 OK
S: RCPT TO:<[email protected]>
R: 550 No such user here
S: RSET
R: 250 OK
S: QUIT
R: 221 MIT-Multics.ARPA Service closing transmission channel
重复使用 SMTP 连接
SMTP 客户端可以使用同一个 SMTP 连接将多封邮件发送到同一个目的地。此功能称为SMTP 连接缓存Postfix 提供此功能。使用此性能功能时,Postfix 会RSET
在每条MAIL FROM
命令前发送一条消息,以验证 SMTP 连接是否仍然可用(请参阅Postfix 连接缓存)。