让我们假设一个典型的设置,其中从 sendmail 调用 procmail 以将传入的电子邮件过滤到正确的邮箱中。是在与 sendmail 的传入 SMTP 连接仍处于活动状态时完成,还是在电子邮件已被接受后完成?
如果是前者,那么我理解 procmail 可能会返回到 sendmail 一个错误,以便 sendmail 回复一个错误代码,例如554 Transaction failed
在接受SMTP DATA时,而不是通常的 200?
在我的例子中,sendmail 从别名数据库调用 procmail,条目如下:
theaddres: theaddres-somedomain-com.virtual
theaddres-somedomain-com.virtual: |"/usr/libexec/sm.bin/someuser.virtual somedomain@theaddress"
然后执行 procmail 脚本:
root@mda:/etc/mail # less /usr/libexec/sm.bin/someuser.virtual
/usr/local/bin/procmail -a $1 /usr/local/etc/procmailrc/someuser.virtual
编辑:
添加更详细的解释。首先,我想确定下面概述的基于维基百科示例的流程在 SMTP 协议中是否可行。如果是,那么是否可以使用 procmail。然后,如果没有(我猜是这种情况),是否存在可能的实现(例如 milter)。
S: 220 smtp.example.com ESMTP Postfix
C: HELO relay.example.org
S: 250 Hello relay.example.org, I am glad to meet you
C: MAIL FROM:<[email protected]>
S: 250 Ok
C: RCPT TO:<[email protected]>
S: 250 Ok
C: RCPT TO:<[email protected]>
S: 250 Ok
C: DATA
S: 354 End data with <CR><LF>.<CR><LF>
C: From: "Bob Example" <[email protected]>
C: To: "Alice Example" <[email protected]>
C: Cc: [email protected]
C: Date: Tue, 15 January 2008 16:02:43 -0500
C: Subject: Test message
C:
C: Hello Alice.
C: This is a test message with 5 header fields and 4 lines in the message body.
Now this is what I would like to see:
S (after receiving the first 2 lines out of 4): 452 Requested action not taken: insufficient system storage
C: QUIT
S: 221 Bye
{The server closes the connection}
因此,服务器停止接收电子邮件(例如,因为它在电子邮件中检测到序列“这是一条测试消息”)并用错误回复客户端。在这种情况下,它是 452,但它可能是响应DATA 请求的任何有效错误。客户可能会也可能不会回应 QUIT,我不在乎。
这可能取决于 SMTP 协议是如何在 TCP 级别实现的。我可以将从客户端接收到的数据量限制为 50 个初始字节(例如通过限制 TCP 帧的大小)吗?SMTP 协议是否允许我在客户端发送 DATA 内容时回复错误?
此外,如果服务器在接收到 DATA 的初始部分后故意断开连接(而不是尝试向客户端发送错误),则与传输电子邮件时 TCP 连接意外断开没有什么不同。表现良好的 MTA 会尝试重新连接并重新发送电子邮件,垃圾邮件发送者可能不会费心重试。
您所描述的完全可行,但在这种情况下 Sendmail会产生退回邮件;这是协议设计的一部分。这样做的方法是让 Procmail 中止并使用合适的退出代码,将退回原因传达回 Sendmail。
例如,要返回“用户未知”错误,
指定要退出的
EXITCODE
返回代码,重新分配HOST
具有立即放弃当前配方文件的模糊但有据可查的副作用。请参阅http://www.iki.fi/era/procmail/mini-faq.html#exitcode了解更多详细信息,例如
sysexits.h
实际退出代码的列表。这需要在您的个人
.procmailrc
中,而不是在/etc/procmailrc
您将无法控制是否在 SMTP 事务完成期间或之后发生这种情况。我记得当 Sendmail 仍然流行时,它实际上会在接收消息时处理 Procmail 规则,但这是一个可能取决于各种情况的实现细节,并且可能会在版本之间发生变化。无论哪种方式,SMTP 都是一种存储转发协议。如果交易失败并且客户端已经断开连接,服务器将尝试连接回发送者的 MX 服务器以传递退回邮件。(在某些情况下这是不可取的;例如,不应生成和传递退回的退回。)
无论哪种方式,为了让 Procmail 能够处理任何内容,您都需要已经收到整个消息;在这个后期阶段显式地失败 SMTP
DATA
事务是毫无意义的,因为您无法撤消接收。如果您想在完成后静默放弃消息DATA
,只需将其发送到/dev/null
.也就是说,尽早拒绝是有益的。如果您可以针对不良发件人实施 IP 级别的阻止,那么在网络堆栈上将更加简单和温和。(在我正在阅读“僵尸网络”的行之间——你知道这些发件人是否被例如 Spamhaus DNSBLs 阻止了吗?)
我认为 procmail 充当本地邮件程序,在电子邮件被接受后运行。基本上,这是交付的下一步。所以它不会影响正在接受电子邮件到 sendmail 进程的连接。当您在本地将电子邮件发送给另一个本地用户时,请考虑一个不同的示例。它首先被 sendmail 进程接受,如果其他本地用户丢失,您将收到另一封电子邮件的错误消息。
您是否考虑过使用 milter(例如 MIMEDefang.org milter)?
MIMEDefang 行为由可定制的 perl 脚本控制。应该可以根据消息内容在 smtp 会话中获得拒绝。它还将使解决方案可移植到其他 MTA,例如 postfix。
经典的 MIMEDefang 示例包括拒绝具有高 SpamAssassin(垃圾邮件)分数的邮件。它可能会单独阻止大多数此类电子邮件。