让我们假设一个典型的设置,即从 sendmail 调用 procmail 来将传入的电子邮件过滤到正确的邮箱中。这是在到 sendmail 的传入 SMTP 连接仍然处于活动状态时完成的,还是在电子邮件已被接受后完成的?
如果是前者,那么我理解 procmail 可能会向 sendmail 返回一个错误,以便 sendmail 回复一个错误代码,例如554 Transaction failed
在接受SMTP 数据,而不是通常的 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,但它可能是响应以下错误的任何有效错误:数据请求。客户端可能会也可能不会回应QUIT,我不在乎。
这可能取决于 SMTP 协议在 TCP 层上的实现方式。我是否可以将从客户端接收的数据量限制为 50 个初始字节(例如通过限制 TCP 帧的大小)?SMTP 协议是否允许我在客户端发送数据内容时回复错误?
此外,如果服务器在收到 DATA 的初始部分后故意断开连接(而不是尝试向客户端发送错误),这与在传输电子邮件时意外断开 TCP 连接没有什么不同。行为良好的 MTA 会尝试重新连接并重新发送电子邮件,而垃圾邮件发送者可能不会费心重试。
答案1
你所描述的是完全可行的,但是 Sendmail将要在这种情况下产生退回消息;这是协议设计的一部分。这样做的方法是让 Procmail 使用合适的退出代码中止,将退回原因传达回 Sendmail。
例如,要返回“用户未知”错误,
:0
* ^Received: from badhelo \(badhost \[10\.9\.8\.7\]\) by yourhost
{ EXITCODE=67 HOST= }
指定EXITCODE
使用哪个返回代码退出,重新分配HOST
具有不明显但有据可查的副作用,即立即放弃当前的配方文件。
看http://www.iki.fi/era/procmail/mini-faq.html#exitcode更多详细信息,例如sysexits.h
获取实际退出代码的列表。
这需要在你的个人.procmailrc
,而不是/etc/procmailrc
您无法控制这种情况是在 SMTP 事务完成期间还是之后发生。我记得当 Sendmail 仍然流行时,它实际上会在接收消息时处理 Procmail 规则,但这是一个实现细节,可能取决于各种情况,并且可能因版本而异。无论哪种方式,SMTP 都是存储转发协议;如果事务失败并且客户端已经断开连接,服务器将尝试重新连接到发件人的 MX 服务器以传送退回邮件。(有些情况下这是不可取的;例如,不应生成和传送退回邮件的退回邮件。)
无论如何,为了让 Procmail 能够处理任何内容,您需要已经收到整个消息;DATA
在这个后期阶段明确地使 SMTP 事务失败是毫无意义的,因为您无法撤消接收。如果您想在DATA
完成后默默地放弃一条消息,只需将其发送到 即可/dev/null
。
话虽如此,尽早拒绝还是有好处的。如果您可以针对不良发件人实施 IP 级阻止,那么这对网络堆栈来说会简单得多,也更温和。(在字里行间,我读到“僵尸网络”——您知道这些发件人是否被 Spamhaus DNSBL 阻止了吗?)
答案2
我认为 procmail 充当本地邮件程序,在电子邮件被接受后运行。基本上,它是传递的下一步。因此它不会影响正在接受电子邮件到 sendmail 进程的连接。考虑一个不同的例子,当您在本地将电子邮件发送给另一个本地用户时。它首先被 sendmail 进程接受,如果另一个本地用户丢失,您将通过另一封电子邮件收到错误消息。
答案3
您是否考虑过使用 milter(例如 MIMEDefang.org milter)?
MIMEDefang 行为由可自定义的 perl scrip 控制。应该可以根据邮件内容在 smtp 会话中获取拒绝信息。它还将使解决方案可移植到其他 MTA,例如 postfix。
经典的 MIMEDefang 示例包括拒绝 SpamAssassin (spamines) 分数较高的邮件。它本身就可以阻止大多数此类电子邮件。