首先我們來介紹一下NET類庫種自帶的SMTP類
在NET中的SystemWebMail名字空間下有一個專門使用SMTP協議來發送郵件的類SmtpMail它已能滿足最普通的發送郵件的需求這個類只有一個自己的公共函數Send()和一個公共屬性—SmtpServer
您必須通過SmtpServer屬性來指定發送郵件的服務器的名稱(或IP地址)然後再調用
Send()函數來發送郵件
代碼示例如下
(in C#)
using SystemWebMail;
public void sendMail()
{
try
{
SystemWebMailMailMessage myMail=new MailMessage();
myMailFrom = ;
myMailTo = ;
myMailSubject = MailTest;
myMailPriority = MailPriorityLow;
myMailBodyFormat = MailFormatText;
myMailBody = Test;
SmtpMailSmtpServer=smarthost; //your smtp server here
SmtpMailSend(myMail);
}
catch(Exception e)
{
throw e;
}
}
您可以在Send函數的參數MailMessage對象中設置郵件的相關屬性
如優先級
附件等等
除了以MailMessage對象為參數(如上述代碼)
Send函數還可以簡單的直接以郵件的
個主要信息(from
to
subject
messageText)作為字符串參數來調用
第二使用CDO組件發送郵件
CDO是Collaboration Data Objects的簡稱它是一組高層的COM對象集合並經歷了好幾個版本的演化現在在Windows和Exchange中使用的都是CDO的版本(分別為cdosysdll和cdoexdll)CDOSYS構建在SMTP協議和NNTP協議之上並且作為Windows Server的組件被安裝您可以在系統目錄(如c:\winnt或c:\windows)的system子目錄中找到它(cdosysdll)
CDO組件相對於先前介紹的SmtpMail對象功能更為豐富並提供了一些SmtpMail類所沒有提供的功能如通過需要認證的SMTP服務器發送郵件等
下面一段代碼就展示了如何使用CDO組件通過需要認證的SMTP服務器發送郵件的過程
(in C#)
public void CDOsendMail()
{
try
{
CDOMessage oMsg = new CDOMessage();
oMsgFrom = ;
oMsgTo = ;
oMsgSubject = MailTest;
oMsgHTMLBody = <html><body>Test</body></html>;
CDOIConfiguration iConfg = oMsgConfiguration;
ADODBFields oFields = iConfgFields;
oFields[]Value=;
oFields[]Value=; //sender mail
oFields[]Value=; //email account
oFields[]Value=username;
oFields[]Value=password;
oFields[]Value=;
//value= 代表Anonymous驗證方式(不需要驗證)
//value= 代表Basic驗證方式(使用basic (cleartext) authentication
//The configuration sendusername/sendpassword or postusername/postpassword fields are used to specify credentials)
//Value= 代表NTLM驗證方式(Secure Password Authentication in Microsoft Outlook Express)
oFields[]Value=x;
oFields[]Value=;
oFieldsUpdate();
oMsgBodyPartCharset=gb;
oMsgHTMLBodyPartCharset=gb;
oMsgSend();
oMsg = null;
}
catch (Exception e)
{
throw e;
}
}
注意
由於Exchange
的CDO組件cdoex
dll會更新原有的Windows
的CDO組件cdosys
dll
所以如果您希望繼續使用cdosys
dll
您必須先通過regsrv
exe卸載掉cdoex
dll
第三使用Socket撰寫郵件發送程序
當然如果您覺得SmtpMail不能滿足您的需求CDO又不夠直截了當那就只能自己動手了其實如果您很熟悉Socket編程自己寫一個發送郵件的程序並不很難以下就是一個例子
首先我們簡單介紹一下帶驗證的SMTP服務器如何使用AUTH原語進行身份驗證其詳細的定義可以參考RFC
具體如下
)首先需要使用EHLO而不是原先的HELO
)EHLO成功以後客戶端需要發送AUTH原語與服務器就認證時用戶名和密碼的傳遞方式進行協商
)如果協商成功服務器會返回以開頭的結果碼這是就可以把用戶名和密碼傳給服務器
)最後如果驗證成功就可以開始發信了
下面是一個實際的例子客戶端在WinXP的Command窗口中通過telnet smtpNET 命令連接到的smtp服務器發信
Welcome to coremail System(With AntiSpam)
EHLO NET
PIPELINING
SIZE
ETRN
AUTH LOGIN
BITMIME
AUTH LOGIN
VXNlcmhbWU
bXlhYNvdW
UGFzcdvcmQ
bXlwYXNzdyZA==
Authentication successful
MAIL FROM:myaccount@NET
Ok
RCPT TO:myaccount@NET
Ok
Data
End data with <CR><LF><CR><LF>
This is a testing email
haha
Ok: queued as ACDC
QUIT
Bye
上面的內容就是發信的全過程其中與身份驗證有關的主要是第九到第十四行
AUTH LOGIN 客戶端輸入
VXNlcmhbWU 服務器提示Username:=
bXlhYNvdW 客戶端輸入myaccount=的Base編碼
UGFzcdvcmQ 服務器提示Password:=
bXlwYXNzdyZA== 客戶端輸入mypassword=的Base編碼
Authentication successful 服務器端通過驗證
從上面的分析可以看出在這個身份驗證過程中服務器和客戶端都直接通過Socket傳遞經過標准Base編碼的純文本這個過程可以非常方便的用C#實現或者直接添加到原有的源代碼中
另外有些ESMTP服務器不支持AUTH LOGIN方式的認證只支持AUTH CRAMMD方式驗證但是這兩者之間的區別只是文本的編碼方式不同
實現此功能的源代碼可以在SourceForgeNET net/ 上找到下載下面給出了一個簡單的偽碼
public void SendMail(MailMessage msg)
{
NetworkStream nwstream = GetConnection();
WriteToStream(ref nwstream EHLO + smtpHost + \r\n);
string welcomeMsg = ReadFromStream(ref nwstream);
// implement HELO command if EHLO is unrecognized
if (IsUnknownCommand(welcomeMsg))
{
WriteToStream(ref nwstream HELO + smtpHost + \r\n);
}
CheckForError(welcomeMsg ReplyConstantsOK);
// Authentication is used if the u/p are supplied
AuthLogin(ref nwstream);
WriteToStream(ref nwstream MAIL FROM: < + msgFromAddress + >\r\n);
CheckForError(ReadFromStream(ref nwstream) ReplyConstantsOK);
SendRecipientList(ref nwstream msgTo);
SendRecipientList(ref nwstream msgCC);
SendRecipientList(ref nwstream msgBCC);
WriteToStream(ref nwstream DATA\r\n);
CheckForError(ReadFromStream(ref nwstream) ReplyConstantsSTART_INPUT);
if (msgReplyToName != null && msgReplyToNameLength != )
{ WriteToStream(ref nwstream ReplyTo: \ + msgReplyToName + \ < +
msgReplyToAddress + >\r\n); }
else
{ WriteToStream(ref nwstream ReplyTo: < + msgReplyToAddress + >\r\n); }
if (msgFromName != null && msgFromNameLength != )
{ WriteToStream(ref nwstream From: \ + msgFromName + \ < +
msgFromAddress + >\r\n); }
else
{ WriteToStream(ref nwstream From: < + msgFromAddress + >\r\n); }
WriteToStream(ref nwstream To: + CreateAddressList(msgTo) + \r\n);
if (msgCCCount != )
{ WriteToStream(ref nwstream CC: + CreateAddressList(msgCC) + \r\n); }
WriteToStream(ref nwstream Subject: + msgSubject + \r\n);
if (msgPriority != null)
{ WriteToStream(ref nwstream XPriority: + msgPriority + \r\n); }
if (msgHeadersCount > )
{
SendHeaders(ref nwstream msg);
}
if (msgAttachmentsCount > || msgHtmlBody != null)
{
SendMessageBody(ref nwstream msg);
}
else
{
WriteToStream(ref nwstream msgBody + \r\n);
}
WriteToStream(ref nwstream \r\n\r\n);
CheckForError(ReadFromStream(ref nwstream) ReplyConstantsOK);
WriteToStream(ref nwstream QUIT\r\n);
CheckForError(ReadFromStream(ref nwstream) ReplyConstantsQUIT);
CloseConnection();
}
private bool AuthLogin(ref NetworkStream nwstream)
{
if (username != null && usernameLength > && password != null && passwordLength > )
{
WriteToStream(ref nwstream AUTH LOGIN\r\n);
if (AuthImplemented(ReadFromStream(ref nwstream)))
{
WriteToStream(ref nwstream ConvertToBaseString(
EncodingASCIIGetBytes(thisusernameToCharArray())) + \r\n);
CheckForError(ReadFromStream(ref nwstream) ReplyConstantsSERVER_CHALLENGE);
WriteToStream(ref nwstream ConvertToBaseString(EncodingASCIIGetBytes(
thispasswordToCharArray())) + \r\n);
CheckForError(ReadFromStream(ref nwstream) ReplyConstantsAUTH_SUCCESSFUL);
return true;
}
}
return false;
}
總結本文介紹了
NET中三種不同的使用SMTP協議發送郵件的方法
其中第一種(使用SmtpMail類)方案能滿足大部分基本的發送郵件的功能需求
而第二種(使用CDO組件)和第三種(使用Socket自己撰寫SMTP類)方案提供更自由和完整的定制方法
比如他們都能實現第一種方案不能做到的通過帶認證的SMTP服務器發送郵件的功能
From:http://tw.wingwit.com/Article/program/net/201311/12344.html