2012-02-09 26 views
0

叫我試圖以異步方式發送電子郵件,但是當我把我的SendMailMesage()方法從一個線程池或一個簡單的線程內,電子郵件根本不會發送時不被髮送。Gmail電子郵件從一個線程池

任何方式如何實現這一目標?定期發送電子郵件sendind會大大減慢我的應用程序。

PS:如果它很重要,SendMailMesage()正在從引用的項目發送,而不是MVC項目本身。

謝謝。

編輯:我的代碼。

namespace App.Core.Utils.Mailer 
{ 
    public static class Sender 
    { 
     /// <summary> 
     /// Sends a MailMessage object using the SMTP settings. 
     /// </summary> 
     public static void SendMailMessage(MailMessage message) 
     { 
      if (!Settings.Instance.SendEmails) 
      { 
       return; 
      } 

      if (message == null) 
       throw new ArgumentNullException("message"); 

      try 
      { 
       message.IsBodyHtml = true; 
       message.BodyEncoding = Encoding.UTF8; 
       var smtp = new SmtpClient(Settings.Instance.SmtpServer); 

       // don't send credentials if a server doesn't require it, 
       // linux smtp servers don't like that 
       if (!string.IsNullOrEmpty(Settings.Instance.SmtpUserName)) 
       { 
        smtp.Credentials = new System.Net.NetworkCredential(Settings.Instance.SmtpUserName, Settings.Instance.SmtpPassword); 
       } 
       smtp.Port = Settings.Instance.SmtpServerPort; 
       smtp.EnableSsl = Settings.Instance.EnableSsl; 
       smtp.Send(message); 
      } 
      catch (SmtpException) 
      { 
       //OnEmailFailed(message); 
      } 
      finally 
      { 
       // Remove the pointer to the message object so the GC can close the thread. 
       message.Dispose(); 
      } 
     } 

     public static void SendMailMessageAsync(MailMessage message) 
     { 
      ThreadPool.QueueUserWorkItem(state => SendMailMessage(message)); 
     } 
    } 
} 

請注意:這工作在WebForms。我將代碼複製到一個MVC項目中,現在如果我調用SendMailMessageAsync方法,則不會發送任何內容。沒有錯誤。

+0

當它沒有被調用在線程池中時它工作嗎? – casperOne 2012-02-09 02:39:42

回答

1

我們在MVC中使用它,它很好用。由於它實現了一個接口,你可以注入一個實例到控制器構造函數,而不是使用一個靜態方法:

public class MvcEmailSender : ISendEmails 
{ 
    public MvcEmailSender(ILogExceptions logger, 
     IQueryEntities queryables, IUnitOfWork unitOfWork) 
    { 
     // save args to readonly fields on the instance 
    } 

    public void Send(EmailMessage message) 
    { 
     // constructor really passes more args here 
     var sender = new SmtpEmailSender(message, arg2, arg3, arg4); 
     var thread = new Thread(sender.Send); 
     thread.Start(); 
    } 
} 

public class SmtpEmailSender 
{ 
    private readonly EmailMessage _emailMessage; 
    private int _retryCount; 

    public SmtpEmailSender(EmailMessage emailMessage, ILogExceptions logger, 
     IQueryEntities queryables, IUnitOfWork unitOfWork) 
    { 
     if (emailMessage == null) 
      throw new ArgumentNullException("emailMessage"); 

     _emailMessage = emailMessage; 
     // save other constructor args to readonly fields 
    } 

    public void Send() 
    { 
     try 
     { 
      // assemble message, send, & update database 
     } 
     catch (Exception ex) 
     { 
      // log exception, then retry like so: 
      if (_retryCount++ <= 3) 
      { 
       Thread.Sleep(10000); 
       Send(); 
      } 
     } 
    } 
} 

我們也有在web.config中提供一些設置,你呢?如果是這樣,請使用web.config中的system.net部分更新您的問題。

要使用此,我們只是從控制器調用ISendEmails.Send(EmailMessage)。該實現負責對其進行線程化,而不知道MVC。

這兩個2類和ISendEmails接口中引用的項目被聲明,而不是MVC項目(接口處於一個API組件和上面的2類在一個IMPL組件)。

更新

我響應註釋更新代碼。請注意,這些類的構造函數確實比最初描述的更依賴。我們也(構造函數)注入ILogExceptions,IQueryEntities和IUnitOfWork依賴項。在try塊內部,除了將EmailMessage轉換爲MailMessage併發送外,EmailMessage域對象在數據庫中更新,並且在SmtpClient.Send(MailMessage)成功後更新其SentOnUtc值。這就是我們如何證明電子郵件實際上已發送。當捕獲到異常時,會在重試之前記錄它。

+0

謝謝,這確實有效。您是否願意解釋如何在您的Send()方法的註釋代碼中手動發送重試? :) – rebelliard 2012-02-09 12:59:01

+0

完全沒有,代碼+答案已更新。 – danludwig 2012-02-09 15:53:54

+0

謝謝你。 :) – rebelliard 2012-02-09 19:06:12

相關問題