我试图解决您是完全相同的问题。我提出的解决方案涉及大约一个小时通过RFC2821浇注并尽可能最好地解释它。如果你有兴趣,你可以在这里找到它 - http://www.rfc-editor.org/rfc/rfc2821.txt
从阅读RFC大外卖是4yz
形式的代码表示一个瞬态负面完成代码,它保证重试。表格5yz
的代码表示一个永久的否定完成代码,您不应该重试。
因此,我们的目标是过滤出哪些收件人需要重试,哪些不是。所有5yz
代码可以被解释为“不重试”与552例外,有些服务器可能会错误地发送,而不是452.从那里出来,你需要决定:
- 这是一个严重的技术错误(503
BadCommandSequence
),这会导致您的服务在不重试任何内容的情况下快速失败。
OR
- 这是一个负永久完成代码只适用于单一的接收者,在这种情况下,你就这么走了有问题的收件人,然后重试发送操作。
因此,我的做法是这样的:
- 处理的
SmtpFailedRecipientsException
和SmtpFailedRecipientException
。
- 将所有失败的收件人存储到列表中。
- 对于每个失败的收件人,请致电我的特殊
HandleFailedRecipient()
解释SMTP代码的方法。如果在任何时候该方法返回false
那么这表示一个更严重的错误,并且我的服务应该快速失败(不尝试重新发送电子邮件)。
- 否则,该方法可能会或可能不会重新添加收件人(取决于SMTP代码)。
- 最后,如果邮件中仍有剩余的收件人,请尝试重新发送。
这里是我的方法,解释SMTP代码:
private bool HandleFailedRecipient(MailMessage message, string emailAddress, SmtpStatusCode statusCode, AddressType addressType)
{
//Notify any event subscribers that a recipient failed and give them the SMTP code.
RecipientFailedOnSend(this, new MailAddressEventArgs() { Address = emailAddress, AddressType = addressType, StatusCode = statusCode });
//5yz codes typically indicate a 'Permanent Negative Completion reply', which means we should NOT keep trying to send the message.
//The codes below can be interpreted as exceptions to the rule. In these cases we will just strip the user and try to resend.
if (statusCode == SmtpStatusCode.MailboxUnavailable || //550 = "No such user"
statusCode == SmtpStatusCode.MailboxNameNotAllowed || //553 = "User name ambiguous"
statusCode == SmtpStatusCode.UserNotLocalTryAlternatePath || //551 = "Mail address not deliverable"
statusCode == SmtpStatusCode.TransactionFailed) //554 = "Transaction failed/no valid recipients"
{
return true;
}
//The 4yz codes are 'Transient Negative Completion reply' codes, which means we should re-add the recipient and let the calling routine try again after a timeout.
if (statusCode == SmtpStatusCode.ServiceNotAvailable ||
statusCode == SmtpStatusCode.MailboxBusy ||
statusCode == SmtpStatusCode.LocalErrorInProcessing ||
statusCode == SmtpStatusCode.InsufficientStorage ||
statusCode == SmtpStatusCode.ClientNotPermitted ||
//The ones below are 'Positive Completion reply' 2yz codes. Not likely to occur in this scenario but we will account for them anyway.
statusCode == SmtpStatusCode.SystemStatus ||
statusCode == SmtpStatusCode.HelpMessage ||
statusCode == SmtpStatusCode.ServiceReady ||
statusCode == SmtpStatusCode.ServiceClosingTransmissionChannel ||
statusCode == SmtpStatusCode.Ok ||
statusCode == SmtpStatusCode.UserNotLocalWillForward ||
statusCode == SmtpStatusCode.CannotVerifyUserWillAttemptDelivery ||
statusCode == SmtpStatusCode.StartMailInput ||
statusCode == SmtpStatusCode.CannotVerifyUserWillAttemptDelivery ||
//The code below (552) may be sent by some incorrect server implementations instead of 452 (InsufficientStorage).
statusCode == SmtpStatusCode.ExceededStorageAllocation)
{
if ((addressType & AddressType.To) != 0)
{
message.To.Add(emailAddress);
}
if ((addressType & AddressType.CC) != 0)
{
message.CC.Add(emailAddress);
}
if ((addressType & AddressType.BCC) != 0)
{
message.Bcc.Add(emailAddress);
}
return true;
}
//Anything else indicates a very serious error (probably of the 5yz variety that we haven't handled yet). Tell the calling routine to fail fast.
return false;
}
让我知道,如果这是有道理的,或者如果你需要看到更多的代码,但它应该是比较明确的从这里开始。