我有一项服务,可以发送电子邮件并将出站电子邮件存储在数据库中。 我正在使用.NET本机Smtp类进行电子邮件传输。如果电子邮件发送失败,我会设置一个错误标志。
我的服务会定期检查未送达的邮件并尝试重新发送。在什么情况下它应该重新发送电子邮件?我已经注意到即使电子邮件地址不正确也会引发异常,但我希望我的服务能够丢弃任何无效的电子邮件,否则它将永远重试。
基本上,我想抓住一个例外,即电子邮件很有可能被重新发送。我想这只是网络错误而不是电子邮件帐户。 哪个SmtpStatusCode表示值得重试:
http://msdn.microsoft.com/en-us/library/system.net.mail.smtpstatuscode.aspx
答案 0 :(得分:6)
我试图解决你遇到的完全相同的问题。我提出的解决方案涉及到一小时的RFC2821倾注并尽可能地解释它。如果您有兴趣,可以在此处找到 - http://www.rfc-editor.org/rfc/rfc2821.txt
阅读RFC的最大好处是,4yz
形式的代码表示短暂的否定完成代码,需要重试。 5yz
形式的代码表示永久否定完成代码,您不应该重试。
因此,我们的目标是过滤掉需要重试的收件人以及不重审的收件人。所有5yz
代码都可以解释为"不要重试"除了552,有些服务器可能会错误地发送而不是452.从那时起你需要决定:
BadCommandSequence
),这会导致您的服务快速失败而不会重试任何内容。OR
因此,我的方法是这样的:
SmtpFailedRecipientsException
和SmtpFailedRecipientException
。HandleFailedRecipient()
方法来解释SMTP代码。如果该方法在任何时候返回false
,则表示更严重的错误,我的服务应该快速失败(不尝试重新发送电子邮件)。这是解释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;
}
让我知道这是否有意义,或者您是否需要查看更多代码,但它应该从这里相对清晰。