菜鸟学堂:
/******************************************************
filename:
copyright (c) 2003-xxxx *********公司技术开发部
writer:
create date:2004-12-20
rewriter:
rewrite date:
impact:
main content:(function name、parameters、returns)
支持esmtp, 多附件
******************************************************/
using system;
using system.collections;
using system.net.sockets;
using system.io;
using system.text;
namespace edu.stu.common.mail
{
///<summary>
/// module id:0005
/// depiction:发送邮件,支持esmtp, 多附件
/// wreter:nick
/// create date;2004-12-20
///</summary>
public class mailsender
{
#region "fields"
private string m_strfromname = "";
private string[] m_strto = null;
private string m_strfrom = "";
private string m_strpassword = "";
private string m_strusername = "";
private int m_iport = 25;
private string m_strserver = "";
private int m_ipriority = 3;
private string m_strencoding = "8bit";
private string m_strlanguageencoding = "gb2312";
private bool m_bishtml = true;
private string m_strhtmlbody = "";
private string m_strtxtbody = "";
private string m_strsubject = "";
private string m_strtoname = "";
private arraylist m_alattachments = new arraylist ();
#endregion
#region "propertes"
/// <summary>
/// smtp服务器域名
/// </summary>
public string server
{
get { return m_strserver; }
set { if (value != m_strserver) m_strserver = value; }
}
/// <summary>
/// smtp服务器端口 [默认为25]
/// </summary>
public int port {
get { return m_iport; }
set { if (value != m_iport) m_iport = value; }
}
/// <summary>
/// 用户名 [如果需要身份验证的话]
/// </summary>
public string username
{
get { return m_strusername; }
set { if (value != m_strusername) m_strusername = value; }
}
/// <summary>
/// 密码 [如果需要身份验证的话]
/// </summary>
public string password
{
get { return m_strpassword; }
set { if (value != m_strpassword) m_strpassword = value; }
}
/// <summary>
/// 发件人地址
/// </summary>
public string from
{
get { return m_strfrom; }
set { if (value != m_strfrom) m_strfrom = value;}
}
/// <summary>
/// 收件人地址
/// </summary>
public string[] to
{
get { return m_strto; }
set { if (value != m_strto) m_strto = value;}
}
/// <summary>
/// 发件人姓名
/// </summary>
public string fromname
{
get { return m_strfromname; }
set { if (value != m_strfromname) m_strfromname = value; }
}
/// <summary>
/// 收件人姓名
/// </summary>
public string toname
{
get { return m_strtoname; }
set { if (value != m_strtoname) m_strtoname = value; }
}
/// <summary>
/// 邮件的主题
/// </summary>
public string subject
{
get { return m_strsubject; }
set { if (value != m_strsubject) m_strsubject = value; }
}
/// <summary>
/// 邮件正文
/// </summary>
public string body
{
get { return m_strtxtbody; }
set { if (value != m_strtxtbody) m_strtxtbody = value; }
}
/// <summary>
/// 超文本格式的邮件正文
/// </summary>
public string htmlbody {
get { return m_strhtmlbody; }
set { if (value != m_strhtmlbody) m_strhtmlbody = value; }
}
/// <summary>
/// 是否是html格式的邮件
/// </summary>
public bool ishtml
{
get { return m_bishtml; }
set { if (value != m_bishtml) m_bishtml = value; }
}
/// <summary>
/// 语言编码 [默认为gb2312]
/// </summary>
public string languageencoding
{
get { return m_strlanguageencoding; }
set { if (value != m_strlanguageencoding) m_strlanguageencoding = value; }
}
/// <summary>
/// 邮件编码 [默认为8bit]
/// </summary>
public string mailencoding
{
get { return m_strencoding; }
set { if (value != m_strencoding) m_strencoding = value; }
}
/// <summary>
/// 邮件优先级 [默认为3]
/// </summary>
public int priority
{
get { return m_ipriority; }
set { if (value != m_ipriority) m_ipriority = value; }
}
/// <summary>
/// 附件 [attachmentinfo]
/// </summary>
public ilist attachments
{
get { return m_alattachments; }
// set { if (value != m_alattachments) m_alattachments = value; }
}
#endregion
#region "struct attachmentinfo"
/// <summary>
/// 附件信息
/// </summary>
public struct attachmentinfo
{
/// <summary>
/// 附件的文件名 [如果输入路径,则自动转换为文件名]
/// </summary>
public string filename
{
get { return filename; }
set { filename = path.getfilename(value); }
} private string filename;
/// <summary>
/// 附件的内容 [由经base64编码的字节组成]
/// </summary>
public string bytes
{
get { return bytes; }
set { if (value != bytes) bytes = value; }
} private string bytes;
/// <summary>
/// 从流中读取附件内容并构造
/// </summary>
/// <param name="p_strfilename">附件的文件名</param>
/// <param name="p_stream">流</param>
public attachmentinfo (string p_strfilename, stream p_stream)
{
filename = path.getfilename (p_strfilename);
byte[] by = new byte [p_stream.length];
p_stream.read (by,0,(int)p_stream.length); // 读取文件内容
//格式转换
bytes = convert.tobase64string (by); // 转化为base64编码
}
/// <summary>
/// 按照给定的字节构造附件
/// </summary>
/// <param name="p_strfilename">附件的文件名</param>
/// <param name="ibytes">附件的内容 [字节]</param>
public attachmentinfo (string p_strfilename, byte[] ibytes)
{
filename = path.getfilename (p_strfilename);
bytes = convert.tobase64string (ibytes); // 转化为base64编码
}
/// <summary>
/// 从文件载入并构造
/// </summary>
/// <param name="p_strpath"></param>
public attachmentinfo (string p_strpath)
{
filename = path.getfilename (p_strpath);
filestream file = new filestream (p_strpath, filemode.open);
byte[] by = new byte [file.length];
file.read (by,0,(int)file.length); // 读取文件内容
//格式转换
bytes = convert.tobase64string (by); // 转化为base64编码
file.close ();
}
}
#endregion
#region "functions"
/// <summary>
/// 发送邮件
/// </summary>
private void sendmail()
{
// 创建tcpclient对象, 并建立连接
tcpclient tcpnewclient = null;
try
{
tcpnewclient = new tcpclient (m_strserver, m_iport);
}
catch (exception)
{
throw new exception ("无法连接服务器");
}
readstring (tcpnewclient.getstream());//获取连接信息
// 开始进行服务器认证
// 如果状态码是250则表示操作成功
if (!command (tcpnewclient.getstream(), "ehlo localhost", "250"))
{
tcpnewclient.close();
throw new exception ("登陆阶段失败");
}
if (m_strusername != "")
{
// 需要身份验证
if (!command (tcpnewclient.getstream(), "auth login", "334"))
{
tcpnewclient.close();
throw new exception ("身份验证阶段失败");
}
// 此处将username转换为base64码
string nameb64 = tobase64 (m_strusername);
if (!command (tcpnewclient.getstream(), nameb64, "334"))
{
tcpnewclient.close();
throw new exception ("身份验证阶段失败");
}
// 此处将m_strpassword转换为base64码
string passb64 = tobase64 (m_strpassword);
if (!command (tcpnewclient.getstream(), passb64, "235"))
{
tcpnewclient.close();
throw new exception ("身份验证阶段失败");
}
}
// 准备发送
writestring (tcpnewclient.getstream(), "mail from: " + m_strfrom);
for(int i=0;i<m_strto.length;i++)
{
writestring (tcpnewclient.getstream(), "rcpt m_strto: " + m_strto[i]);
}
writestring (tcpnewclient.getstream(), "data");
// 发送邮件头
writestring (tcpnewclient.getstream(), "date: " + datetime.now); // 时间
writestring (tcpnewclient.getstream(), "from: " + m_strfromname + "<" + m_strfrom + ">"); // 发件人
writestring (tcpnewclient.getstream(), "subject: " + m_strsubject); // 主题
writestring (tcpnewclient.getstream(), "to:" + m_strtoname + "<" + m_strto + ">"); // 收件人
//邮件格式
writestring (tcpnewclient.getstream(), "content-type: multipart/mixed; boundary=/"unique-boundary-1/"");
writestring (tcpnewclient.getstream(), "reply-to:" + m_strfrom); // 回复地址
writestring (tcpnewclient.getstream(), "x-priority:" + m_ipriority); // 优先级
writestring (tcpnewclient.getstream(), "mime-version:1.0"); // mime版本
// 数据id,随意
// writestring (tcpnewclient.getstream(), "message-id: " + datetime.now.tofiletime() + "@security.com");
writestring (tcpnewclient.getstream(), "content-transfer-encoding:" + m_strencoding); // 内容编码
writestring (tcpnewclient.getstream(), "x-mailer:jcpersonal.utility.mailsender"); // 邮件发送者
writestring (tcpnewclient.getstream(), "");
writestring (tcpnewclient.getstream(), tobase64 ("this is a multi-part message in mime format."));
writestring (tcpnewclient.getstream(), "");
// 从此处开始进行分隔输入
writestring (tcpnewclient.getstream(), "--unique-boundary-1");
// 在此处定义第二个分隔符
writestring (tcpnewclient.getstream(), "content-type: multipart/alternative;boundary=/"unique-boundary-2/"");
writestring (tcpnewclient.getstream(), "");
if(!m_bishtml)
{
// 文本信息
writestring (tcpnewclient.getstream(), "--unique-boundary-2");
writestring (tcpnewclient.getstream(), "content-type: text/plain;charset=" + m_strlanguageencoding);
writestring (tcpnewclient.getstream(), "content-transfer-encoding:" + m_strencoding);
writestring (tcpnewclient.getstream(), "");
writestring (tcpnewclient.getstream(), m_strtxtbody);
writestring (tcpnewclient.getstream(), "");//一个部分写完之后就写如空信息,分段
writestring (tcpnewclient.getstream(), "--unique-boundary-2--");//分隔符的结束符号,尾巴后面多了--
writestring (tcpnewclient.getstream(), "");
}
else
{
//html信息
writestring (tcpnewclient.getstream(), "content-type: multipart/mixed");
writestring (tcpnewclient.getstream(), "--unique-boundary-2");
writestring (tcpnewclient.getstream(), "content-type: text/html;charset=" + m_strlanguageencoding);
writestring (tcpnewclient.getstream(), "content-transfer-encoding:" + m_strencoding);
writestring (tcpnewclient.getstream(), "");
writestring (tcpnewclient.getstream(), m_strhtmlbody);
writestring (tcpnewclient.getstream(), "");
writestring (tcpnewclient.getstream(), "--unique-boundary-2--");//分隔符的结束符号,尾巴后面多了--
writestring (tcpnewclient.getstream(), "");
}
// 发送附件
// 对文件列表做循环
for (int i = 0; i < m_alattachments.count; i++)
{
writestring (tcpnewclient.getstream(), "--unique-boundary-1"); // 邮件内容分隔符
writestring (tcpnewclient.getstream(), "content-type: application/octet-stream;name=/"" + ((attachmentinfo)m_alattachments[i]).filename + "/""); // 文件格式
writestring (tcpnewclient.getstream(), "content-transfer-encoding: base64"); // 内容的编码
writestring (tcpnewclient.getstream(), "content-disposition:attachment;filename=/"" + ((attachmentinfo)m_alattachments[i]).filename + "/""); // 文件名
writestring (tcpnewclient.getstream(), "");
writestring (tcpnewclient.getstream(), ((attachmentinfo)m_alattachments[i]).bytes); // 写入文件的内容
writestring (tcpnewclient.getstream(), "");
}
command (tcpnewclient.getstream(), ".", "250"); // 最后写完了,输入"."
// 关闭连接
tcpnewclient.close ();
}
/// <summary>
/// 向流中写入字符
/// </summary>
/// <param name="p_netstream">来自tcpclient的流</param>
/// <param name="p_str">写入的字符</param>
protected void writestring (networkstream p_netstream, string p_str)
{
p_str = p_str + "/r/n"; // 加入换行符
// 将命令行转化为byte[]
byte[] bwrite = encoding.getencoding(m_strlanguageencoding).getbytes(p_str.tochararray());
// 由于每次写入的数据大小是有限制的,那么我们将每次写入的数据长度定在75个字节,一旦命令长度超过了75,就分步写入。
int istart=0;
int ilength = bwrite.length;
int ipage = 0;
int isize = 75;
int icount = isize;
try
{
if (ilength>75)
{
// 数据分页
if ((ilength / isize) * isize < ilength)
ipage = ilength/isize+1;
else
ipage=ilength/isize;
for (int i=0;i<ipage;i++)
{
istart=i*isize;
if (i==ipage-1)
icount=ilength-(i*isize);
p_netstream.write(bwrite,istart,icount);// 将数据写入到服务器上
}
}
else
p_netstream.write(bwrite,0,bwrite.length);
}
catch(exception)
{
// 忽略错误
}
}
/// <summary>
/// 从流中读取字符
/// </summary>
/// <param name="p_netstream">来自tcpclient的流</param>
/// <returns>读取的字符</returns>
protected string readstring (networkstream p_netstream)
{
string strsp = null;
byte[] by = new byte[1024];
int isize = p_netstream.read(by,0,by.length);// 读取数据流
if (isize > 0)
{
strsp = encoding.default.getstring(by);// 转化为string
}
return strsp;
}
/// <summary>
/// 发出命令并判断返回信息是否正确
/// </summary>
/// <param name="p_netstream">来自tcpclient的流</param>
/// <param name="p_strcommand">命令</param>
/// <param name="p_strstate">正确的状态码</param>
/// <returns>是否正确</returns>
protected bool command (networkstream p_netstream, string p_strcommand, string p_strstate)
{
string strsp = null;
bool bsuccess = false;
try
{
// 写入命令
writestring (p_netstream, p_strcommand);
strsp = readstring (p_netstream);// 接受返回信息
if (strsp.indexof(p_strstate) != -1)// 判断状态码是否正确
bsuccess=true;
}
catch(exception)
{
// 忽略错误
}
return bsuccess;
}
/// <summary>
/// 字符串编码为base64
/// </summary>
/// <param name="p_str">字符串</param>
/// <returns>base64编码的字符串</returns>
protected string tobase64 (string p_str)
{
try
{
byte[] by = encoding.default.getbytes (p_str.tochararray());
p_str = convert.tobase64string (by);
}
catch(exception)
{
// 忽略错误
}
return p_str;
}
/// <summary>
/// 表示一封待发送的邮件
/// </summary>
public mailsender()
{
//
// todo: 在此处添加构造函数逻辑
//
}
#endregion
#region "tools"
/// <summary>
/// 回复格式化html的格式到htmlt格式
/// </summary>
/// <param name="p_stroldstr">要格式化的字符串</param>
/// <param name="p_strseparator_n"></param>
/// <param name="p_strseparator_r"></param>
/// <returns></returns>
public string reformatspecailhtml_tohtml(string p_stroldstr,string p_strseparator_n,string p_strseparator_r)
{
//string result;
while(p_stroldstr.indexof("<")>-1 || p_stroldstr.indexof(">")>-1 || p_stroldstr.indexof("@$@_n")>-1 || p_stroldstr.indexof("@$@_r")>-1)
{
if(p_stroldstr.indexof("<")>-1)
{
p_stroldstr = p_stroldstr.substring(0,p_stroldstr.indexof("<")) + "<" + p_stroldstr.substring(p_stroldstr.indexof("<")+4);
}
else if(p_stroldstr.indexof(">")>-1)
{
p_stroldstr = p_stroldstr.substring(0,p_stroldstr.indexof(">")) + ">" + p_stroldstr.substring(p_stroldstr.indexof(">")+4);
}
else if(p_stroldstr.indexof(p_strseparator_n)>-1)
{
p_stroldstr = p_stroldstr.substring(0,p_stroldstr.indexof(p_strseparator_n)) + "<br>" + p_stroldstr.substring(p_stroldstr.indexof(p_strseparator_n) + p_strseparator_n.length);
}
else if(p_stroldstr.indexof(p_strseparator_r)>-1)
{
p_stroldstr = p_stroldstr.substring(0,p_stroldstr.indexof(p_strseparator_r)) + "<br>" + p_stroldstr.substring(p_stroldstr.indexof(p_strseparator_r) + p_strseparator_r.length);
}
else
{
p_stroldstr = p_stroldstr;
}
}
return p_stroldstr;
}
/// <summary>
/// 格式化html的格式(目前不用)
/// </summary>
/// <param name="p_stroldstr">要格式化的字符串</param>
/// <returns></returns>
private string formatspecailhtml(string p_stroldstr)
{
string result;
if(p_stroldstr.indexof("<")>-1)
{
result = p_stroldstr.substring(0,p_stroldstr.indexof("<")) + "<" + p_stroldstr.substring(p_stroldstr.indexof("<")+1);
formatspecailhtml(result);
}
else if(p_stroldstr.indexof(">")>-1)
{
result = p_stroldstr.substring(0,p_stroldstr.indexof(">")) + ">" + p_stroldstr.substring(p_stroldstr.indexof(">")+1);
formatspecailhtml(result);
}
else
{
result = p_stroldstr;
}
return result;
}
/// <summary>
/// 回复格式化html的格式到txt格式
/// </summary>
/// <param name="p_stroldstr">要格式化的字符串</param>
/// <param name="p_strseparator_n"></param>
/// <param name="p_strseparator_r"></param>
/// <returns></returns>
public string reformatspecailhtml_totxt(string p_stroldstr,string p_strseparator_n,string p_strseparator_r)
{
//string result;
while(p_stroldstr.indexof("<")>-1 || p_stroldstr.indexof(">")>-1 || p_stroldstr.indexof(p_strseparator_n)>-1 || p_stroldstr.indexof(p_strseparator_r)>-1)
{
if(p_stroldstr.indexof("<")>-1)
{
p_stroldstr = p_stroldstr.substring(0,p_stroldstr.indexof("<")) + "<" + p_stroldstr.substring(p_stroldstr.indexof("<")+4);
}
else if(p_stroldstr.indexof(">")>-1)
{
p_stroldstr = p_stroldstr.substring(0,p_stroldstr.indexof(">")) + ">" + p_stroldstr.substring(p_stroldstr.indexof(">")+4);
}
else if(p_stroldstr.indexof(p_strseparator_n)>-1)
{
p_stroldstr = p_stroldstr.substring(0,p_stroldstr.indexof(p_strseparator_n)) + "/n" + p_stroldstr.substring(p_stroldstr.indexof(p_strseparator_n) + p_strseparator_n.length);
}
else if(p_stroldstr.indexof(p_strseparator_r)>-1)
{
p_stroldstr = p_stroldstr.substring(0,p_stroldstr.indexof(p_strseparator_r)) + "/r" + p_stroldstr.substring(p_stroldstr.indexof(p_strseparator_r) + p_strseparator_r.length);
}
else
{
p_stroldstr = p_stroldstr;
}
}
return p_stroldstr;
}
#endregion
#region "use"
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="p_strmailfrom">发件人地址</param>
/// <param name="p_strmailto">收件人地址</param>
/// <param name="p_strmailformat">邮件主体格式</param>
/// <param name="p_strmailsubject">邮件主题</param>
/// <param name="p_strmailbody">邮件主体</param>
/// <param name="p_strmailattachmentpaths">附件路径</param>
/// <param name="mailsmtp">smtp服务地址</param>
/// <param name="smtpuser"></param>
/// <param name="p_strsmtppassword"></param>
/// <param name="p_strseparator_n"></param>
/// <param name="p_strseparator_r"></param>
public void send(string p_strmailfrom,string[] p_strmailto,string p_strmailformat,string p_strmailsubject,string p_strmailbody,string[] p_strmailattachmentpaths,string mailsmtp,string smtpuser,string p_strsmtppassword,string p_strseparator_n,string p_strseparator_r)
{
//mailsender myemail = null;
try
{
//myemail = new mailsender();
this.from = p_strmailfrom;
this.to = p_strmailto;
this.subject = p_strmailsubject;
this.body = reformatspecailhtml_totxt(p_strmailbody,p_strseparator_n,p_strseparator_r);
this.htmlbody = reformatspecailhtml_tohtml(p_strmailbody,p_strseparator_n,p_strseparator_r);
if(p_strmailformat.toupper() == "html")
{
this.ishtml = true;
}
else
{
this.ishtml = false;
}
for(int i=0;i<p_strmailattachmentpaths.length;i++)
{
if(p_strmailattachmentpaths[i] != null && p_strmailattachmentpaths[i].length > 0)
{
object tempobj = new mailsender.attachmentinfo(p_strmailattachmentpaths[i]);
this.attachments.add(tempobj);
}
}
this.server = mailsmtp;
this.username = smtpuser;
this.password = p_strsmtppassword;
//this.sendmail();
sendmail();
}
catch(exception ex)
{
throw new exception("使用mailsender失败",ex);
}
}
/// <summary>
/// 发送邮件(使用默认分隔符号)
/// </summary>
/// <param name="p_strmailfrom">发件人地址</param>
/// <param name="p_strmailto">收件人地址</param>
/// <param name="p_strmailformat">邮件主体格式</param>
/// <param name="p_strmailsubject">邮件主题</param>
/// <param name="p_strmailbody">邮件主体</param>
/// <param name="p_strmailattachmentpaths">附件路径</param>
/// <param name="mailsmtp">smtp服务地址</param>
/// <param name="smtpuser"></param>
/// <param name="p_strsmtppassword"></param>
/// writer:nick
/// create date:2004-12-20
public void send(string p_strmailfrom,string[] p_strmailto,string p_strmailformat,string p_strmailsubject,string p_strmailbody,string[] p_strmailattachmentpaths,string mailsmtp,string smtpuser,string p_strsmtppassword)
{
string strseparator_n = "@$@_n";
string strseparator_r = "@$@_r";
send(p_strmailfrom,p_strmailto,p_strmailformat, p_strmailsubject, p_strmailbody, p_strmailattachmentpaths, mailsmtp, smtpuser, p_strsmtppassword,strseparator_n,strseparator_r);
}
/// <summary>
/// 发送邮件(无附件)
/// </summary>
/// <param name="p_strmailfrom">发件人地址</param>
/// <param name="p_strmailto">收件人地址</param>
/// <param name="p_strmailformat">邮件主体格式</param>
/// <param name="p_strmailsubject">邮件主题</param>
/// <param name="p_strmailbody">邮件主体</param>
/// <param name="mailsmtp">smtp服务地址</param>
/// <param name="smtpuser"></param>
/// <param name="p_strsmtppassword"></param>
/// writer:nick
/// create date:2004-12-20
public void send(string p_strmailfrom,string[] p_strmailto,string p_strmailformat,string p_strmailsubject,string p_strmailbody,string mailsmtp,string smtpuser,string p_strsmtppassword)
{
string[] strmailattachmentpaths = new string[3];
send(p_strmailfrom,p_strmailto,p_strmailformat,p_strmailsubject,p_strmailbody,strmailattachmentpaths, mailsmtp, smtpuser, p_strsmtppassword);
}
/// <summary>
/// 发送邮件(无附件、txt格式)
/// </summary>
/// <param name="p_strmailfrom">发件人地址</param>
/// <param name="p_strmailto">收件人地址</param>
/// <param name="p_strmailsubject">邮件主题</param>
/// <param name="p_strmailbody">邮件主体</param>
/// <param name="mailsmtp">smtp服务地址</param>
/// <param name="smtpuser"></param>
/// <param name="p_strsmtppassword"></param>
/// writer:nick
/// create date:2004-12-20
public void send(string p_strmailfrom,string[] p_strmailto,string p_strmailsubject,string p_strmailbody,string mailsmtp,string smtpuser,string p_strsmtppassword)
{
string strmailformat = "txt";
send(p_strmailfrom,p_strmailto,strmailformat,p_strmailsubject,p_strmailbody,mailsmtp,smtpuser,p_strsmtppassword);
}
/// <summary>
/// 发送邮件
/// </summary>
/// writer:nick
/// create date:2004-12-20
public void send()
{
sendmail();
}
/// <summary>
/// 销毁(预留)
/// </summary>
/// writer:nick
/// create date:2004-12-20
public void dispose()
{
}
#endregion
}
}