熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

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

2022-06-13   來源: .NET編程 

  有時我們需要在網站中加入發送郵件的功能例如一個網上投稿系統當稿件被采用的時候發送郵件通知作者下面就以這個功能為例說明如何實現自動發送郵件

  實現發送郵件功能

  首先說一下在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) {

  thism_smtpService = smtpService;

  thism_loginName = loginName;

  thism_password = password;

  thism_enableSSL = enableSSL;

  thism_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();

  mailToAdd(address);

  mailFrom = new MailAddress(thism_loginName senderName EncodingUTF);

  mailSubject = title;

  mailBody = content;

  mailBodyEncoding = EncodingUTF;

  mailIsBodyHtml = false;

  mailPriority = MailPriorityNormal;

  SmtpClient smtp = new SmtpClient();

  smtpCredentials = new NetworkCredential(thism_loginName thism_password);

  smtpHost = thism_smtpService;

  smtpEnableSsl = thism_enableSSL;

  smtpPort = thism_port;

  smtpSend(mail);

  }

  }

  在使用時首先構造一個EmailNotificationService類再調用SendTo方法即可例如

  EmailNotificationService mailNotificationService = new EmailNotificationService( true LoginPassword);

  mailNotificationServiceSendTo(SenderName Title Content);

  發送郵件實現方案

  上面創建好了一個負責發送郵件的類接下來的問題是應該在什麼時候調用這個類發送電子郵件需要進行網絡通信耗時比較多而且SmtpClient的Send方法是會阻塞調用線程的一旦調用了該方法就要等到郵件發送完畢或出錯才能結束方法調用所以不能將對EmailNotificationService的調用放在ASPNET頁面的代碼中如果這麼做客戶端就要等待很長時間才能獲得響應用戶體驗是比較差的

  SmtpClient還有一個SendAsync方法該方法與Send方法的區別是SendAsync是異步的調用該方法之後會產生一個新的線程來負責發送郵件之後調用線程立即返回不會再等待郵件發送結束那麼我們是不是可以用SendAsync代替Send並在頁面代碼中調用呢?答案是否定的雖然客戶端可以很快獲得相應但郵件根本沒有發送出去這是由ASPNET頁面生命周期的特性決定的客戶端向服務器的每一次請求頁面都會經歷一個由產生到銷毀的過程當頁面銷毀的時候負責發送郵件的線程還沒有完成發送郵件的工作就被強制結束了

  由於ASPNET頁面生命周期的特性我們不能將調用代碼放在頁面的代碼中我們需要一個與頁面無關的線程一個在網站運行時始終存在的線程我的方案是使用一個全局對象來管理一個發送郵件線程同時維護一個待發送郵件鏈表當全局對象創建的時候鏈表中沒有任何內容發送郵件線程處於掛起狀態當某個頁面中的處理需要發送電子郵件時就將與發送郵件相關的信息添加到待發送郵件鏈表中此時鏈表不為空發送郵件線程開始工作逐個取出鏈表中的郵件信息並發送一直到鏈表為空再次進入掛起狀態如此循環反復

  實現發送郵件功能

  基本的構思已經確定好了接下來就是寫代碼實現了首先定義一個類來封裝待發送郵件的相關信息本文開頭已經說過要以一個網上投稿系統作為例子所以這裡所用的信息與該應用有關

  /// <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() {

  thism_lockObject = new object();

  thism_mailNotifyInfos = new LinkedList<MailNotifyInfo>();

  thism_threadEvent = new ManualResetEvent(false);

  thism_workThread = new Thread(thisThreadStart);

  thism_workThreadStart();

  }

  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 (thism_lockObject) {

  thism_mailNotifyInfosAddLast(mailNotifyInfo);

  if (thism_mailNotifyInfosCount != ) {

  thism_threadEventSet();

  }

  }

  }

  /// <summary>

  /// 發送郵件線程的執行方法

  /// </summary>

  private void ThreadStart() {

  while (true) {

  thism_threadEventWaitOne();

  MailNotifyInfo mailNotifyInfo = thism_mailNotifyInfosFirstValue;

  EmailNotificationService mailNotificationService = new EmailNotificationService( true LoginPassword);

  mailNotificationServiceSendTo(稿件中心

  mailNotifyInfoEmailAddress

  稿件狀態變更通知

  StringFormat({}你的稿件{}狀態已變更為{} mailNotifyInfoAuthor mailNotifyInfoTitle mailNotifyInfoArticleStatus));

  lock (thism_lockObject) {

  thism_mailNotifyInfosRemove(mailNotifyInfo);

  if (thism_mailNotifyInfosCount == ) {

  thism_threadEventReset();

  }

  }

  }

  }

  該類比較簡單首先在構造函數中初始化成員變量然後啟動發送郵件線程此時該線程是掛起的

  當外部調用AppendNotification方法時會在鏈表中添加一個MailNotifyInfo對象然後喚醒發送郵件線程由於在生產環境下可能會出現同時調用AppendNotification方法的情形所以這裡要進行同步

  發送郵件線程喚醒後進入一個死循環等待事件對象觸發當事件對象出發之後就開始發送郵件了郵件發送完畢後從鏈表中刪除已發送的郵件然後檢查鏈表是否為空如果是則重置事件對象重新進入掛起狀態同樣地在對鏈表進行操作時也要進行同步

  至此發送郵件的功能實現完畢需要發送郵件的時候只要像這樣調用即可

  MailNotifyInfo mailNotifyInfo = new MailNotifyInfo();

  

  NotificationHandlerInstanceAppendNotification(mailNotifyInfo);

  這只是一個很粗陋的框架而且還不完善例如這裡假設網站是不間斷運行的系統沒有考慮當網站關閉時發送郵件線程的處理大家可以在這個基礎上添磚加瓦使其更加完善另外自動發送郵件也是常見的功能例如定時檢查某個條件如果成立則發送郵件要實現自動發送郵件的話只要對本文的方案稍加修改即可在NotificationHandler中添加一個Timer定時執行某個方法在這個方法中進行條件檢查並觸發事件即可


From:http://tw.wingwit.com/Article/program/net/201311/11381.html
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.