C# - MailSender 邮件发送组件源代码 (支持ESMTP, 附件)

//============================================================
// File: MailSender.cs
// 邮件发送组件
// 支持ESMTP, 多附件
//============================================================

namespace JcPersonal.Utility
{
using System;
using System.Collections;
using System.Net.Sockets;
using System.IO;
using System.Text;

///

1<summary>   
2/// Mail 发送器   
3/// </summary>

public class MailSender
{
///

1<summary>   
2/// SMTP服务器域名   
3/// </summary>

public string Server {
get { return server; }
set { if (value != server) server = value; }
} private string server = "";

///

1<summary>   
2/// SMTP服务器端口 [默认为25]   
3/// </summary>

public int Port {
get { return port; }
set { if (value != port) port = value; }
} private int port = 25;

///

1<summary>   
2/// 用户名 [如果需要身份验证的话]   
3/// </summary>

public string UserName {
get { return userName; }
set { if (value != userName) userName = value; }
} private string userName = "";

///

1<summary>   
2/// 密码 [如果需要身份验证的话]   
3/// </summary>

public string Password {
get { return password; }
set { if (value != password) password = value; }
} private string password = "";

///

1<summary>   
2/// 发件人地址   
3/// </summary>

public string From {
get { return from; }
set { if (value != from) from = value;}
} private string from = "";

///

1<summary>   
2/// 收件人地址   
3/// </summary>

public string To {
get { return to; }
set { if (value != to) to = value;}
} private string to = "";

///

1<summary>   
2/// 发件人姓名   
3/// </summary>

public string FromName {
get { return fromName; }
set { if (value != fromName) fromName = value; }
} private string fromName = "";

///

1<summary>   
2/// 收件人姓名   
3/// </summary>

public string ToName {
get { return toName; }
set { if (value != toName) toName = value; }
} private string toName = "";

///

1<summary>   
2/// 邮件的主题   
3/// </summary>

public string Subject {
get { return subject; }
set { if (value != subject) subject = value; }
} private string subject = "";

///

1<summary>   
2/// 邮件正文   
3/// </summary>

public string Body {
get { return body; }
set { if (value != body) body = value; }
} private string body = "";

///

1<summary>   
2/// 超文本格式的邮件正文   
3/// </summary>

public string HtmlBody {
get { return htmlBody; }
set { if (value != htmlBody) htmlBody = value; }
} private string htmlBody = "";

///

1<summary>   
2/// 是否是html格式的邮件   
3/// </summary>

public bool IsHtml {
get { return isHtml; }
set { if (value != isHtml) isHtml = value; }
} private bool isHtml = false;

///

1<summary>   
2/// 语言编码 [默认为GB2312]   
3/// </summary>

public string LanguageEncoding {
get { return languageEncoding; }
set { if (value != languageEncoding) languageEncoding = value; }
} private string languageEncoding = "GB2312";

///

1<summary>   
2/// 邮件编码 [默认为8bit]   
3/// </summary>

public string MailEncoding {
get { return encoding; }
set { if (value != encoding) encoding = value; }
} private string encoding = "8bit";

///

1<summary>   
2/// 邮件优先级 [默认为3]   
3/// </summary>

public int Priority {
get { return priority; }
set { if (value != priority) priority = value; }
} private int priority = 3;

///

1<summary>   
2/// 附件 [AttachmentInfo]   
3/// </summary>

public IList Attachments {
get { return attachments; }
// set { if (value != attachments) attachments = value; }
} private ArrayList attachments = new ArrayList ();

///

1<summary>   
2/// 发送邮件   
3/// </summary>

public void SendMail ()
{
// 创建TcpClient对象, 并建立连接
TcpClient tcp = null;
try
{
tcp = new TcpClient (server, port);
}
catch (Exception)
{
throw new Exception ("无法连接服务器");
}

ReadString (tcp.GetStream());//获取连接信息

// 开始进行服务器认证
// 如果状态码是250则表示操作成功
if (!Command (tcp.GetStream(), "EHLO Localhost", "250"))
throw new Exception ("登陆阶段失败");

if (userName != "")
{
// 需要身份验证
if (!Command (tcp.GetStream(), "AUTH LOGIN", "334"))
throw new Exception ("身份验证阶段失败");
string nameB64 = ToBase64 (userName); // 此处将username转换为Base64码
if (!Command (tcp.GetStream(), nameB64, "334"))
throw new Exception ("身份验证阶段失败");
string passB64 = ToBase64 (password); // 此处将password转换为Base64码
if (!Command (tcp.GetStream(), passB64, "235"))
throw new Exception ("身份验证阶段失败");
}

// 准备发送
WriteString (tcp.GetStream(), "mail From: " + from);
WriteString (tcp.GetStream(), "rcpt to: " + to);
WriteString (tcp.GetStream(), "data");

// 发送邮件头
WriteString (tcp.GetStream(), "Date: " + DateTime.Now); // 时间
WriteString (tcp.GetStream(), "From: " + fromName + "<" + from + ">"); // 发件人
WriteString (tcp.GetStream(), "Subject: " + subject); // 主题
WriteString (tcp.GetStream(), "To:" + toName + "<" + to + ">"); // 收件人

//邮件格式
WriteString (tcp.GetStream(), "Content-Type: multipart/mixed; boundary="unique-boundary-1"");
WriteString (tcp.GetStream(), "Reply-To:" + from); // 回复地址
WriteString (tcp.GetStream(), "X-Priority:" + priority); // 优先级
WriteString (tcp.GetStream(), "MIME-Version:1.0"); // MIME版本

// 数据ID,随意
// WriteString (tcp.GetStream(), "Message-Id: " + DateTime.Now.ToFileTime() + "@security.com ");
WriteString (tcp.GetStream(), "Content-Transfer-Encoding:" + encoding); // 内容编码
WriteString (tcp.GetStream(), "X-Mailer:JcPersonal.Utility.MailSender"); // 邮件发送者
WriteString (tcp.GetStream(), "");

WriteString (tcp.GetStream(), ToBase64 ("This is a multi-part message in MIME format."));
WriteString (tcp.GetStream(), "");

// 从此处开始进行分隔输入
WriteString (tcp.GetStream(), "--unique-boundary-1");

// 在此处定义第二个分隔符
WriteString (tcp.GetStream(), "Content-Type: multipart/alternative;Boundary="unique-boundary-2"");
WriteString (tcp.GetStream(), "");

if(!isHtml)
{
// 文本信息
WriteString (tcp.GetStream(), "--unique-boundary-2");
WriteString (tcp.GetStream(), "Content-Type: text/plain;charset=" + languageEncoding);
WriteString (tcp.GetStream(), "Content-Transfer-Encoding:" + encoding);
WriteString (tcp.GetStream(), "");
WriteString (tcp.GetStream(), body);
WriteString (tcp.GetStream(), "");//一个部分写完之后就写如空信息,分段
WriteString (tcp.GetStream(), "--unique-boundary-2--");//分隔符的结束符号,尾巴后面多了--
WriteString (tcp.GetStream(), "");
}
else
{
//html信息
WriteString (tcp.GetStream(), "--unique-boundary-2");
WriteString (tcp.GetStream(), "Content-Type: text/html;charset=" + languageEncoding);
WriteString (tcp.GetStream(), "Content-Transfer-Encoding:" + encoding);
WriteString (tcp.GetStream(), "");
WriteString (tcp.GetStream(), htmlBody);
WriteString (tcp.GetStream(), "");
WriteString (tcp.GetStream(), "--unique-boundary-2--");//分隔符的结束符号,尾巴后面多了--
WriteString (tcp.GetStream(), "");
}

// 发送附件
// 对文件列表做循环
for (int i = 0; i < attachments.Count; i++)
{
WriteString (tcp.GetStream(), "--unique-boundary-1"); // 邮件内容分隔符
WriteString (tcp.GetStream(), "Content-Type: application/octet-stream;name="" + ((AttachmentInfo)attachments[i]).FileName + """); // 文件格式
WriteString (tcp.GetStream(), "Content-Transfer-Encoding: base64"); // 内容的编码
WriteString (tcp.GetStream(), "Content-Disposition:attachment;filename="" + ((AttachmentInfo)attachments[i]).FileName + """); // 文件名
WriteString (tcp.GetStream(), "");
WriteString (tcp.GetStream(), ((AttachmentInfo)attachments[i]).Bytes); // 写入文件的内容
WriteString (tcp.GetStream(), "");
}

Command (tcp.GetStream(), ".", "250"); // 最后写完了,输入"."

// 关闭连接
tcp.Close ();
}

///

1<summary>   
2/// 向流中写入字符   
3/// </summary>

///

1<param name="netStream"/>

来自TcpClient的流
///

1<param name="str"/>

写入的字符
protected void WriteString (NetworkStream netStream, string str)
{
str = str + "\r\n"; // 加入换行符

// 将命令行转化为byte[]
byte[] bWrite = Encoding.GetEncoding(languageEncoding).GetBytes(str.ToCharArray());

// 由于每次写入的数据大小是有限制的,那么我们将每次写入的数据长度定在75个字节,一旦命令长度超过了75,就分步写入。
int start=0;
int length=bWrite.Length;
int page=0;
int size=75;
int count=size;
try
{
if (length>75)
{
// 数据分页
if ((length/size)*size

  1<length) (i="page-1)" (int="" <summary="" catch(exception)="" count="length-(i*size);" else="" for="" i="0;i&lt;page;i++)" if="" netstream.write(bwrite,0,bwrite.length);="" netstream.write(bwrite,start,count);="" page="length/size;" start="i*size;" {="" }="" 将数据写入到服务器上="" 忽略错误="">   
  2/// 从流中读取字符   
  3///    
  4/// <param name="netStream"/>来自TcpClient的流   
  5/// <returns>读取的字符</returns>   
  6protected string ReadString (NetworkStream netStream)   
  7{   
  8string sp = null;   
  9byte[] by = new byte[1024];   
 10int size = netStream.Read(by,0,by.Length);// 读取数据流   
 11if (size &gt; 0)   
 12{   
 13sp = Encoding.Default.GetString(by);// 转化为String   
 14}   
 15return sp;   
 16} 
 17
 18/// <summary>   
 19/// 发出命令并判断返回信息是否正确   
 20/// </summary>   
 21/// <param name="netStream"/>来自TcpClient的流   
 22/// <param name="command"/>命令   
 23/// <param name="state"/>正确的状态码   
 24/// <returns>是否正确</returns>   
 25protected bool Command (NetworkStream netStream, string command, string state)   
 26{   
 27string sp=null;   
 28bool success=false;   
 29try   
 30{   
 31WriteString (netStream, command);// 写入命令   
 32sp = ReadString (netStream);// 接受返回信息   
 33if (sp.IndexOf(state) != -1)// 判断状态码是否正确   
 34success=true;   
 35}   
 36catch(Exception)   
 37{   
 38// 忽略错误   
 39}   
 40return success;   
 41} 
 42
 43/// <summary>   
 44/// 字符串编码为Base64   
 45/// </summary>   
 46/// <param name="str"/>字符串   
 47/// <returns>Base64编码的字符串</returns>   
 48protected string ToBase64 (string str)   
 49{   
 50try   
 51{   
 52byte[] by = Encoding.Default.GetBytes (str.ToCharArray());   
 53str = Convert.ToBase64String (by);   
 54}   
 55catch(Exception)   
 56{   
 57// 忽略错误   
 58}   
 59return str;   
 60} 
 61
 62/// <summary>   
 63/// 附件信息   
 64/// </summary>   
 65public struct AttachmentInfo   
 66{   
 67/// <summary>   
 68/// 附件的文件名 [如果输入路径,则自动转换为文件名]   
 69/// </summary>   
 70public string FileName {   
 71get { return fileName; }   
 72set { fileName = Path.GetFileName(value); }   
 73} private string fileName; 
 74
 75/// <summary>   
 76/// 附件的内容 [由经Base64编码的字节组成]   
 77/// </summary>   
 78public string Bytes {   
 79get { return bytes; }   
 80set { if (value != bytes) bytes = value; }   
 81} private string bytes; 
 82
 83/// <summary>   
 84/// 从流中读取附件内容并构造   
 85/// </summary>   
 86/// <param name="ifileName"/>附件的文件名   
 87/// <param name="stream"/>流   
 88public AttachmentInfo (string ifileName, Stream stream)   
 89{   
 90fileName = Path.GetFileName (ifileName);   
 91byte[] by = new byte [stream.Length];   
 92stream.Read (by,0,(int)stream.Length); // 读取文件内容   
 93//格式转换   
 94bytes = Convert.ToBase64String (by); // 转化为base64编码   
 95} 
 96
 97/// <summary>   
 98/// 按照给定的字节构造附件   
 99/// </summary>   
100/// <param name="ifileName"/>附件的文件名   
101/// <param name="ibytes"/>附件的内容 [字节]   
102public AttachmentInfo (string ifileName, byte[] ibytes)   
103{   
104fileName = Path.GetFileName (ifileName);   
105bytes = Convert.ToBase64String (ibytes); // 转化为base64编码   
106} 
107
108/// <summary>   
109/// 从文件载入并构造   
110/// </summary>   
111/// <param name="path"/>   
112public AttachmentInfo (string path)   
113{   
114fileName = Path.GetFileName (path);   
115FileStream file = new FileStream (path, FileMode.Open);   
116byte[] by = new byte [file.Length];   
117file.Read (by,0,(int)file.Length); // 读取文件内容   
118//格式转换   
119bytes = Convert.ToBase64String (by); // 转化为base64编码   
120file.Close ();   
121}   
122}   
123}   
124} 
125
126* * *
127
128// 使用: 
129
130MailSender ms = new MailSender ();   
131ms.From = " [email protected] ";   
132ms.To = " [email protected] ";   
133ms.Subject = "Subject";   
134ms.Body = "body text";   
135ms.UserName = "########"; // 怎么能告诉你呢   
136ms.Password = "********"; // 怎么能告诉你呢   
137ms.Server = "smtp.tom.com"; 
138
139ms.Attachments.Add (new MailSender.AttachmentInfo (@"D:\test.txt")); 
140
141Console.WriteLine ("mail sending...");   
142try   
143{   
144ms.SendMail ();   
145Console.WriteLine ("mail sended.");   
146}   
147catch (Exception e)   
148{   
149Console.WriteLine (e);   
150}</length)>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus