我試圖解決您是完全相同的問題。我提出的解決方案涉及大約一個小時通過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;
}
讓我知道,如果這是有道理的,或者如果你需要看到更多的代碼,但它應該是比較明確的從這裏開始。