2011-06-02 145 views
2

我有一項服務可以發送電子郵件並將出站電子郵件存儲在數據庫中。 我使用.NET本機Smtp類進行電子郵件傳輸。如果電子郵件傳遞失敗,我有一個錯誤標誌。.net smtp用SmtpStatusCode發送 - 什麼時候應該發生重試?

我的服務將定期檢查未傳送的郵件並嘗試重新發送。應該在什麼情況下重試發送電子郵件?我注意到,即使電子郵件地址不正確,它也會拋出異常,但我希望我的服務能夠排除任何無效的電子郵件,否則它將永久重試。

基本上,我想捕捉一個很好的機會可以重新發送電子郵件的例外。我想這隻會是網絡錯誤,而不是電子郵件帳戶。在SmtpStatusCode的 將指示值得重試:

http://msdn.microsoft.com/en-us/library/system.net.mail.smtpstatuscode.aspx

回答

4

我試圖解決您是完全相同的問題。我提出的解決方案涉及大約一個小時通過RFC2821澆注並儘可能最好地解釋它。如果你有興趣,你可以在這裏找到它 - http://www.rfc-editor.org/rfc/rfc2821.txt

從閱讀RFC大外賣是4yz形式的代碼表示一個瞬態負面完成代碼,它保證重試。表格5yz的代碼表示一個永久的否定完成代碼,您不應該重試。

因此,我們的目標是過濾出哪些收件人需要重試,哪些不是。所有5yz代碼可以被解釋爲「不重試」與552例外,有些服務器可能會錯誤地發送,而不是452.從那裏出來,你需要決定:

  • 這是一個嚴重的技術錯誤(503 BadCommandSequence),這會導致您的服務在不重試任何內容的情況下快速失敗。

OR

  • 這是一個負永久完成代碼只適用於單一的接收者,在這種情況下,你就這麼走了有問題的收件人,然後重試發送操作。

因此,我的做法是這樣的:

  • 處理的SmtpFailedRecipientsExceptionSmtpFailedRecipientException
  • 將所有失敗的收件人存儲到列表中。
  • 對於每個失敗的收件人,請致電我的特殊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; 
    } 

讓我知道,如果這是有道理的,或者如果你需要看到更多的代碼,但它應該是比較明確的從這裏開始。

相關問題