以前我们公司是有网上的群发软件,每天每次都发有上十万份电子日刊,但是根据用户回应,以及公司内部推测,
得到群发软件效果不好,发送成功率很低;又由于公司内部特殊需求,公司决定自己开发。
前些日子,经理让我开发一个群发软件,当时我很软松的接下啦,因为以前研究过类似问题,也做过单发软件邮件
功能,用的是微软自带的邮件发送类库(System.Web.Mail)MailMessage、SmtpMail两个类
(初期过程:http://blog.csdn.net/mlks_2008/archive/2007/04/22/1574864.aspx),想心把这个单发做成模块或类库
不就可以了吗,又没有什么大问题。回去就把SMTP服务装上了,程序很快就搞定了,发送邮件时报错,
捕获的异常信息是“未能访问"CDO.Message"对象”,到时网上查了一下,原因是我的WIN2003系统没有cdonts.dll,在WIN2000
找了一个此文件,在DOS窗口内,进入System32目录下,执行regsvr32 cdonts.dll 注册了一下,发送成功了.之后传到
服务器上,公司人员用它发送,公司的邮箱、163邮件都可以收到邮件;用了大半个月后发现hotmail.com、163.com邮箱
有时能收到,有时收不到,只有公司邮箱正常.查了几天也不知道是什么原因。只好另换其它,之后找了三个类库(Jmail类,
web service,编写的类库),而且当前使用的方法比.net自带的类库更好,有发送成功失败返回值(有时不能返回与机子安全性
配制有关,要开放一些端口,禁用邮件收发限制等)。
目前邮件发送还有一个问题,就是hotmail.com等邮箱把邮件识别为垃圾邮件,正在研究中,待以后补充...
内容简写不少,有兴趣的可以与我联系。一起讨论 QQ:67222474 MSN:mlks_2008@hotmail.com
目前使用的发送类库:
/* **********************************************
* 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 = " " ;
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 = " type=multipart/alternative " ;
string charsetx = " charset="{0}" " ;
string boundary = " boundary="{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( " name="{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( " name="{0}" " , info.Name));
temp.Append(CRLF);
temp.Append(conTransEncoding);
temp.Append(CRLF);
temp.Append( " Content-Disposition: attachment; " );
temp.Append(CRLF);
temp.Append( string .Format( " filename="{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:winntmmdet.log");
/// message.Attachments.Add(@"c:winnthh.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:winntmmdet.log");
/// message.Attachments.Add(@"c:winnthh.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:SystemMy DocumentsMy Pictures";
/// message.BodyFormat = EMailFormat.Html;
///
/// message.Attachments.Add(@"c:winntmmdet.log");
/// message.Attachments.Add(@"c:winnthh.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:SystemMy DocumentsHomepage3index.htm");
///
/// message.Attachments.Add(@"c:winntmmdet.log");
/// message.Attachments.Add(@"c:winnthh.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} " , Dns.GetHostName() ));
if ( ! checkResponse(sock, 250 ))
{
sock.Close();
return false ;
}
// AUTH LOGIN
sendData(sock, string .Format( " AUTH LOGIN " ));
if ( ! checkResponse(sock, 334 ))
{
sock.Close();
return false ;
}
// USERNAME
sendData(sock, string .Format( " {0} " ,Base64.String(userName)));
if ( ! checkResponse(sock, 334 ))
{
sock.Close();
return false ;
}
// PASSWORD
sendData(sock, string .Format( " {0} " ,Base64.String(password)));
if ( ! checkResponse(sock, 235 ))
{
sock.Close();
return false ;
}
}
else
{
// SMTP HELO
sendData(sock, string .Format( " HELO {0} " , Dns.GetHostName() ));
if ( ! checkResponse(sock, 250 ))
{
sock.Close();
return false ;
}
}
// MAIL FROM
sendData(sock, string .Format( " MAIL From:{0} " , 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}> " , to));
if ( ! checkResponse(sock, 250 ))
{
sock.Close();
return false ;
}
else
{
// 验证 EMail 地址是否存在。
if (checkEMail)
{
// QUIT
sendData(sock, " QUIT " );
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}> " , To));
if ( ! checkResponse(sock, 250 ))
{
sock.Close();
return false ;
}
}
}
// DATA
sendData(sock, ( " DATA " ));
if ( ! checkResponse(sock, 354 ))
{
sock.Close();
return false ;
}
sendData(sock, message.Encode());
sendData(sock, " . " );
if ( ! checkResponse(sock, 250 ))
{
sock.Close();
return false ;
}
// QUIT
sendData(sock, " QUIT " );
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
}
/* **********************************************
* Rainsoft Development Library for Microsoft.NET
*
* Copyright (c) 2004,2005 RainTrail Studio.China
* All Rigths Reserved!
* Author: Q.yuhen (qyuhen@hotmail.com)
********************************************** */
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;
}
}
}
/* **********************************************
* Rainsoft Development Library for Microsoft.NET
*
* Copyright (c) 2004,2005 RainTrail Studio.China
* All Rigths Reserved!
* Author: Q.yuhen (qyuhen@hotmail.com)
********************************************** */
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( " " );
i += nextchunk;
}
return result.ToString();
}
finally
{
fs.Close();
}
}
}
}