从上面的分析可以看出,在这个身份验证过程中,服务器和客户端都直接通过Socket传递经过标准Base64编码的纯文本。这个过程可以非常方便的用C#实现,或者直接添加到原有的源代码中。另外,有些ESMTP服务器不支持AUTH LOGIN方式的认证,只支持AUTH CRAM-MD5方式验证。但是这两者之间的区别只是文本的编码方式不同。
实现此功能的源代码可以在SourceForge.NET http://sourceforge.NET/projects/opensmtp-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, ReplyConstants.OK);
// Authentication is used if the u/p are supplied
AuthLogin(ref nwstream);
WrITeToStream(ref nwstream, "MAIL FROM: <" + msg.From.Address + ">\r\n");
CheckForError(ReadFromStream(ref nwstream), ReplyConstants.OK);
SendRecipientList(ref nwstream, msg.To);
SendRecipientList(ref nwstream, msg.CC);
SendRecipientList(ref nwstream, msg.BCC);
WrITeToStream(ref nwstream, "DATA\r\n");
CheckForError(ReadFromStream(ref nwstream), ReplyConstants.START_INPUT);
if (msg.ReplyTo.Name != null && msg.ReplyTo.Name.Length != 0)
{ WrITeToStream(ref nwstream, "Reply-To: \"" + msg.ReplyTo.Name + "\" <" +
msg.ReplyTo.Address + ">\r\n"); }
else
{ WrITeToStream(ref nwstream, "Reply-To: <" + msg.ReplyTo.Address + ">\r\n"); }
if (msg.From.Name != null && msg.From.Name.Length != 0)
{ WrITeToStream(ref nwstream, "From: \"" + msg.From.Name + "\" <" +
msg.From.Address + ">\r\n"); }
else
{ WrITeToStream(ref nwstream, "From: <" + msg.From.Address + ">\r\n"); }
WrITeToStream(ref nwstream, "To: " + CreateAddressList(msg.To) + "\r\n");
if (msg.CC.Count != 0)
{ WrITeToStream(ref nwstream, "CC: " + CreateAddressList(msg.CC) + "\r\n"); }
WrITeToStream(ref nwstream, "Subject: " + msg.Subject + "\r\n");
if (msg.PriorITy != null)
{ WrITeToStream(ref nwstream, "X-PriorITy: " + msg.PriorITy + "\r\n"); }
if (msg.Headers.Count > 0)
{
SendHeaders(ref nwstream, msg);
}
if (msg.Attachments.Count > 0 || msg.HtmlBody != null)
{
SendMessageBody(ref nwstream, msg);
}
else
{
WrITeToStream(ref nwstream, msg.Body + "\r\n");
}
WrITeToStream(ref nwstream, "\r\n.\r\n");
CheckForError(ReadFromStream(ref nwstream), ReplyConstants.OK);
WrITeToStream(ref nwstream, "QUIT\r\n");
CheckForError(ReadFromStream(ref nwstream), ReplyConstants.QUIT);
CloseConnection();
}
private bool AuthLogin(ref NetworkStream nwstream)
{
if (username != null && username.Length > 0 && password != null && password.Length > 0)
{
WrITeToStream(ref nwstream, "AUTH LOGIN\r\n");
if (AuthImplemented(ReadFromStream(ref nwstream)))
{
WrITeToStream(ref nwstream, Convert.ToBase64String(
Encoding.ASCII.GetBytes(this.username.ToCharArray())) + "\r\n");
CheckForError(ReadFromStream(ref nwstream), ReplyConstants.SERVER_CHALLENGE);
WrITeToStream(ref nwstream, Convert.ToBase64String(Encoding.ASCII.GetBytes(
this.password.ToCharArray())) + "\r\n");
CheckForError(ReadFromStream(ref nwstream), ReplyConstants.AUTH_SUCCESSFUL);
return true;
}
}
return false;
}
总结
本文介绍了.NET中三种不同的使用SMTP协议发送邮件的方法,其中第一种(使用SmtpMail类)方案能满足大部分基本的发送邮件的功能需求,而第二种(使用CDO组件)和第三种(使用Socket自己撰写SMTP类)方案提供更自由和完整的定制方法,比如他们都能实现第一种方案不能做到的通过带认证的SMTP服务器发送邮件的功能。