首先我们来介绍一下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函数还可以简单的直接以邮件的个主要信息(fromtosubjectmessageText)作为字符串参数来调用
第二使用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组件cdoexdll会更新原有的Windows的CDO组件cdosysdll所以如果您希望继续使用cdosysdll您必须先通过regsrvexe卸载掉cdoexdll
第三使用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服务器发送邮件的功能