功能说明
=========
1. 支持身份验证。
2. 支持附件。
3. 支持无 SMTP 服务器的邮件直接投送功能。
4. 支持 HTML 邮件。
5. 支持 EMAIL 地址真实性验证功能。
代码演示
=========
1. 使用 Smtp Server 发送普通邮件
某些 Smtp Server (如:263.net) 要求发信人(From)地址必须是验证帐号的地址, 否则发送失败。
EMailSmtp smtp = new EMailSmtp();
smtp.SmtpServer = "smtp.263.net";
smtp.UserName = "username";
smtp.Password = "password";
EMailMessage message = new EMailMessage();
message.To = "q.yuhen@263.net";
message.From = "someone@sina.com.cn";
message.Subject = "标题";
message.Body = "邮件测试!";
message.Attachments.Add(@"c:/winnt/mmdet.log");
message.Attachments.Add(@"c:/winnt/hh.exe");
smtp.Send(message);
除了使用 EMailMessage 对象外,还可是使用另外一种简便模式发送
EMailSmtp smtp = new EMailSmtp();
smtp.SmtpServer = "smtp.263.net";
smtp.UserName = "username";
smtp.Password = "password";
smtp.Send("q.yuhen@263.net", "someone@sina.com.cn", "标题", "邮件测试");
2. 直投将邮件发送到对方信箱中,无需 SMTP 服务器。
DNS 服务器地址属性设置可省略,但是为了提高速度,建议使用本地 DNS 服务器。 直接发送时,一些服务器(如:263.net)要求接收人和发送人地址不能相同,否则将失败。 而且,接收人不能包含多个地址,也就是说不能使用 ";" 来连接多个地址。
EMailSmtp smtp = new EMailSmtp();
smtp.DnsServer = "192.168.0.1";
EMailMessage message = new EMailMessage();
message.To = "q.yuhen@263.net";
message.From = "someone@sina.com.cn";
message.Subject = "标题";
message.Body = "邮件测试!";
message.Attachments.Add(@"c:/winnt/mmdet.log");
message.Attachments.Add(@"c:/winnt/hh.exe");
smtp.SendEMS(message);
同样也可以使用简便模式发送
EMailSmtp smtp = new EMailSmtp();
smtp.DnsServer = "192.168.0.1";
smtp.SendEMS("q.yuhen@263.net", "someone@sina.com.cn", "标题", "邮件测试");
3. HTML 邮件发送
由于 HTML 内部的图片可能使用相对路径,因此您必须指定 HtmlBaseUrl,也就是 HTML 文件所在路径。 同样支持直接投送和简便模式,请参考上面代码。
EMailSmtp smtp = new EMailSmtp();
smtp.SmtpServer = "smtp.263.net";
smtp.UserName = "username";
smtp.Password = "password";
EMailMessage message = new EMailMessage();
message.To = "q.yuhen@263.net";
message.From = "someone@sina.com.cn";
message.Subject = "标题";
message.Body = @"<html><font color='red'>body</font><br><img src = '1.gif'></html>";
message.HtmlBaseUrl = @"D:/System/My Documents/My Pictures/";
message.BodyFormat = EMailFormat.Html;
message.Attachments.Add(@"c:/winnt/mmdet.log");
message.Attachments.Add(@"c:/winnt/hh.exe");
smtp.Send(message);
4. HTML 文件邮件发送
使用 ImportHtmlFile 将 HTML 文件导入到 EMailMessage 对象时,无需指定 HtmlBaseUrl 和 BodyFormat 属性。同样支持直接投送和简便模式,请参考上面代码。
EMailSmtp smtp = new EMailSmtp();
smtp.SmtpServer = "smtp.263.net";
smtp.UserName = "username";
smtp.Password = "password";
EMailMessage message = new EMailMessage();
message.To = "q.yuhen@263.net";
message.From = "someone@sina.com.cn";
message.Subject = "标题";
message.ImportHtmlFile(@"D:/System/My Documents/Homepage/2003/index.htm");
message.Attachments.Add(@"c:/winnt/mmdet.log");
message.Attachments.Add(@"c:/winnt/hh.exe");
smtp.Send(message);
5. 验证 EMail 地址的真实性
部分邮件服务器对 RCPT TO 命令并不作验证,因此这个功能并不能保证 100% 正确。
EMailSmtp smtp = new EMailSmtp();
Console.WriteLine(smtp.EMailExists("q.yuhen@263.net"));
源代码
========
ESmtp.cs
* Rainsoft Development Library for Microsoft.NET
*
* Copyright (c) 2004,2005 RainTrail Studio.China
* All Rigths Reserved!
* Author: Q.yuhen (qyuhen@hotmail.com)
********************************************** */
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using Rainsoft.Text;
namespace Rainsoft.Network
{
#region Message
/// <summary>
/// 正文格式
/// </summary>
public enum EMailFormat
{
/// <summary>
/// 文本
/// </summary>
Text,
/// <summary>
/// HTML
/// </summary>
Html
}
/// <summary>
/// 优先级
/// </summary>
public enum EMailPriority
{
/// <summary>
/// 普通
/// </summary>
Normal,
/// <summary>
/// 低
/// </summary>
Low,
/// <summary>
/// 高
/// </summary>
High
}
/// <summary>
/// 邮件消息构造类
/// </summary>
public class EMailMessage
{
private string partRoot = "=====000_ROOT=====";
private string partSon = "=====001_SON=====";
private string partGrandSon = "=====002_GRANDSON=====";
private string partStart = "--{0}";
private string partEnd = "--{0}--";
private string CRLF = "/r/n";
private string conTransEncoding = "Content-Transfer-Encoding: base64";
private string body = "";
private string cc = "";
private string from = "";
private string subject = "";
private string to = "";
private string charset = "GB2312";
private string htmlBaseUrl = "";
private EMailPriority priority = EMailPriority.Normal;
private EMailFormat bodyFormat = EMailFormat.Text;
private ArrayList attachments = new ArrayList();
private ArrayList images = new ArrayList();
/// <summary>
/// 附件
/// </summary>
public ArrayList Attachments
{
get { return attachments; }
}
/// <summary>
/// 正文
/// </summary>
public string Body
{
get { return body; }
set { body = value; }
}
/// <summary>
/// 正文类型
/// </summary>
public EMailFormat BodyFormat
{
get { return bodyFormat; }
set { bodyFormat = value; }
}
/// <summary>
/// 抄送
/// </summary>
public string Cc
{
get { return cc; }
set { cc = value; }
}
/// <summary>
/// 发信人
/// </summary>
public string From
{
get { return from; }
set { from = value; }
}
/// <summary>
/// 优先级
/// </summary>
public EMailPriority Priority
{
get { return priority; }
set { priority = value; }
}
/// <summary>
/// 标题
/// </summary>
public string Subject
{
get { return subject; }
set { subject = value; }
}
/// <summary>
/// 收信人
/// </summary>
public string To
{
get { return to; }
set { to = value; }
}
/// <summary>
/// 字符集
/// </summary>
public string Charset
{
get { return charset; }
set { charset = value; }
}
/// <summary>
/// HTML 邮件图片的基地址
/// </summary>
public string HtmlBaseUrl
{
get { return htmlBaseUrl; }
set { htmlBaseUrl = value; }
}
/// <summary>
/// 对邮件进行编码
/// </summary>
/// <returns></returns>
public string Encode()
{
string htmlText = "Html Mail";
string conTypeRelat = "Content-Type: multipart/related;";
string conTypeText = "Content-Type: text/plain;";
string conTypeAlter = "Content-Type: multipart/alternative;";
string conTypeHtml = "Content-Type: text/html;";
string conTypeMixed = "Content-Type: multipart/mixed;";
string mimeMessage = "This is a multi-part message in MIME format." ;
string typeAlter = "/ttype=multipart/alternative";
string charsetx = "/tcharset=/"{0}/"";
string boundary = "/tboundary=/"{0}/"";
try
{
StringBuilder temp = new StringBuilder();
// HEAD -----------------------------------------------------------
// from
temp.Append(string.Format("From:{0} ", from));
temp.Append(CRLF);
// to
string[] tos = to.Split(new char[] {';'});
temp.Append("To: ");
for( int i=0; i< tos.Length; i++)
{
temp.Append( i > 0 ? "," : "" );
temp.Append(tos[i]);
}
temp.Append(CRLF);
// cc
if(cc != null)
{
tos= cc.Split(new char[] {';'});
temp.Append("Cc: ");
for( int i=0; i< tos.Length; i++)
{
temp.Append( i > 0 ? "," : "" );
temp.Append(tos[i]);
}
temp.Append(CRLF);
}
// date
temp.Append(string.Format("Date: {0}", DateTime.Now.ToString("r")));
temp.Append(CRLF);
// subject
temp.Append(string.Format("Subject: =?{0}?B?{1}?=", charset, Base64.String(subject)));
temp.Append(CRLF);
// mime version
temp.Append("MIME-Version: 1.0");
temp.Append(CRLF);
// priority
temp.Append(string.Format("X-Priority: {0}", (int)priority));
temp.Append(CRLF);
// x-mailer
temp.Append("X-Mailer: Rainsoft Mail Sender.");
temp.Append(CRLF);
// CONTENT -------------------------------------------
// content
if (attachments.Count == 0)
{
if (bodyFormat == EMailFormat.Text)
{
temp.Append(conTypeText);
temp.Append(CRLF);
temp.Append(string.Format(charsetx, charset));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append(CRLF);
// text body
temp.Append(Base64.String(body));
temp.Append(CRLF);
}
else
{
temp.Append(conTypeRelat);
temp.Append(CRLF);
temp.Append(string.Format(boundary, partRoot));
temp.Append(CRLF);
temp.Append(typeAlter);
temp.Append(CRLF);
temp.Append(CRLF);
temp.Append(mimeMessage);
temp.Append(CRLF);
temp.Append(CRLF);
// root start
temp.Append(string.Format(partStart, partRoot));
temp.Append(CRLF);
temp.Append(conTypeAlter);
temp.Append(CRLF);
temp.Append(string.Format(boundary, partSon));
temp.Append(CRLF);
temp.Append(CRLF);
// text body
temp.Append(string.Format(partStart, partSon));
temp.Append(CRLF);
temp.Append(conTypeText);
temp.Append(CRLF);
temp.Append(string.Format(charsetx, charset));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append(CRLF);
temp.Append(Base64.String(htmlText));
temp.Append(CRLF);
temp.Append(CRLF);
// html body
temp.Append(string.Format(partStart, partSon));
temp.Append(CRLF);
temp.Append(conTypeHtml);
temp.Append(CRLF);
temp.Append(string.Format(charsetx, charset));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append(CRLF);
encodeHtmlBody(temp);
temp.Append(CRLF);
temp.Append(CRLF);
// son end
temp.Append(string.Format(partEnd, partSon));
temp.Append(CRLF);
temp.Append(CRLF);
// html images
encodeImages(temp);
}
}
else
{
if (bodyFormat == EMailFormat.Text)
{
// root start
temp.Append(conTypeMixed );
temp.Append(CRLF);
temp.Append(string.Format(boundary, partRoot));
temp.Append(CRLF);
temp.Append(CRLF);
temp.Append(mimeMessage);
temp.Append(CRLF);
temp.Append(CRLF);
// text body
temp.Append(string.Format(partStart, partRoot));
temp.Append(CRLF);
temp.Append(conTypeText);
temp.Append(CRLF);
temp.Append(string.Format(charsetx, charset));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append(CRLF);
temp.Append(Base64.String(body));
temp.Append(CRLF);
temp.Append(CRLF);
}
else
{
temp.Append(conTypeMixed);
temp.Append(CRLF);
temp.Append(string.Format(boundary, partRoot));
temp.Append(CRLF);
temp.Append(CRLF);
temp.Append(mimeMessage);
temp.Append(CRLF);
temp.Append(CRLF);
// root start
temp.Append(string.Format(partStart, partRoot));
temp.Append(CRLF);
temp.Append(conTypeRelat);
temp.Append(CRLF);
temp.Append(string.Format(boundary, partSon));
temp.Append(CRLF);
temp.Append(typeAlter);
temp.Append(CRLF);
temp.Append(CRLF);
// son start
temp.Append(string.Format(partStart, partSon));
temp.Append(CRLF);
temp.Append(conTypeAlter);
temp.Append(CRLF);
temp.Append(string.Format(boundary, partGrandSon));
temp.Append(CRLF);
temp.Append(CRLF);
// text body
temp.Append(string.Format(partStart, partGrandSon));
temp.Append(CRLF);
temp.Append(conTypeText);
temp.Append(CRLF);
temp.Append(string.Format(charsetx, charset));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append(CRLF);
temp.Append(Base64.String(htmlText));
temp.Append(CRLF);
temp.Append(CRLF);
// html body
temp.Append(string.Format(partStart, partGrandSon));
temp.Append(CRLF);
temp.Append(conTypeHtml);
temp.Append(CRLF);
temp.Append(string.Format(charsetx, charset));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append(CRLF);
encodeHtmlBody(temp);
temp.Append(CRLF);
temp.Append(CRLF);
// grandson end
temp.Append(string.Format(partEnd, partGrandSon));
temp.Append(CRLF);
temp.Append(CRLF);
// html images
encodeImages(temp);
// son end
temp.Append(string.Format(partEnd, partSon));
temp.Append(CRLF);
temp.Append(CRLF);
}
}
// attchments
encodeAttachments(temp);
temp.Append(string.Format(partEnd, partRoot));
temp.Append(CRLF);
return temp.ToString();
}
catch
{
return "";
}
}
/// <summary>
/// 导入 HTML 文件到正文
/// </summary>
public void ImportHtmlFile(string file)
{
if (File.Exists(file))
{
StreamReader r = new StreamReader(file, Encoding.Default);
body = r.ReadToEnd();
htmlBaseUrl = Path.GetDirectoryName(file);
bodyFormat = EMailFormat.Html;
}
}
/// <summary>
/// 对 HTML 正文进行编码。
/// </summary>
/// <param name="temp"></param>
private void encodeHtmlBody(StringBuilder temp)
{
// 搜索全部图像连接
string p = "(?<a1>//<img.*?)(src ?= ?[/"'])(?<url>.*?)([/"'])(?<a2>.*?//>)";
string s = Regex.Replace(body, p, new MatchEvaluator(matchEvaluator), RegexOptions.IgnoreCase | RegexOptions.Singleline);
p = "background ?= ?[/"'](?<url>.*?)[/"']";
s = Regex.Replace(s, p, new MatchEvaluator(matchEvaluator), RegexOptions.IgnoreCase | RegexOptions.Singleline);
temp.Append(Base64.String(s));
}
/// <summary>
/// Regex 回调函数。提取图片文件列表。
/// </summary>
private string matchEvaluator(Match match)
{
string file = match.Groups["url"].Value.ToLower();
// 还原正确路径
if (file.StartsWith("file://"))
file = file.Substring(7);
else
file = Path.Combine(htmlBaseUrl, file.Replace("/", @"/"));
// 添加到列表
if (File.Exists(file))
{
images.Add(file);
string cid = "cid:" + getImageCid(file, images.Count - 1); // cid 不能大写
if (match.Value.ToLower().StartsWith("background"))
return string.Format("background=/"{0}/"", cid);
else
return string.Format("{0}src=/"{1}/"{2}", match.Groups["a1"], cid, match.Groups["a2"]);
}
else
return match.Value;
}
/// <summary>
/// 获取 HTML 邮件中图片的 CID
/// </summary>
/// <param name="file">图片文件名</param>
/// <param name="index">在列表中的索引位置</param>
/// <returns></returns>
private string getImageCid(string file, int index)
{
// _主文件名(索引).扩展名
return string.Format("_{0}({1}){2}",
Path.GetFileNameWithoutExtension(file).Replace(" ", ""),
index,
Path.GetExtension(file).Replace(" ", ""));
}
/// <summary>
/// 对 HTML 图像进行编码
/// </summary>
private void encodeImages(StringBuilder temp)
{
if (bodyFormat == EMailFormat.Html && images.Count > 0)
{
for(int i = 0; i < images.Count; i++)
{
string file = (string)images[i];
if (!File.Exists(file)) continue;
if (attachments.Count == 0)
{
temp.Append(string.Format(partStart, partRoot));
temp.Append(CRLF);
}
else
{
temp.Append(string.Format(partStart, partSon));
temp.Append(CRLF);
}
string type = "";
switch (Path.GetExtension(file))
{
case ".jpg": type = "jpeg"; break;
default: type = Path.GetExtension(file).Substring(1); break;
}
temp.Append(string.Format("Content-Type: image/{0};", type));
temp.Append(CRLF);
temp.Append(string.Format("/tname=/"{0}/"", Path.GetFileName(file)));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append((string.Format("Content-ID: <{0}>", getImageCid(file, i))));
temp.Append(CRLF);
temp.Append(CRLF);
temp.Append(Base64.File(file));
temp.Append(CRLF);
}
}
}
/// <summary>
/// 对附件进行编码
/// </summary>
private void encodeAttachments(StringBuilder temp)
{
if (attachments.Count > 0)
{
foreach(object obj in attachments)
{
FileInfo info = new FileInfo((string)obj);
if (info.Exists)
{
temp.Append(string.Format(partStart, partRoot));
temp.Append(CRLF);
temp.Append("Content-Type: application/octet-stream;");
temp.Append(CRLF);
temp.Append(string.Format("/tname=/"{0}/"", info.Name));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append("Content-Disposition: attachment;");
temp.Append(CRLF);
temp.Append(string.Format("/tfilename=/"{0}/"", info.Name));
temp.Append(CRLF);
temp.Append(CRLF);
temp.Append(Base64.File(info.FullName));
temp.Append(CRLF);
}
}
}
}
}
#endregion
#region Smtp
/// <summary>
/// SMTP 邮件发送
/// </summary>
/// <remarks>
/// <para>1. 支持身份验证。 </para>
/// <para>2. 支持附件。</para>
/// <para>3. 支持无 SMTP 服务器的邮件直接投送功能。</para>
/// <para>4. 支持 HTML 邮件。</para>
/// <para>5. 支持 EMAIL 地址真实性验证功能。</para>
/// </remarks>
/// <example>
/// <para>1. 使用 Smtp Server 发送普通邮件</para>
/// 某些 Smtp Server (如:263.net) 要求发信人(From)地址必须是验证帐号的地址,
/// 否则发送失败。
/// <code>
/// EMailSmtp smtp = new EMailSmtp();
/// smtp.SmtpServer = "smtp.263.net";
/// smtp.UserName = "username";
/// smtp.Password = "password";
///
/// EMailMessage message = new EMailMessage();
/// message.To = "q.yuhen@263.net";
/// message.From = "someone@sina.com.cn";
/// message.Subject = "标题";
/// message.Body = "邮件测试!";
///
/// message.Attachments.Add(@"c:/winnt/mmdet.log");
/// message.Attachments.Add(@"c:/winnt/hh.exe");
///
/// smtp.Send(message);
/// </code>
/// 除了使用 EMailMessage 对象外,还可是使用另外一种简便模式发送
/// <code>
/// EMailSmtp smtp = new EMailSmtp();
/// smtp.SmtpServer = "smtp.263.net";
/// smtp.UserName = "username";
/// smtp.Password = "password";
/// smtp.Send("q.yuhen@263.net", "someone@sina.com.cn", "标题", "邮件测试");
/// </code>
/// <para>2. 直投将邮件发送到对方信箱中,无需 SMTP 服务器。</para>
/// DNS 服务器地址属性设置可省略,但是为了提高速度,建议使用本地 DNS 服务器。
/// 直接发送时,一些服务器(如:263.net)要求接收人和发送人地址不能相同,否则将失败。
/// 而且,接收人不能包含多个地址,也就是说不能使用 ";" 来连接多个地址。
/// <code>
/// EMailSmtp smtp = new EMailSmtp();
/// smtp.DnsServer = "192.168.0.1";
///
/// EMailMessage message = new EMailMessage();
/// message.To = "q.yuhen@263.net";
/// message.From = "someone@sina.com.cn";
/// message.Subject = "标题";
/// message.Body = "邮件测试!";
///
/// message.Attachments.Add(@"c:/winnt/mmdet.log");
/// message.Attachments.Add(@"c:/winnt/hh.exe");
///
/// smtp.SendEMS(message);
/// </code>
/// 同样也可以使用简便模式发送
/// <code>
/// EMailSmtp smtp = new EMailSmtp();
/// smtp.DnsServer = "192.168.0.1";
/// smtp.SendEMS("q.yuhen@263.net", "someone@sina.com.cn", "标题", "邮件测试");
/// </code>
/// <para>3. HTML 邮件发送</para>
/// <para>由于 HTML 内部的图片可能使用相对路径,因此您必须指定 HtmlBaseUrl,也就是 HTML 文件所在路径。
/// 同样支持直接投送和简便模式,请参考上面代码。</para>
/// <code>
/// EMailSmtp smtp = new EMailSmtp();
/// smtp.SmtpServer = "smtp.263.net";
/// smtp.UserName = "username";
/// smtp.Password = "password";
///
/// EMailMessage message = new EMailMessage();
/// message.To = "q.yuhen@263.net";
/// message.From = "someone@sina.com.cn";
/// message.Subject = "标题";
///
///
message.Body = @"<html><font
color='red'>body</font><br><img
src = '1.gif'></html>";
/// message.HtmlBaseUrl = @"D:/System/My Documents/My Pictures/";
/// message.BodyFormat = EMailFormat.Html;
///
/// message.Attachments.Add(@"c:/winnt/mmdet.log");
/// message.Attachments.Add(@"c:/winnt/hh.exe");
///
/// smtp.Send(message);
/// </code>
/// <para>4. HTML 文件邮件发送</para>
/// <para>使用 ImportHtmlFile 将 HTML 文件导入到 EMailMessage 对象时,无需指定 HtmlBaseUrl 和 BodyFormat
/// 属性。同样支持直接投送和简便模式,请参考上面代码。</para>
/// <code>
/// EMailSmtp smtp = new EMailSmtp();
/// smtp.SmtpServer = "smtp.263.net";
/// smtp.UserName = "username";
/// smtp.Password = "password";
///
/// EMailMessage message = new EMailMessage();
/// message.To = "q.yuhen@263.net";
/// message.From = "someone@sina.com.cn";
/// message.Subject = "标题";
///
/// message.ImportHtmlFile(@"D:/System/My Documents/Homepage/2003/index.htm");
///
/// message.Attachments.Add(@"c:/winnt/mmdet.log");
/// message.Attachments.Add(@"c:/winnt/hh.exe");
///
/// smtp.Send(message);
/// </code>
/// <para>5. 验证 EMail 地址的真实性</para>
/// <para> 部分邮件服务器对 RCPT TO 命令并不作验证,因此这个功能并不能保证 100% 正确。</para>
/// <code>
/// EMailSmtp smtp = new EMailSmtp();
/// Console.WriteLine(smtp.EMailExists("q.yuhen@263.net"));
/// </code>
/// </example>
public sealed class EMailSmtp
{
private string smtpServer = "localhost";
private string userName = "";
private string password = "";
private string dnsServer = "";
/// <summary>
/// 构造函数
/// </summary>
public EMailSmtp()
{
}
/// <summary>
/// Smtp 服务器地址。
/// </summary>
public string SmtpServer
{
set { smtpServer = value; }
get { return smtpServer; }
}
/// <summary>
/// Smtp 登录帐号。
/// </summary>
public string UserName
{
set { userName = value; }
get { return userName; }
}
/// <summary>
/// Smtp 登录密码。
/// </summary>
public string Password
{
set { password = value; }
get { return password; }
}
/// <summary>
/// 域名解析服务器
/// </summary>
public string DnsServer
{
set { dnsServer = value; }
get { return dnsServer; }
}
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="mailTo">接收人地址</param>
/// <param name="mailFrom">发送人地址</param>
/// <param name="subject">标题</param>
/// <param name="bodyText">正文</param>
/// <returns></returns>
public bool Send(string mailTo, string mailFrom, string subject, string bodyText)
{
EMailMessage mail = new EMailMessage();
mail.From = mailFrom;
mail.To = mailTo;
mail.Subject = subject;
mail.Body = bodyText;
mail.BodyFormat = EMailFormat.Text;
return this.Send(mail);
}
/// <summary>
/// EMS 方式发送邮件
/// </summary>
public bool SendEMS(string mailTo, string mailFrom, string subject, string bodyText)
{
EMailMessage mail = new EMailMessage();
mail.From = mailFrom;
mail.To = mailTo;
mail.Subject = subject;
mail.Body = bodyText;
mail.BodyFormat = EMailFormat.Text;
return this.SendEMS(mail);
}
/// <summary>
/// 获取 MX 记录
/// </summary>
private MXRecord[] getMX(string email)
{
try
{
string host = email.Substring(email.IndexOf("@") + 1);
DnsMX mx = new DnsMX();
if (dnsServer != string.Empty) mx.AddDnsServer(dnsServer);
mx.AddDnsServer(new string[]{"202.102.192.68"}); // 添加辅助地址,防止用户输入的错误。
MXRecord[] list = mx.GetMXRecords(host);
if (list.Length == 0)
{
list = new MXRecord[1];
list[0].Exchange = host;
}
return list;
}
catch
{
}
return null;
}
/// <summary>
/// EMS 方式发送邮件
/// </summary>
public bool SendEMS(EMailMessage message)
{
try
{
int i = message.To.IndexOf(";");
if (i > -1) message.To = message.To.Substring(0, i);
MXRecord[] list = getMX(message.To);
foreach(MXRecord r in list)
{
this.smtpServer = r.Exchange;
this.userName = "";
this.password = "";
if (this.Send(message)) return true;
}
}
catch
{
}
return false;
}
/// <summary>
/// 发送邮件。
/// </summary>
/// <param name="message">邮件内容对象。</param>
/// <returns>是否发送成功。</returns>
public bool Send(EMailMessage message)
{
return this.smtp(message, false);
}
/// <summary>
/// 验证邮箱地址是否真实存在。
/// </summary>
/// <param name="email">邮件地址</param>
/// <returns></returns>
public bool EMailExists(string email)
{
EMailMessage message = new EMailMessage();
message.From = "test@sina.com.cn";
message.To = email;
MXRecord[] list = getMX(message.To);
foreach(MXRecord r in list)
{
this.smtpServer = r.Exchange;
this.userName = "";
this.password = "";
if (this.smtp(message, true)) return true;
}
return false;
}
/// <summary>
/// 邮件发送 AND 地址验证
/// </summary>
/// <param name="message">邮件内容对象。</param>
/// <param name="checkEMail">是否验证地址。</param>
/// <returns></returns>
private bool smtp(EMailMessage message, bool checkEMail)
{
try
{
IPHostEntry IPhst = Dns.Resolve(smtpServer);
IPEndPoint endPt = new IPEndPoint(IPhst.AddressList[0], 25);
Socket sock = new Socket(endPt.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// Connect to Smtp Server
sock.Connect(endPt);
if(!checkResponse(sock, 220))
{
sock.Close();
return false;
}
if(userName != "")
{
// ESMTP HELO
sendData(sock, string.Format("EHLO {0}/r/n", Dns.GetHostName() ));
if(!checkResponse(sock, 250))
{
sock.Close();
return false;
}
// AUTH LOGIN
sendData(sock, string.Format("AUTH LOGIN/r/n"));
if(!checkResponse(sock, 334))
{
sock.Close();
return false;
}
// USERNAME
sendData(sock, string.Format("{0}/r/n",Base64.String(userName)));
if(!checkResponse(sock, 334))
{
sock.Close();
return false;
}
// PASSWORD
sendData(sock, string.Format("{0}/r/n",Base64.String(password)));
if(!checkResponse(sock, 235))
{
sock.Close();
return false;
}
}
else
{
// SMTP HELO
sendData(sock, string.Format("HELO {0}/r/n", Dns.GetHostName() ));
if(!checkResponse(sock, 250))
{
sock.Close();
return false;
}
}
// MAIL FROM
sendData(sock, string.Format("MAIL From:{0}/r/n", message.From));
if(!checkResponse(sock, 250))
{
sock.Close();
return false;
}
// RCPT TO
string[] tos = message.To.Split(new char[] {';'});
foreach (string to in tos)
{
sendData(sock, string.Format("RCPT TO:<{0}>/r/n", to));
if(!checkResponse(sock, 250))
{
sock.Close();
return false;
}
else
{
// 验证 EMail 地址是否存在。
if (checkEMail)
{
// QUIT
sendData(sock, "QUIT/r/n");
checkResponse(sock, 221);
sock.Close();
return true;
}
}
}
// CC
if(message.Cc != "")
{
tos = message.Cc.Split(new char[] {';'});
foreach (string To in tos)
{
sendData(sock, string.Format("RCPT TO:<{0}>/r/n", To));
if(!checkResponse(sock, 250))
{
sock.Close();
return false;
}
}
}
// DATA
sendData(sock, ("DATA/r/n"));
if(!checkResponse(sock, 354))
{
sock.Close();
return false;
}
sendData(sock, message.Encode());
sendData(sock, "./r/n");
if(!checkResponse(sock, 250))
{
sock.Close();
return false;
}
// QUIT
sendData(sock, "QUIT/r/n");
checkResponse(sock, 221);
sock.Close();
return true;
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
return false;
}
}
/// <summary>
/// 发送数据到服务器。
/// </summary>
/// <param name="sock"></param>
/// <param name="msg"></param>
private void sendData(Socket sock, string msg)
{
byte[] s = Encoding.ASCII.GetBytes(msg);
sock.Send(s, 0, s.Length, SocketFlags.None);
}
/// <summary>
/// 检查服务器返回指令。
/// </summary>
/// <param name="sock"></param>
/// <param name="responseExpected"></param>
/// <returns></returns>
private bool checkResponse(Socket sock, int responseExpected)
{
string sResponse;
int response;
byte[] bytes = new byte[1024];
while (sock.Available == 0)
{
System.Threading.Thread.Sleep(100);
}
sock.Receive(bytes, 0, sock.Available, SocketFlags.None);
sResponse = Encoding.ASCII.GetString(bytes);
response = Convert.ToInt32(sResponse.Substring(0, 3));
if(response != responseExpected) return false;
return true;
}
}
#endregion
}
DnsMX.cs
* Rainsoft Development Library for Microsoft.NET
*
* Copyright (c) 2004,2005 RainTrail Studio.China
* All Rigths Reserved!
* Author: Q.yuhen (qyuhen@hotmail.com)
********************************************** */
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Net.Sockets;
using System.Collections;
namespace Rainsoft.Network
{
#region DnsMX
/// <summary>
/// DnsMX 结构
/// </summary>
public struct MXRecord
{
/// <summary>
/// 优先级
/// </summary>
public int Preference;
/// <summary>
/// 主机地址
/// </summary>
public string Exchange;
/// <summary>
/// 转换成字符串
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Exchange + ":" + Preference.ToString();
}
}
#endregion
/// <summary>
/// 通过 DNS 服务器查询邮件服务器 MX 记录
/// </summary>
/// <example>
/// <code>
/// DnsMX mx = new DnsMX();
/// mx.AddDnsServer("158.152.1.58");
/// MXRecord[] results = mx.GetMXRecords("263.net");
///
/// foreach(MXRecord m in results)
/// {
/// Console.WriteLine(m);
/// }
/// </code>
/// </example>
public sealed class DnsMX
{
private byte[] data;
private int position, id, length;
private string name;
private ArrayList dnsServers;
private static int DNS_PORT = 53;
private System.Text.Encoding ASCII = Encoding.ASCII;
/// <summary>
/// 构造
/// </summary>
public DnsMX()
{
id = DateTime.Now.Millisecond * 60;
dnsServers = new ArrayList();
}
/// <summary>
/// 添加 DNS 服务器
/// </summary>
/// <param name="dnsServer"></param>
public void AddDnsServer(string dnsServer)
{
this.dnsServers.Add(dnsServer);
}
/// <summary>
/// 添加 DNS 服务器
/// </summary>
/// <param name="dnsServers"></param>
public void AddDnsServer(System.Collections.ICollection dnsServers)
{
this.dnsServers.AddRange(dnsServers);
}
/// <summary>
/// 返回 MX 记录
/// </summary>
/// <param name="host"></param>
/// <returns></returns>
public MXRecord[] GetMXRecords(string host)
{
MXRecord[] result = null;
foreach(object o in dnsServers)
{
try
{
result = getMXRecords(host, (string)o);
break;
}
catch(IOException)
{
continue;
}
}
return result;
}
/// <summary>
/// 网络查询
/// </summary>
/// <param name="host"></param>
/// <param name="serverAddress"></param>
/// <returns></returns>
private MXRecord[] getMXRecords(string host, string serverAddress)
{
UdpClient dnsClient = new UdpClient(serverAddress, DNS_PORT);
makeQuery(++id, host);
dnsClient.Send(data, data.Length);
IPEndPoint endpoint = null;
data = dnsClient.Receive(ref endpoint);
length = data.Length;
return makeResponse();
}
/// <summary>
/// 构造查询包
/// </summary>
/// <param name="id"></param>
/// <param name="name"></param>
private void makeQuery(int id, String name)
{
data = new byte[512];
for(int i = 0; i < 512; ++i) data[i] = 0;
data[0] = (byte) (id >> 8);
data[1] = (byte) (id & 0xFF );
data[2] = (byte) 1; data[3] = (byte) 0;
data[4] = (byte) 0; data[5] = (byte) 1;
data[6] = (byte) 0; data[7] = (byte) 0;
data[8] = (byte) 0; data[9] = (byte) 0;
data[10] = (byte) 0; data[11] = (byte) 0;
string[] tokens = name.Split(new char[] {'.'});
string label;
position = 12;
for(int j = 0; j < tokens.Length; j++)
{
label = tokens[j];
data[position++] = (byte) (label.Length & 0xFF);
byte[] b = ASCII.GetBytes(label);
for(int k=0; k < b.Length; k++)
{
data[position++] = b[k];
}
}
data[position++] = (byte) 0 ; data[position++] = (byte) 0;
data[position++] = (byte) 15; data[position++] = (byte) 0 ;
data[position++] = (byte) 1 ;
}
/// <summary>
/// 分解反馈包
/// </summary>
/// <returns></returns>
private MXRecord[] makeResponse()
{
ArrayList list = new ArrayList();
MXRecord mx;
int qCount = ((data[4] & 0xFF) << 8) | (data[5] & 0xFF);
if (qCount < 0) throw new IOException("invalid question count");
int aCount = ((data[6] & 0xFF) << 8) | (data[7] & 0xFF);
if (aCount < 0) throw new IOException("invalid answer count");
position=12;
for( int i = 0; i < qCount; ++i)
{
name = "";
position = proc(position);
position += 4;
}
for (int i = 0; i < aCount; ++i)
{
name = "";
position = proc(position);
position+=10;
int pref = (data[position++] << 8) | (data[position++] & 0xFF);
name = "";
position = proc(position);
mx.Preference = pref;
mx.Exchange = name;
list.Add(mx);
}
return (MXRecord[])list.ToArray(typeof(MXRecord));
}
private int proc(int position)
{
int len = (data[position++] & 0xFF);
if(len == 0) return position;
int offset;
do
{
if ((len & 0xC0) == 0xC0)
{
if (position >= length) return -1;
offset = ((len & 0x3F) << 8) | (data[position++] & 0xFF);
proc(offset);
return position;
}
else
{
if ((position + len) > length) return -1;
name += ASCII.GetString(data, position, len);
position += len;
}
if (position > length) return -1;
len = data[position++] & 0xFF;
if (len != 0) name += ".";
}
while (len != 0);
return position;
}
}
}
Base64.cs
* Rainsoft Development Library for Microsoft.NET
*
* Copyright (c) 2004,2005 RainTrail Studio.China
* All Rigths Reserved!
* Author: Q.yuhen (qyuhen@hotmail.com)
********************************************** */
using System;
using System.Text;
using System.IO;
namespace Rainsoft.Text
{
/// <summary>
/// BASE64 编码
/// </summary>
public sealed class Base64
{
private Base64(){}
/// <summary>
/// 对字符串进行 base64 编码。
/// </summary>
/// <param name="str">待编码的字符串</param>
/// <returns></returns>
public static string String(string str)
{
try
{
byte[] by = System.Text.Encoding.Default.GetBytes(str);
str = Convert.ToBase64String(by);
}
catch(Exception)
{
}
return str;
}
/// <summary>
/// 对文件进行 base64 编码。
/// </summary>
/// <param name="file">对文件进行编码</param>
/// <returns></returns>
public static string File(string file)
{
byte[] binaryData;
StringBuilder result = new StringBuilder();
FileInfo info = new FileInfo(file);
FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
try
{
binaryData = new Byte[fs.Length];
long bytesRead = fs.Read(binaryData, 0, (int)fs.Length);
string base64String = System.Convert.ToBase64String(binaryData, 0, binaryData.Length);
for(int i = 0; i < base64String.Length ; )
{
int nextchunk = 100;
if (base64String.Length - (i + nextchunk ) < 0) nextchunk = base64String.Length - i;
result.Append(base64String.Substring(i, nextchunk));
result.Append("/r/n");
i += nextchunk;
}
return result.ToString();
}
finally
{
fs.Close();
}
}
}
}