通过我的服务器的部分电子邮件被转发到外部账户。
不幸的是,我的上游 SMTP 服务器对垃圾邮件非常挑剔——并拒绝一些合法邮件。当转发的邮件发生这种情况时,我会收到退回邮件(作为邮件管理员)——而不是发件人。
我理解,这是因为 sendmail 在本地对消息进行排队,断开与中继的连接,然后才继续转发它们。如果进一步的转发因任何原因中断(例如,下一个中继将消息误认为垃圾邮件),我的 sendmail 就只能保留这些碎片。
是否可以配置以便开始转发立即地(一旦确定了转发目的地)?状态——成功或失败——可以直接传达给上一个中继仍在线上...
如果 sendmail 无法做到这一点,其他 MTA 可以吗?谢谢!
答案1
不,这是不可能的,因为它没有在任何广泛使用的 SMTP 软件中实现;你必须编写自己的支持这种行为的 SMTP 服务器,这超出了 Serverfault 的范围。在这个答案中,我解释了为什么所有 MTA 都以非常相似的方式(使用队列)实现了 SMTP 协议,以及为什么这是实现协议所有要求的最佳方式。
A邮件传输代理MTA 总是根据自己的设置拒绝或接受邮件并将其放入队列。然后,该邮件将被中继或从队列中投递。
那是因为
可能存在永久性错误和暂时性错误。如果 MTA 无法立即连接下一跳,它将稍后重试,并且只有当延迟达到设置的限制时才会反弹。它也不能等待另一个 MTA 响应后再关闭连接,因为它可能还有其他消息要先传递。
可以有多个收件人。虽然客户端可以简单地使用
RCPT TO
命令一次列出所有收件人,但邮件最终可能会被发送到其他几台服务器,其中一些服务器现在可用,一些服务器稍后可用。此外,MTA 无法在初始连接期间一次打开所有这些连接并等待它们的响应。对于只有一个收件人的邮件,没有实际理由采用完全不同的工作流程。应该始终清楚哪个 MTA 当前负责传递消息。(MadHatter 的回答中的示例已对此进行了解释。)
SMTP 就是这样设计的。与连接命令的语法要求不同,这导致了非常相似的架构;发送邮件,后缀乃至微软 Exchange具有用于发送和接收邮件的单独组件。
- SMTP 服务器组件接收邮件并将其添加到队列。
- 然后,单独的 SMTP 客户端尝试将其进一步发送到其他 MTA,或者如果收件人是本地的,则可以将邮件保存到文件中或传递给邮件投递代理MDA,例如 Procmail。
该要求仍然来自SMTP规范;RFC 5321 2.1 关于SMTP模型基本结构:
功能齐全的 SMTP 实现(包括这些功能较差的实现所使用的中继及其目的地)应支持本规范中讨论的所有排队、重试和备用地址功能。在许多情况和配置中,上面讨论的功能较差的客户端应该使用消息提交协议(RFC 4409) 而不是 SMTP。
再进一步:
换句话说,消息传输可以在原始 SMTP 发送者和最终 SMTP 接收者之间的单个连接中进行,也可以通过中介系统在一系列跳转中进行。无论哪种情况,一旦服务器在邮件数据末尾发出成功响应,就会正式移交消息的责任:协议要求服务器必须承担传递消息或正确报告传递失败的责任(请参阅第 6.1、6.2 和 7.8 节)。
答案2
我认为 Esa 的回答非常好,但我不同意其中的一些观点。我认为你想要的是是有可能,但这不是个好主意,而且对你没有帮助。正如他所说,RFC5321 s2.1 指出
一旦服务器在邮件数据末尾发出成功响应,就会正式移交消息的责任:协议要求服务器必须承担传递消息或正确报告失败的责任
如果服务器 B 收到来自服务器 A 的消息并将其传递给服务器 C,我认为这不会阻止 B 等待向 A 确认收货,直到它收到来自 C 的收货确认 - 这正是您所要求的。但问题是两台服务器之间的250 OK
原子性(要么接收方已接受,因此负责交付,要么尚未接受,因此发送方仍负责),而三台服务器之间的原子性则不是。
考虑这样一种情况:客户端 A 在发送邮件之后但尚未收到 之前意外断开连接250 OK
,而 B 正在将邮件传递给 C。然后 C 使用 确认收到来自 B 的邮件250 OK
,因此 B 知道 C 已收到邮件。但是 A 不知道,因此 A 仍需负责,必须继续将邮件重新传递给 B。如果 A 和 B 之间存在一些系统性通信问题(例如,某个可爱的防火墙认为干扰 SMTP 对话的内容是其职责),则可能导致传递大量相同邮件的副本。
此外,sendmail 已经做了您认为它不会做的事情:如果无法向 C 发送邮件,它将尝试将责任转嫁给 A。这通常仅在 A 怀有恶意,并且位于信封发件人(应向其发送此类通知的人)或根本没有运行邮件服务器的情况下才会失败。在这种情况下,邮件必须被送到 B 的邮局局长,因为 B 负责递送(已经发送250 OK
给 A,但没有从 C 那里收到),无法递送给 C(已经尝试过并且得到了 5xx 永久失败)并且无法交还给 A(因为 A 使这变得不可能)所以没有其他人可以交给它。这是我今天早上收到的一个例子:
Date: Tue, 8 Aug 2017 02:53:55 +0100
From: Mail Delivery Subsystem <[email protected]>
To: [email protected]
Subject: Returned mail: see transcript for details
Parts/Attachments:
1 Shown 17 lines Text
2 Shown 407 bytes Message, "Delivery Status"
3 Shown 15 KB Message
3.1 10 KB Application
----------------------------------------
The original message was received at Tue, 8 Aug 2017 02:53:53 +0100
from localhost [IPv6:::1]
----- The following addresses had permanent fatal errors -----
<[email protected]>
(reason: 550-5.7.1 Unauthenticated email from aol.com is not accepted due to domain's)
----- Transcript of session follows -----
... while talking to gmail-smtp-in.l.google.com.:
>>> DATA
<<< 550-5.7.1 Unauthenticated email from aol.com is not accepted due to domain's
<<< 550-5.7.1 DMARC policy. Please contact the administrator of aol.com domain if
<<< 550-5.7.1 this was a legitimate mail. Please visit
<<< 550-5.7.1 https://support.google.com/mail/answer/2451690 to learn about the
<<< 550 5.7.1 DMARC initiative. 53si155585wrc.260 - gsmtp
554 5.0.0 Service unavailable
[ Part 2: "Delivery Status" ]
Reporting-MTA: dns; lory.teaparty.net
Received-From-MTA: DNS; localhost
Arrival-Date: Tue, 8 Aug 2017 02:53:53 +0100
Final-Recipient: RFC822; [email protected]
Action: failed
Status: 5.7.1
Remote-MTA: DNS; gmail-smtp-in.l.google.com
Diagnostic-Code: SMTP; 550-5.7.1 Unauthenticated email from aol.com is not accepted due to domain's
Last-Attempt-Date: Tue, 8 Aug 2017 02:53:55 +0100
[ Part 3: "Included Message" ]
Date: Tue, 08 Aug 2017 01:53:46 -0000
From: [email protected]
To: [email protected]
[...]
请注意,原始电子邮件声称来自 aol.com 地址。那么,我怎么不试图将失败报告发回给他们呢?因为他们在原始 SMTP 事务中撒了谎:
Aug 8 02:53:51 lory sendmail[9457]: v781rmjA009457: from=<[email protected]>, size=14095, class=0, nrcpts=1, msgid=<[email protected]>, proto=SMTP, daemon=MTA-v6, relay=[37.114.157.178]
这是我的错,我还没有为我的那个特定域名 () 设置 SPF stphilipschurch.org.uk
,但是既然我没有,没有什么能阻止我接受这个谎言 - 然后我陷入了无法送达的消息,无法返回给发件人,因为发件人是恶意的并且不感兴趣(通过阿塞拜疆的 ISP 连接)。
总结:sendmail 在可以时已经执行了您要求的操作。当 sendmail 无法执行时,您想要执行的操作对它没有帮助,并且会产生问题。不要这样做。