深入Lumisoft.NET實現郵件發送功能的方法詳解_.Net教程

      編輯Tag賺U幣

      推薦:深入Lumisoft.NET組件開發碰到亂碼等問題的解決方法
      本篇文章介紹了,在Lumisoft.NET組件開發中碰到亂碼等一些問題的解決方法。需要的朋友參考下

      在前面的一些文章中,有介紹過DotNet內置SMTP類的郵件發送功能,附件、嵌入圖片的模式都有介紹,本文繼續介紹Lumisoft.NET這個非常優秀的開源組件,用該組件來設計開發郵件工具,將變得更加方便,功能更加強大。網上很多文章基本介紹如何使用該組件來收取郵件較多,較少介紹使用該組件做郵件發送功能的。本文主要探尋使用該組件實現郵件的發送功能,郵件發送有兩種方式,一種是不用發件人即可發送郵件,一種是使用發件人賬戶密碼和SMTP服務器來實現郵件發送的,本文分別對這兩種方式進行介紹。

      組件下載地址:http://www.lumisoft.ee/lswww/download/downloads/

      組件論壇地址:http://www.lumisoft.ee/Forum/default.aspx?g=forum

      秉承一貫的做法,先貼出相關的實現圖形,感官認識下,在進入詳細的介紹說明,以求達到最好的理解深度。

      1、 首先是發件人的設置,可以從文本文件的導出,以及新建等操作,以方便用戶操作。



      2、 內容也支持導入導出,并且保存到數據庫,方便進行記錄及操作等,另外可以對內容進行隨機混淆,混淆的內容在HTML郵件中式隱藏的,方便糊弄一下服務器的識別。



      3、 郵件發送可以選擇兩種方式,下面將分別介紹這兩種方式的實現,一種采用該控件封裝非常好的郵件直投技術,不需要SMTP賬號發送的;一種是普通的SMTP發送方式。當然我們還可以設置更多的參數,例如郵件尾部信息、HTML內容提示、 以及一些發送期間自動撥號的設置操作等。



      4、 郵件直投技術,通過模擬賬戶來附加用戶的郵件地址(或者可以成為偽裝)。其中我填寫了一些常用的SMTP服務器的域名,方便在其中構造合乎要求的郵件格式,還可以設置郵件回執通知,如下圖所示。



      5、 如果是采用普通發送方式,那么就需要制定用戶的賬號密碼等信息,發送的時候,自動從啟動獲取發件人信息進行批量發送操作。



      6、 最后體驗一下少量郵件的發送效果,發送采用多線程發送,多線程采用比較有名的SmartThreadPool組件,并且發送過程總詳細記錄其中的日志,供參考。

      介紹完畢相關的功能效果圖,下面我們來分析下主要功能實現的代碼

      復制代碼 代碼如下:www.wf0088.com

      private TimerHelper timer = null;

      private void btnSend_Click(object sender, EventArgs e)
      {
      //重置計數變量
      failedItems = 0;
      successItems = 0;

      workItemsCompleted = 0;
      workItemsGenerated = 0;

      Portal.gc.FailedCount = 0;//重置失敗次數

      STPStartInfo stpStartInfo = new STPStartInfo();
      stpStartInfo.IdleTimeout = 10;
      stpStartInfo.MaxWorkerThreads = 100;
      stpStartInfo.MinWorkerThreads = 0;
      //stpStartInfo.StartSuspended = true;
      _smartThreadPool = new SmartThreadPool(stpStartInfo);
      _workItemsGroup = _smartThreadPool;

      workItemsProducerThread = new Thread(new ThreadStart(this.WorkItemsProducer));
      workItemsProducerThread.IsBackground = true;
      workItemsProducerThread.Start();

      RefreshStatusCount();

      int intervalRedial = SystemConfig.Default.IntervalRedial * 1000 * 60;
      if (intervalRedial > 0)
      {
      if (timer != null)
      {
      timer.Stop();
      timer.Dispose();
      }
      timer = new TimerHelper(intervalRedial,false);
      timer.Execute += new TimerHelper.TimerExecution(timer_Execute);
      timer.Start();
      }
      }

      private static object locker = new object();
      private void timer_Execute()
      {
      if (Monitor.TryEnter(locker))
      {
      string message = string.Format("在時間 {0} 時刻執行了一次重撥號操作!", DateTime.Now);
      ShowSendStatus(message);

      string RasName = SystemConfig.Default.RasName;
      if (!string.IsNullOrEmpty(RasName))
      {
      message = string.Format("正在準備重新撥號({0})", RasName);
      ShowSendStatus(message);

      Portal.gc.ReConnect(RasName);
      Portal.gc.FailedCount = 0;//重新歸零
      }

      Monitor.Exit(locker);
      }
      else
      {
      Monitor.Enter(locker);
      Monitor.Exit(locker);
      }
      }


      上面是主要的任務生成操作以及相關的撥號操作,其中任務詳細的生成代碼如下所示。
      private void WorkItemsProducer()
      復制代碼 代碼如下:www.wf0088.com

      {
      CallCtrlWithThreadSafetyEx.SetText(this.txtSendDetail, "");

      EnableControl(false, true, true);
      string message = string.Format("任務開始");
      RecordMessage(message);

      #region 生成任務

      IWorkItemsGroup workItemsGroup = _workItemsGroup;
      if (null == workItemsGroup)
      {
      return;
      }

      List<string> addressList = GetAddressList();
      List<MyMailInfo> mailInfoList = GetMailInfo();
      for (int i = 0; i < addressList.Count; i++)
      {
      try
      {
      SendJobInfo jobInfo = new SendJobInfo();
      jobInfo.domainList = mailDomainList;
      jobInfo.mailTo = addressList[i];
      jobInfo.mailInfo = GetOneMail(mailInfoList, i);
      jobInfo.ShowSendStatus = ShowSendStatus;
      jobInfo.currentDomain = (i % mailDomainList.Count);//設置一個標志,默認那個賬戶開始發送
      jobInfo.UseDirectSendType = SystemConfig.Default.EmailDirectSend;

      //如果用戶未指定發送賬號,那么采用默認的顯示名稱
      //如果為空,發送的時候,會自動采用郵件地址作為顯示名稱
      if (string.IsNullOrEmpty(SystemConfig.Default.UserEmailFrom))
      {
      jobInfo.mailFromDisplay = SystemConfig.Default.DefaultFromDisplayName;
      }

      workItemCallback = new WorkItemCallback(this.DoWork);
      workItemsGroup.QueueWorkItem(workItemCallback, jobInfo);
      Thread.Sleep(100);
      }
      catch (ObjectDisposedException ex)
      {
      LogTextHelper.WriteLine(ex.ToString());
      continue;
      }

      Interlocked.Increment(ref workItemsGenerated);
      }

      #endregion

      RefreshStatusCount();
      message = string.Format("共有 {0} 個任務,還剩下 {1} 個",
      workItemsGenerated, workItemsGenerated - workItemsCompleted);
      CallCtrlWithThreadSafetyEx.SetText(this, message);
      RecordMessage(message);

      try
      {
      //workItemsGroup.Start();
      workItemsGroup.WaitForIdle();
      _smartThreadPool.Shutdown();
      }
      catch (Exception ex)
      {
      LogTextHelper.WriteLine(ex.ToString());
      }

      UpdateFinishStatus();
      }


      由于采用了多線程來處理,所以停止發送的時候,需要把相關的線程對象進行釋放,如下代碼所示。
      復制代碼 代碼如下:www.wf0088.com

      private void btnStop_Click(object sender, EventArgs e)
      {
      try
      {
      _smartThreadPool.Shutdown();
      _smartThreadPool.Dispose();
      _smartThreadPool = null;

      if (timer != null)
      {
      timer.Stop();
      timer.Dispose();
      }
      }
      catch (Exception ex)
      {
      LogTextHelper.WriteLine(ex.ToString());
      }

      UpdateFinishStatus();
      }


      其中具體的郵件發送功能封裝在SendJobInfo中,通過判斷不同的類型,進行不同的發送操作。

      其中最為關鍵的發送代碼,就是如何利用LumiSoft.NET組件來構造相應的郵件對象,下面先先介紹下郵件直投的發送方式,由于該組件封裝比較好,直投發送方式很簡單:

      復制代碼 代碼如下:www.wf0088.com

      Mail_Message message = Create_PlainText_Html_Attachment_Image(mailTo, mailFrom, mailFromDisplay);
      SMTP_Client.QuickSend(message);

      其中Create_PlainText_Html_Attachment_Image的封裝函數詳細內容如下所示:
      復制代碼 代碼如下:www.wf0088.com

      代碼

      private Mail_Message Create_PlainText_Html_Attachment_Image(string mailTo, string mailFrom, string mailFromDisplay)
      {
      Mail_Message msg = new Mail_Message();
      msg.MimeVersion = "1.0";
      msg.MessageID = MIME_Utils.CreateMessageID();
      msg.Date = DateTime.Now;
      msg.From = new Mail_t_MailboxList();
      msg.From.Add(new Mail_t_Mailbox(mailFromDisplay, mailFrom));
      msg.To = new Mail_t_AddressList();
      msg.To.Add(new Mail_t_Mailbox(mailTo, mailTo));
      msg.Subject = mailInfo.Title;

      //設置回執通知
      string notifyEmail = SystemConfig.Default.DispositionNotificationTo;
      if (!string.IsNullOrEmpty(notifyEmail) && ValidateUtil.IsEmail(notifyEmail))
      {
      msg.DispositionNotificationTo = new Mail_t_Mailbox(notifyEmail, notifyEmail);
      }

      #region MyRegion
      //--- multipart/mixed -----------------------------------
      MIME_h_ContentType contentType_multipartMixed = new MIME_h_ContentType(MIME_MediaTypes.Multipart.mixed);
      contentType_multipartMixed.Param_Boundary = Guid.NewGuid().ToString().Replace('-', '.');
      MIME_b_MultipartMixed multipartMixed = new MIME_b_MultipartMixed(contentType_multipartMixed);
      msg.Body = multipartMixed;

      //--- multipart/alternative -----------------------------
      MIME_Entity entity_multipartAlternative = new MIME_Entity();
      MIME_h_ContentType contentType_multipartAlternative = new MIME_h_ContentType(MIME_MediaTypes.Multipart.alternative);
      contentType_multipartAlternative.Param_Boundary = Guid.NewGuid().ToString().Replace('-', '.');
      MIME_b_MultipartAlternative multipartAlternative = new MIME_b_MultipartAlternative(contentType_multipartAlternative);
      entity_multipartAlternative.Body = multipartAlternative;
      multipartMixed.BodyParts.Add(entity_multipartAlternative);

      //--- text/plain ----------------------------------------
      MIME_Entity entity_text_plain = new MIME_Entity();
      MIME_b_Text text_plain = new MIME_b_Text(MIME_MediaTypes.Text.plain);
      entity_text_plain.Body = text_plain;

      //普通文本郵件內容,如果對方的收件客戶端不支持HTML,這是必需的
      string plainTextBody = "如果你郵件客戶端不支持HTML格式,或者你切換到“普通文本”視圖,將看到此內容";
      if (!string.IsNullOrEmpty(SystemConfig.Default.PlaintTextTips))
      {
      plainTextBody = SystemConfig.Default.PlaintTextTips;
      }

      text_plain.SetText(MIME_TransferEncodings.QuotedPrintable, Encoding.UTF8, plainTextBody);
      multipartAlternative.BodyParts.Add(entity_text_plain);

      //--- text/html -----------------------------------------
      string htmlText = mailInfo.Content;//"<html>這是一份測試郵件,<img src=\"cid:test.jpg\">來自<font color=red><b>LumiSoft.Net</b></font></html>";
      MIME_Entity entity_text_html = new MIME_Entity();
      MIME_b_Text text_html = new MIME_b_Text(MIME_MediaTypes.Text.html);
      entity_text_html.Body = text_html;
      text_html.SetText(MIME_TransferEncodings.QuotedPrintable, Encoding.UTF8, htmlText);
      multipartAlternative.BodyParts.Add(entity_text_html);

      //--- application/octet-stream -------------------------
      foreach (string attach in mailInfo.Attachments)
      {
      multipartMixed.BodyParts.Add(Mail_Message.CreateAttachment(attach));
      }

      foreach (string imageFile in mailInfo.EmbedImages)
      {
      MIME_Entity entity_image = new MIME_Entity();
      entity_image.ContentDisposition = new MIME_h_ContentDisposition(MIME_DispositionTypes.Inline);
      string fileName = DirectoryUtil.GetFileName(imageFile, true);
      entity_image.ContentID = BytesTools.BytesToHex(Encoding.Default.GetBytes(fileName));
      MIME_b_Image body_image = new MIME_b_Image(MIME_MediaTypes.Image.jpeg);
      entity_image.Body = body_image;
      body_image.SetDataFromFile(imageFile, MIME_TransferEncodings.Base64);
      multipartMixed.BodyParts.Add(entity_image);
      }

      #endregion

      return msg;
      }


      如果使用普通的賬號方式發送SMTP郵件,主要代碼如下所示,其中可以看出是利用了命令方式一步步和服務器進行交互的。
      復制代碼 代碼如下:www.wf0088.com

      using (SMTP_Client client = new SMTP_Client())
      {
      int port = domainInfo.Ssl ? WellKnownPorts.SMTP_SSL : WellKnownPorts.SMTP;
      if (domainInfo.Port > 0)
      {
      port = domainInfo.Port;
      }

      client.Connect(domainInfo.SmtpServer, port, domainInfo.Ssl);
      client.Authenticate(domainInfo.Username, domainInfo.Password);
      //string text = client.GreetingText;
      client.MailFrom(mailFrom, -1);
      client.RcptTo(mailTo);

      MemoryStream stream = Create_Html_Attachment_Image(mailTo, mailFrom, mailFromDisplay);
      client.SendMessage(stream);
      client.Disconnect();
      }


      其中構造郵件內容的代碼和剛才的部分類似,詳細代碼如下所示。
      復制代碼 代碼如下:www.wf0088.com

      private MemoryStream Create_Html_Attachment_Image(string mailTo, string mailFrom, string mailFromDisplay)
      {
      Mime m = new Mime();
      MimeEntity mainEntity = m.MainEntity;

      mainEntity.From = new AddressList();
      mainEntity.From.Add(new MailboxAddress(mailFromDisplay, mailFrom));

      mainEntity.To = new AddressList();
      mainEntity.To.Add(new MailboxAddress(mailTo, mailTo));
      mainEntity.Subject = mailInfo.Title;
      mainEntity.ContentType = MediaType_enum.Multipart_mixed;

      MimeEntity textEntity = mainEntity.ChildEntities.Add();
      textEntity.ContentType = MediaType_enum.Text_html;
      textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
      textEntity.DataText = mailInfo.Content;
      .........................

      MemoryStream msg = new MemoryStream();
      m.ToStream(msg);
      msg.Position = 0;

      return msg;
      }


      利用Lumisoft.NET這個組件,可以實現很多相關的郵件操作,這里介于興趣及篇幅原因,主要介紹郵件發送的功能模塊,其中貼出的代碼,一個是為了和感興趣的朋友相互交流,一個也是為了自己今后做一個借鑒,并不鼓勵大家用此軟件或者代碼來大批量發送垃圾郵件。

      分享:深入Lumisoft.NET組件POP3郵件接收與刪除操作的使用詳解
      本篇文章對Lumisoft.NET組件POP3郵件接收與刪除操作的使用進行了詳細的介紹。需要的朋友參考下

      來源:模板無憂//所屬分類:.Net教程/更新時間:2013-05-08
      相關.Net教程