這兩天想要把自己的應用程式加上發送 E-mail 的功能,於是 survey 了幾種方法:

  • CDOSYS (Microsoft Collaboration Data Objects for Windows 2000)
  • Outlook 提供的 MAPI (Mail Application Programming Interface)
  • Indy.NET

CDOSYS 是一個 COM 元件,從 Windows 2000 之後便內建於作業系統,開發人員可以利用此元件來撰寫 E-mail 用戶端程式。若要在 .NET 程式中使用此元件,就必須加入 System.Web.dll 組件參考,這個組件將 CDOSYS COM 元件再包一層,以便讓 .NET 應用程式使用。用法很簡單,參考以下範例程式:

using System.Web.Mail;

private void btnSend_Click(object sender, System.EventArgs e)
{
  MailMessage mail = new MailMessage();
  mail.From = "huanlin@techshare.com";   // 寄件人
  mail.To = "bill@microsoft.com";        // 收件人
  mail.Subject = "測試";                 // 主旨
  mail.Body = "這是一封測試信件";        // 內文
  SmtpMail.SmtpServer = "msa.hinet.net";  // SMTP 伺服器位址
  SmtpMail.Send(mail);
}

但實際測試後發現很容易出問題,例如這個最常見的的錯誤:"無法存取 'CDO.Message' 物件"。由於這個錯誤是由底層的 CDOSYS COM 元件所引發,而 System.Web.dll 並沒有把詳細的錯誤訊息顯示出來,因此往往得費一番手腳找出錯誤的真正原因。我在 Google 上找到相關的系列文章:http://www.systemwebmail.com/faq/4.2.3.aspx。看了這系列的文章之後,決定還是省點麻煩,改用別的方法了。

我試的第二種方法是以 OLE Automation 控制 Outlook 來寄信,做法也很簡單,只要參考下面這篇官方教學文件就可以很快上手:How to use the Microsoft Outlook Object Library to send an HTML formatted message by using Visual C# .NET。使用這種方法有個小缺點,就是是每次寄信時都要建立一個 Outlook 應用程式的 instance,因此需要佔用較多的記憶體資源,且效率上也稍微差了一點。

以上兩種方法都要透過 COM。後來我到網路上尋找別的元件,找到了以前在撰寫 Delphi 程式時常用的 Indy 套件,原來已經有 .NET 版了。Indy 是一套純 .NET 的元件,完全不需要用到 COM 技術,其中包含的 Indy.Sockets 組件就可以用來撰寫 E-mail 程式。不只是 E-mail,這個元件提供了所有跟 sockets 程式設計相關的元件,包括:TCP、UDP、SMTP、POP3、NNTP、HTTP...等。使用也很簡單,例如以下這個寄信的範例程式:

using Indy.Sockets;

    private void btnSend_Click(object sender, System.EventArgs e)
    {
      Indy.Sockets.Message msg = new Indy.Sockets.Message();
      
      // 寄件人
      msg.From.Text = txtFrom.Text; 
      
      // 收件人可以有多個,只要將收件人物件加入 Message 物件的 Recipipients 屬性即可。
      EMailAddressItem recipient = msg.Recipients.Add();
      recipient.Address = txtTo.Text;
      
      // 主旨
      msg.Subject = txtSubject.Text;
      
      // 內文
      msg.Body.Text = txtBody.Text;

      // 建立 SMTP 物件並設定 SMTP 伺服器位址
      SMTP smtp = new SMTP();
      smtp.Host = txtSmtpServer.Text;
      smtp.Connect();
      try 
      {
        smtp.Send(msg);   // 送出信件
      }
      finally
      {
        smtp.Disconnect();
      }
    }

基本上我還是偏好最後一種方式,一來 Indy 是我之前就用過的元件,品質不錯,而且開放原始碼;二來它是純 .NET 元件,不需要用到 COM。