ASP.NET自動發送郵件功能的實現

來源:互聯網
上載者:User
有時我們需要在網站中加入發送郵件的功能,例如一個網上投稿系統,當稿件被採用的時候發送郵件通知作者。下面就以這個功能為例說明如何?自動發送郵件。

  實現發送郵件功能  首先說一下在.Net下如何發送郵件。.Net已經為我們準備好了與發送郵件相關的類,只要直接調用即可,非常方便。下面是我自己寫的一個郵件通知類:  /// <summary>  /// 郵件通知服務類。  /// </summary>  public class EmailNotificationService {  /// <summary>  /// 構造一個郵件通知服務類的執行個體。  /// </summary>  /// <param name="smtpService">SMTP伺服器的IP地址</param>  /// <param name="enableSSL">是否使用SSL串連SMTP伺服器器</param>  /// <param name="port">SMTP伺服器連接埠</param>  /// <param name="loginName">用於登入SMTP伺服器的使用者名稱</param>  /// <param name="password">登入密碼</param>  public EmailNotificationService(  string smtpService,  bool enableSSL,  int port,  string loginName,  string password) {  this.m_smtpService = smtpService;  this.m_loginName = loginName;  this.m_password = password;  this.m_enableSSL = enableSSL;  this.m_port = port;  }  private readonly string m_smtpService;  private readonly string m_loginName;  private readonly string m_password;  private readonly bool m_enableSSL;  private readonly int m_port;  /// <summary>  /// 發送郵件通知到指定的EMAIL地址。  /// </summary>  /// <param name="senderName">顯示在“寄件者”一欄上的名稱</param>  /// <param name="address">目的EMAIL地址</param>  /// <param name="title">郵件標題</param>  /// <param name="content">郵件內容</param>  public void SendTo(string senderName, string address, string title, string content) {  MailMessage mail = new MailMessage();  mail.To.Add(address);  mail.From = new MailAddress(this.m_loginName, senderName, Encoding.UTF8);  mail.Subject = title;  mail.Body = content;  mail.BodyEncoding = Encoding.UTF8;  mail.IsBodyHtml = false;  mail.Priority = MailPriority.Normal;  SmtpClient smtp = new SmtpClient();  smtp.Credentials = new NetworkCredential(this.m_loginName, this.m_password);  smtp.Host = this.m_smtpService;  smtp.EnableSsl = this.m_enableSSL;  smtp.Port = this.m_port;  smtp.Send(mail);  }  }在使用時,首先構造一個EmailNotificationService類,再調用SendTo方法即可。例如:  EmailNotificationService mailNotificationService = new EmailNotificationService("smtp.gmail.com", true, 587, "LoginName@gmail.com", "LoginPassword");  mailNotificationService.SendTo("SenderName", "TargetAddress@qq.com", "Title", "Content");  發送郵件實現方案  上面建立好了一個負責發送郵件的類,接下來的問題是應該在什麼時候調用這個類。寄送電子郵件需要進行網路通訊,耗時比較多,而且SmtpClient的Send方法是會阻塞調用線程的,一旦調用了該方法,就要等到郵件發送完畢或出錯才能結束方法調用,所以不能將對EmailNotificationService的調用放在ASP.NET頁面的代碼中。如果這麼做,用戶端就要等待很長時間才能獲得響應,使用者體驗是比較差的。  SmtpClient還有一個SendAsync方法,該方法與Send方法的區別是,SendAsync是非同步,調用該方法之後會產生一個新的線程來負責發送郵件,之後調用線程立即返回,不會再等待郵件發送結束。那麼我們是不是可以用SendAsync代替Send,並在頁面代碼中調用呢?答案是否定的,雖然用戶端可以很快獲得相應,但郵件根本沒有發送出去。這是由ASP.NET頁面生命週期的特性決定的,用戶端向伺服器的每一次請求,頁面都會經曆一個由產生到銷毀的過程,當頁面銷毀的時候,負責發送郵件的線程還沒有完成發送郵件的工作就被強制結束了。  由於ASP.NET頁面生命週期的特性,我們不能將調用代碼放在頁面的代碼中。我們需要一個與頁面無關的線程,一個在網站運行時始終存在的線程。我的方案是使用一個全域對象來管理一個髮送郵件線程,同時維護一個待發送郵件鏈表。當全域對象建立的時候,鏈表中沒有任何內容,發送郵件線程處於掛起狀態。當某個頁面中的處理需要寄送電子郵件時,就將與發送郵件相關的資訊添加到待發送郵件鏈表中。此時鏈表不為空白,發送郵件線程開始工作,逐個取出鏈表中的郵件資訊並發送,一直到鏈表為空白,再次進入掛起狀態。如此迴圈反覆。  實現發送郵件功能  基本的構思已經確定好了,接下來就是寫代碼實現了。首先定義一個類來封裝待發送郵件的相關資訊,本文開頭已經說過要以一個網上投稿系統作為例子,所以這裡所用的資訊與該應用有關。  /// <summary>  /// 封裝發送郵件時所需資訊的類。  /// </summary>  public class MailNotifyInfo  {  /// <summary>  /// 擷取或設定稿件的標題。  /// </summary>  public string Title {  get;  set;  }  /// <summary>  /// 擷取或設定稿件的作者名稱。  /// </summary>  public string Author {  get;  set;  }  /// <summary>  /// 擷取或設定作者的電子郵件地址。  /// </summary>  public string EmailAddress {  get;  set;  }  /// <summary>  /// 擷取或設定稿件的狀態。  /// </summary>  public ArticleStatus ArticleStatus {  get;  set;  }  }  然後是全域對象類的定義,我使用了單件模式來實現其全域性。  /// <summary>  /// 處理郵件發送功能的類。  /// </summary>  public class NotificationHandler {  /// <summary>  /// 該類的靜態執行個體。  /// </summary>  private static readonly NotificationHandler g_instance = new NotificationHandler();  /// <summary>  /// 擷取該類的唯一執行個體。  /// </summary>  public static NotificationHandler Instance {  get {  return g_instance;  }  } /// <summary>  /// 預設構造方法。  /// </summary>  private NotificationHandler() {  this.m_lockObject = new object();  this.m_mailNotifyInfos = new LinkedList<MailNotifyInfo>();  this.m_threadEvent = new ManualResetEvent(false);  this.m_workThread = new Thread(this.ThreadStart);  this.m_workThread.Start();  }  private readonly LinkedList<MailNotifyInfo> m_mailNotifyInfos;  private readonly Thread m_workThread;  private readonly ManualResetEvent m_threadEvent;  private readonly Object m_lockObject;  /// <summary>  /// 添加待發送郵件的相關資訊。  /// </summary>  public void AppendNotification(MailNotifyInfo mailNotifyInfo) {  lock (this.m_lockObject) {  this.m_mailNotifyInfos.AddLast(mailNotifyInfo);  if (this.m_mailNotifyInfos.Count != 0) {  this.m_threadEvent.Set();  }  }  }  /// <summary>  /// 發送郵件線程的執行方法。  /// </summary>  private void ThreadStart() {  while (true) {  this.m_threadEvent.WaitOne();  MailNotifyInfo mailNotifyInfo = this.m_mailNotifyInfos.First.Value;  EmailNotificationService mailNotificationService = new EmailNotificationService("smtp.gmail.com", true, 587, "LoginName@gmail.com", "LoginPassword");  mailNotificationService.SendTo("稿件中心",  mailNotifyInfo.EmailAddress,  "稿件狀態變更通知",  String.Format("{0}你的稿件{1}狀態已變更為{2}", mailNotifyInfo.Author, mailNotifyInfo.Title, mailNotifyInfo.ArticleStatus));  lock (this.m_lockObject) {  this.m_mailNotifyInfos.Remove(mailNotifyInfo);  if (this.m_mailNotifyInfos.Count == 0) {  this.m_threadEvent.Reset();  }  }  }  }  該類比較簡單,首先在建構函式中初始化成員變數,然後啟動發送郵件線程,此時該線程是掛起的。  當外部調用AppendNotification方法時,會在鏈表中添加一個MailNotifyInfo對象,然後喚醒發送郵件線程。由於在生產環境下可能會出現同時調用AppendNotification方法的情形,所以這裡要進行同步。  發送郵件線程喚醒後進入一個死迴圈,等待事件對象觸發。當事件對象出發之後就開始發送郵件了。郵件發送完畢後從鏈表中刪除已發送的郵件,然後檢查鏈表是否為空白,如果是則重設事件對象,重新進入掛起狀態。同樣地,在對鏈表進行操作時也要進行同步。  至此,發送郵件的功能實現完畢。需要發送郵件的時候只要像這樣調用即可:  MailNotifyInfo mailNotifyInfo = new MailNotifyInfo();  .....  NotificationHandler.Instance.AppendNotification(mailNotifyInfo);  這隻是一個很粗陋的架構,而且還不完善。例如,這裡假設網站是不間斷啟動並執行系統,沒有考慮當網站關閉時發送郵件線程的處理。大家可以在這個基礎上添磚加瓦,使其更加完善。另外,自動發送郵件也是常見的功能,例如定時檢查某個條件,如果成立則發送郵件。要實現自動發送郵件的話,只要對本文的方案稍加修改即可:在NotificationHandler中添加一個Timer,定時執行某個方法,在這個方法中進行條件檢查並觸發事件即可。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.