现在的位置: 首页 > 综合 > 正文

SMTP类

2013年12月12日 ⁄ 综合 ⁄ 共 35229字 ⁄ 字号 评论关闭

功能说明
=========
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 = @"&lt;html&gt;&lt;font
color='red'&gt;body&lt;/font&gt;&lt;br&gt;&lt;img
src = '1.gif'&gt;&lt;/html&gt;";
  /// 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();
      }
    }
  }  
}

【上篇】
【下篇】

抱歉!评论已关闭.