using System;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections;namespace webQQ
{
public class ESmtpMail
{
/// <summary>
/// 设定语言代码,默认设定为GB2312,如不需要可设置为""
/// </summary>
public string Charset = "GB2312"; /// <summary>
/// 发件人地址
/// </summary>
public string From = ""; /// <summary>
/// 发件人姓名
/// </summary>
public string FromName = ""; /// <summary>
/// 回复邮件地址
/// </summary>
public string ReplyTo = ""; /// <summary>
/// 邮件服务器域名
/// </summary>
private string mailserver = ""; /// <summary>
/// 邮件服务器域名和验证信息
/// 形如:"user:[email protected]:25",也可省略次要信息。如"user:[email protected]"或"www.server.com"
/// </summary>
public string MailDomain
{
set
{
string maidomain = value.Trim();
int tempint; if(maidomain != "")
{
tempint = maidomain.IndexOf("@");
if(tempint != -1)
{
string up = maidomain.Substring(0,tempint);
MailServerUserName = up.Substring(0,up.IndexOf(":"));
int upindex = up.IndexOf(":");
MailServerPassWord = up.Substring(upindex + 1,up.Length - upindex - 1);
maidomain = maidomain.Substring(tempint + 1, maidomain.Length - tempint - 1);
} tempint=maidomain.IndexOf(":");
if(tempint != -1)
{
mailserver = maidomain.Substring(0,tempint);
mailserverport = System.Convert.ToInt32(maidomain.Substring(tempint + 1, maidomain.Length - tempint - 1));
}
else
{
mailserver = maidomain; }
}
}
} /// <summary>
/// 邮件服务器端口号
/// </summary>
private int mailserverport=25; /// <summary>
/// 邮件服务器端口号
/// </summary>
public int MailDomainPort
{
set
{
mailserverport = value;
}
} /// <summary>
/// 是否需要SMTP验证
/// </summary>
private bool ESmtp = false; /// <summary>
/// SMTP认证时使用的用户名
/// </summary>
private string username = ""; /// <summary>
/// SMTP认证时使用的用户名
/// </summary>
public string MailServerUserName
{
set
{
if(value.Trim() != "")
{
username = value.Trim();
ESmtp = true;
}
else
{
username = "";
ESmtp = false;
}
}
} /// <summary>
/// SMTP认证时使用的密码
/// </summary>
private string password = ""; /// <summary>
/// SMTP认证时使用的密码
/// </summary>
public string MailServerPassWord
{
set
{
password = value;
}
} /// <summary>
/// 邮件主题
/// </summary>
public string Subject = "";
        
/// <summary>
/// 是否Html邮件
/// </summary>
public bool Html = false; /// <summary>
/// 邮件正文
/// </summary>
public string Body = ""; /// <summary>
/// 收件人列表
/// </summary>
private Hashtable Recipient = new Hashtable(); /// <summary>
/// 密送收件人列表
/// </summary>
private Hashtable RecipientBCC = new Hashtable(); /// <summary>
/// 邮件发送优先级,可设置为"1","3","5"
/// </summary>
private string priority = "3"; /// <summary>
/// 邮件发送优先级,可设置为"High","Normal","Low"或"1","3","5"
/// </summary>
public string Priority
{
set
{
switch(value.ToLower())
{
case "high":
priority = "1";
break;
case "1":
priority = "1";
break;
case "normal":
priority = "3";
break;
case "3":
priority = "3";
break;
case "low":
priority = "5";
break;
case "5":
priority = "5";
break;
default:
priority = "3";
break;
}
}
} /// <summary>
/// 错误消息反馈
/// </summary>
private string errmsg; /// <summary>
/// 错误消息反馈
/// </summary>
public string ErrorMessage
{
get
{
return errmsg;
}
} /// <summary>
/// 服务器交互记录
/// </summary>
private string logs = ""; /// <summary>
/// 服务器交互记录。
/// </summary>
public string Logs
{
get
{
return logs;
}
} private string enter = "\r\n";
/// <summary>
/// TcpClient对象,用于连接服务器
/// </summary>
private TcpClient tc; /// <summary>
/// NetworkStream对象
/// </summary>
private NetworkStream ns; /// <summary>
/// SMTP错误代码哈希表
/// </summary>
private Hashtable ErrCodeHT = new Hashtable(); /// <summary>
/// SMTP正确代码哈希表
/// </summary>
private Hashtable RightCodeHT = new Hashtable(); /// <summary>
/// SMTP回应代码哈希表
/// </summary>
private void SMTPCodeAdd()
{
ErrCodeHT.Add("500","邮箱地址错误");
ErrCodeHT.Add("501","参数格式错误");
ErrCodeHT.Add("502","命令不可实现");
ErrCodeHT.Add("503","服务器需要SMTP验证");
ErrCodeHT.Add("504","命令参数不可实现");
ErrCodeHT.Add("421","服务未就绪,关闭传输信道");
ErrCodeHT.Add("450","要求的邮件操作未完成,邮箱不可用(例如,邮箱忙)");
ErrCodeHT.Add("550","要求的邮件操作未完成,邮箱不可用(例如,邮箱未找到,或不可访问)");
ErrCodeHT.Add("451","放弃要求的操作;处理过程中出错");
ErrCodeHT.Add("551","用户非本地,请尝试<forward-path>");
ErrCodeHT.Add("452","系统存储不足,要求的操作未执行");
ErrCodeHT.Add("552","过量的存储分配,要求的操作未执行");
ErrCodeHT.Add("553","邮箱名不可用,要求的操作未执行(例如邮箱格式错误)");
ErrCodeHT.Add("432","需要一个密码转换");
ErrCodeHT.Add("534","认证机制过于简单");
ErrCodeHT.Add("538","当前请求的认证机制需要加密");
ErrCodeHT.Add("454","临时认证失败");
ErrCodeHT.Add("530","需要认证"); RightCodeHT.Add("220","服务就绪");
RightCodeHT.Add("250","要求的邮件操作完成");
RightCodeHT.Add("251","用户非本地,将转发向<forward-path>");
RightCodeHT.Add("354","开始邮件输入,以<CRLF>.<CRLF>结束");
RightCodeHT.Add("221","服务关闭传输信道");
RightCodeHT.Add("334","服务器响应验证Base64字符串");
RightCodeHT.Add("235","验证成功");
} /// <summary>
/// 将字符串编码为Base64字符串
/// </summary>
/// <param name="estr">要编码的字符串</param>
private string Base64Encode(string estr)
{
byte[] barray;
barray = Encoding.Default.GetBytes(estr);
return Convert.ToBase64String(barray);
}

解决方案 »

  1.   

    /// <summary>
    /// 将Base64字符串解码为普通字符串
    /// </summary>
    /// <param name="dstr">要解码的字符串</param>
    private string Base64Decode(string dstr)
    {
    byte[] barray;
    barray = Convert.FromBase64String(dstr);
    return Encoding.Default.GetString(barray);
    } public ESmtpMail()
    {
    } ~ESmtpMail()
    {
    ns.Close();
    tc.Close();
    } /// <summary>
    /// 收件人姓名
    /// </summary>
    public string RecipientName = "";
    private int RecipientNum = 0;//收件人数量
    private int RecipientBCCNum = 0;//密件收件人数量 /// <summary>
    /// 添加一个收件人
    /// </summary>
    /// <param name="str">收件人地址</param>
    public bool AddRecipient(string str)
    {
    str=str.Trim();
    if (str == null || str == "" || str.IndexOf("@") == -1)
    return true;
    if(RecipientNum < 10)
    {
    Recipient.Add(RecipientNum,str);
    RecipientNum ++;
    return true;
    }
    else
    {
    errmsg += "收件人过多";
    return false;
    }
    } /// <summary>
    /// 添加一组收件人(不超过10个),参数为字符串数组
    /// </summary>
    /// <param name="str">保存有收件人地址的字符串数组(不超过10个)</param>
    public bool AddRecipient(string[] str)
    {
    for(int i = 0; i < str.Length; i ++)
    {
    if (!AddRecipient(str[i]))
    {
    return false;
    }
    }
    return true;
    } /// <summary>
    /// 添加一个密件收件人
    /// </summary>
    /// <param name="str">收件人地址</param>
    public bool AddRecipientBCC(string str)
    {
    if (str == null || str.Trim() == "")
    return true;
    if(RecipientBCCNum < 10)
    {
    RecipientBCC.Add(RecipientBCCNum,str);
    RecipientBCCNum ++;
    return true;
    }
    else
    {
    errmsg += "收件人过多";
    return false;
    }
    } /// <summary>
    /// 添加一组密件收件人(不超过10个),参数为字符串数组
    /// </summary>
    /// <param name="str">保存有收件人地址的字符串数组(不超过10个)</param>
    public bool AddRecipientBCC(string[] str)
    {
    for(int i = 0; i < str.Length; i ++)
    {
    if (!AddRecipientBCC(str[i]))
    {
    return false;
    }
    }
    return true;
    } /// <summary>
    /// 发送SMTP命令
    /// </summary>
    private bool SendCommand(string Command)
    {
    byte[]  WriteBuffer;
    if(Command == null || Command.Trim() == "")
    {
    return true;
    }
    logs += Command;
    WriteBuffer = Encoding.Default.GetBytes(Command);
    try
    {
    ns.Write(WriteBuffer,0,WriteBuffer.Length);
    }
    catch
    {
    errmsg = "网络连接错误";
    return false;
    }
    return true;
    } /// <summary>
    /// 接收SMTP服务器回应
    /// </summary>
    private string RecvResponse()
    {
    int StreamSize;
    string ReturnValue = "";
    byte[]  ReadBuffer = new byte[1024] ;
    try
    {
    StreamSize = ns.Read(ReadBuffer,0,ReadBuffer.Length);
    }
    catch
    {
    errmsg = "网络连接错误";
    return "false";
    } if (StreamSize == 0)
    {
    return ReturnValue ;
    }
    else
    {
    ReturnValue = Encoding.Default.GetString(ReadBuffer).Substring(0,StreamSize);
    logs += ReturnValue;
    return ReturnValue;
    }
    } /// <summary>
    /// 与服务器交互,发送一条命令并接收回应。
    /// </summary>
    /// <param name="Command">一个要发送的命令</param>
    /// <param name="errstr">如果错误,要反馈的信息</param>
    private bool Dialog(string Command,string errstr)
    {
    if (Command == null || Command.Trim() == "")
    {
    return true;
    }
    if (SendCommand(Command))
    {
    string RR = RecvResponse();
    if (RR == "false")
    {
    return false;
    }
    string RRCode = RR.Substring(0,3);
    if (RightCodeHT[RRCode] != null)
    {
    return true;
    }
    else
    {
    if(ErrCodeHT[RRCode] != null)
    {
    errmsg += (RRCode+ErrCodeHT[RRCode].ToString());
    errmsg += enter;
    }
    else
    {
    errmsg += RR;
    }
    errmsg += errstr;
    return false;
    }
    }
    else
    {
    return false;
    }
    }
    /// <summary>
    /// 与服务器交互,发送一组命令并接收回应。
    /// </summary> private bool Dialog(string[] Command,string errstr)
    {
    for(int i = 0; i < Command.Length; i ++)
    {
    if (!Dialog(Command[i],""))
    {
    errmsg += enter;
    errmsg += errstr;
    return false;
    }
    }
    return true;
    } private bool SendEmail()
    {
    //连接网络
    try
    {
    tc = new TcpClient(mailserver,mailserverport);
    }
    catch(Exception e)
    {
    errmsg = e.ToString();
    return false;
    } ns = tc.GetStream();
    SMTPCodeAdd(); //验证网络连接是否正确
    if (RightCodeHT[RecvResponse().Substring(0,3)] == null)
    {
    errmsg = "网络连接失败";
    return false;
    } string[] SendBuffer;
    string SendBufferstr; //进行SMTP验证
    if (ESmtp)
    {
    SendBuffer = new string[4];
    SendBuffer[0] = "EHLO " + mailserver + enter;
    SendBuffer[1] = "AUTH LOGIN" + enter;
    SendBuffer[2] = Base64Encode(username) + enter;
    SendBuffer[3] = Base64Encode(password) + enter;
    if (!Dialog(SendBuffer,"SMTP服务器验证失败,请核对用户名和密码。"))
    return false;
    }
    else
    {
    SendBufferstr = "HELO " + mailserver + enter;
    if (!Dialog(SendBufferstr,""))
    return false;
    } SendBufferstr = "MAIL FROM:<" + From + ">" + enter;
    if(!Dialog(SendBufferstr,"发件人地址错误,或不能为空"))
    return false; SendBuffer = new string[10];
    for (int i = 0; i < Recipient.Count; i ++)
    {
    SendBuffer[i] = "RCPT TO:<" + Recipient[i].ToString() +">" + enter;
    }
    if (!Dialog(SendBuffer,"收件人地址有误"))
    return false; SendBuffer = new string[10];
    for(int i = 0; i < RecipientBCC.Count; i ++)
    {
    SendBuffer[i] = "RCPT TO:<" + RecipientBCC[i].ToString() +">" + enter;
    }
    if (!Dialog(SendBuffer,"密件收件人地址有误"))
    return false; SendBufferstr = "DATA" + enter;
    if (!Dialog(SendBufferstr,""))
    return false; SendBufferstr = "From:" + FromName + "<" + From +">" + enter; if (ReplyTo.Trim() != "")
    {
    SendBufferstr += "Reply-To: " + ReplyTo + enter;
    } SendBufferstr += "To:" + RecipientName + "<" + Recipient[0] +">" + enter;
    SendBufferstr += "CC:";
    for (int i = 1; i < Recipient.Count; i ++)
    {
    SendBufferstr += Recipient[i].ToString() + "<" + Recipient[i].ToString() + ">,";
    }
    SendBufferstr += enter; if (Charset == "")
    {
    SendBufferstr += "Subject:" + Subject + enter;
    }
    else
    {
    SendBufferstr += "Subject:" + "=?" + Charset.ToUpper() + "?B?" + Base64Encode(Subject) + "?=" + enter;
    } SendBufferstr += "X-Priority:" + priority + enter;
    SendBufferstr += "X-MSMail-Priority:" + priority + enter;
    SendBufferstr += "Importance:" + priority + enter;
    SendBufferstr += "X-Mailer: PowBoard" + enter;
    SendBufferstr += "MIME-Version: 1.0" + enter; if (Html)
    {
    SendBufferstr += "Content-Type: text/html;" + enter;
    }
    else
    {
    SendBufferstr += "Content-Type: text/plain;" + enter;
    } if (Charset == "")
    {
    SendBufferstr += " charset=\"iso-8859-1\"" + enter;
    }
    else
    {
    SendBufferstr += " charset=\"" + Charset.ToLower() + "\"" + enter;
    } SendBufferstr += "Content-Transfer-Encoding: base64" + enter; SendBufferstr += enter + enter;
    SendBufferstr += Base64Encode(Body) + enter;
    SendBufferstr += enter + "." + enter; if (!Dialog(SendBufferstr,"错误信件信息"))
    return false; SendBufferstr = "QUIT" + enter;
    if (!Dialog(SendBufferstr,"断开连接时错误"))
    return false; ns.Close();
    tc.Close();
    return true;
    }
    /// <summary>
    /// 发送邮件方法,所有参数均通过属性设置。
    /// </summary>
    public bool Send()
    {
    if (Recipient.Count == 0)
    {
    errmsg = "收件人列表不能为空";
    return false;
    } if(RecipientName == "")
    Recipien
      

  2.   

    public bool Send(string smtpserver)
    {

    MailDomain = smtpserver;
    return Send();
    } /// <summary>
    /// 发送邮件方法
    /// </summary>
    /// <param name="smtpserver">smtp服务器信息,如"username:[email protected]:25",也可去掉部分次要信息,如"www.smtpserver.com"</param>
    /// <param name="from">发件人mail地址</param>
    /// <param name="fromname">发件人姓名</param>
    /// <param name="replyto">回复邮件地址</param>
    /// <param name="to">收件人地址</param>
    /// <param name="toname">收件人姓名</param>
    /// <param name="html">是否HTML邮件</param>
    /// <param name="subject">邮件主题</param>
    /// <param name="body">邮件正文</param>
    public bool Send(string smtpserver,string from,string fromname,string replyto,string to,string toname,bool html,string subject,string body)
    {
    MailDomain = smtpserver;
    From = from;
    FromName = fromname;
    ReplyTo = replyto;
    AddRecipient(to);
    RecipientName = toname;
    Html = html;
    Subject = subject;
    Body = body;
    return Send();
    }
    }
    }
      

  3.   

    邮件发送在web应用中是屡见不鲜的,在asp时代大家多是利用一些第三方提供的组件如JMAIL、ASPMAIL等进行邮件发送。自从微软推出Asp.net后,很多程序员开始转向采用C#作为主要的开发语言。asp.net提供了更加强大的功能,同时也提供给了大家一个SMTP类作为邮件发送之用。但是,随着垃圾邮件的广泛传播,很多邮件服务提供商纷纷增加了SMTP 的认证手续,也就是ESMTP,而微软提供的SMTP类居然不支持认证发送。当然现在网上也出现了一些解决方案,利用其他的一些手段来发出认证信息。但我想,是不是还有更好的呢?为了解决这个问题,笔者两日茶饭不思,日以继夜,终于找到了一个方法:)。下面,我们将利用TCPCLIENT这个类直接与SMTP服务器通讯进行邮件的发送。实际上原理也就是利用套接字(Socket)和服务器进行对话通讯,按照SMTP协议的规范,和服务器建立联系。我们以往用的一些邮件组件都是这么做的。在开始之前,我们要对SMTP协议及其扩展ESMTP有个初步的了解。SMTP和ESMTP的一些主要命令格式有以下一些:HELO <信息发送端的名称> 例如:HELO Localhost这相当于和服务器打个招呼,你好,我是某某EHLO <信息发送端的名称> 例如:EHLO Localhost这是针对ESMTP服务器的接触方式,必须输入这个命令,系统才会开始认证程序AUTH LOGIN 输入这个命令,系统的认证程序将会启动,同时系统会返回一个经过Base64处理过的字符串,意思是“请输入用户名”。接着必须发送用户名给服务器,用户名也必须经过Base64编码转换,服务器在通过用户名的认证之后会要求输入密码,此时输入经过Base64编码转换后的密码。成功后,即可运行下面的命令了。 MAIL FROM:<发件人地址> 例如:MAIL FROM: [email protected]这是告诉服务器发件人的邮件地址RCPT TO:<收件人地址> 例如:RCPT TO: [email protected]这是告诉服务器收件人的邮件地址DATA 输入这个命令后,服务器正式开始接受数据.数据输入完成后,必须输入命令“.”,服务器就会停止数据的接受.QUIT 退出系统上面是一些基本命令的描述,如果大家还有什么不懂的地方,可以参考TCP/IP有关的书籍,也可以到这个网站看看RFC文档:http://210.25.132.18/rfc/index.html现在我们正式开始,看看在C# 中如何来进行工作。第一步:创建一个类,命名为MailSend,这个类继承System.Net.Sockets.TcpClientusing System;using System.Net.Sockets;//用于处理网络连接using System.IO; //用于处理附件的包using System.Text;//用于处理文本编码using System.Data;using System.Net;public class MailSend:TcpClient{ public MailSend(){}}在这里我要讲讲TcpClient这个类,它的主要作用就是为TCP网络服务提供客户端的连接,大家可以看到,他来源于Sockets这个包,实际上是基于 Socket 类构建。不过他以更高的抽象程度提供 TCP 服务,操作起来也更简单。第二步:建立一些基本的变量及连接方法1、基本变量private String server;//SMTP服务器域名private int port;//端口private String username;//用户名private String password;//密码private String subject;//主题private String body;//文本内容private String htmlbody;//超文本内容private String from;//发件人地址private String to;//收件人地址private String fromname;//发件人姓名private String toname;//收件人姓名private String content_type;//邮件类型private String encode;//邮件编码private String charset;//语言编码private DataTable filelist;//附件列表 private int priority;//邮件优先级以上定义的都是邮件发送所需的一些基本信息,可以将上述变量做为属性来传递。如:public String SMTPServer{set{this.server=value;}}其余的也可如此.2、向服务器写入命令的方法变量strCmd为需要输入的命令或数据的字符串变量charset为数据的字符语言编码,一般可以设置为GB2312private void WriteStream(String strCmd,String charset){Stream TcpStream;//定义操作对象strCmd = strCmd + "\r\n"; //加入换行符TcpStream =this.GetStream();//获取数据流//将命令行转化为byte[]byte[] bWrite = Encoding.GetEncoding(charset).GetBytes(strCmd.ToCharArray());//由于每次写入的数据大小是有限制的,那么我们将每次写入的数据长度定在75个字节,一旦命令长度超过了75,就分步写入。int start=0;int length=bWrite.Length;int page=0;int size=75;int count=size;if (length>75){//数据分页if ((length/size)*size<length)page=length/size+1;elsepage=length/size;for (int i=0;i<page;i++)//根据页数循环写入{start=i*size;if (i==page-1)count=length-(i*size);TcpStream.Write(bWrite,start,count);//将数据写入到服务器上}}elseTcpStream.Write(bWrite,0,bWrite.Length);}catch(Exception){}}本方法中,我们最后用到的也就最重要的就是TcpStream.Write()这句话,前面所做的只是将数据分页,可以分步写入。另外在写入数据时,必须把字符串转化为byte[]类型。在这里我用的是Stream这个对象,同时你也可以使用NetworkStream这个对象来进行操作,实际效果是一致的。在下面的返回信息获取中,我就用到了NetworkStream,实际上这也是帮助大家熟悉流操作对象的一个过程。3、获取服务器的返回信息private string ReceiveStream(){String sp=null;byte[] by=new byte[1024];NetworkStream ns = this.GetStream();//此处即可获取服务器的返回数据流int size=ns.Read(by,0,by.Length);//读取数据流if (size>0){sp=Encoding.Default.GetString(by);//转化为String}return sp;}除了输入DATA命令之后,其余的时间向服务器发送命令,服务器都会返回一些信息,并同时有一个状态码返回,告诉你操作是否成功完成了。一旦输入DATA命令,也就是数据开始传递的这段时间中,服务器不会返回任何信息,直到输入“.”结束传递,服务器才会返回信息。4、发出命令并判断返回信息是否正确,也就是看发出的命令服务器是否接受并通过了。本方法实际上将上面的两个方法结合来用,一个写,一个收,然后进行判断,看是否正确。这样我们就能够监控每步操作是否正常进行了。参数strCmd也就是需要输入的命令或者数据参数state为返回的表明操作成功的状态码private bool OperaStream(string strCmd,string state){ string sp=null;bool success=false;try{WriteStream(strCmd);//写入命令sp = ReceiveStream();//接受返回信息if (sp.IndexOf(state)!=-1)//判断状态码是否正确success=true;}catch(Exception ex){Console.Write(ex.ToString());}return success;}我们进行每一步操作时,都是通过状态码来确定是否成功的,那么如果操作成功,就会返回正确的状态码,根据这个原理,我们在这个方法中,同时输入命令和表明操作成功的状态码,通过获取的数据判断返回的是不是正确的状态码,以此来决定是否继续进行下一步操作。在这里我要告诉大家一些基本的状态码表示的含义。211 帮助返回系统状态214 帮助信息220 服务准备就绪221 关闭连接250 请求操作就绪251 用户不在本地,转寄到< P a t h >354 开始邮件输入421 服务不可用450 操作未执行,邮箱忙451 操作中止,本地错误452 操作未执行,存储空间不足500 命令不可识别或语法错501 参数语法错502 命令不支持503 命令顺序错504 命令参数不支持550 操作未执行,邮箱不可用551 非本地用户552 中止,存储空间不足553 操作未执行,邮箱名不正确554 传输失败写完以上的基本方法,我们可以开始和服务器进行连接了。由于现在的服务器有SMTP和ESMTP两种,不同的服务器连接的命令格式不一样,那么我们需要完成一个方法来取得服务器的连接。public bool getMailServer(){ try{ //域名解析System.Net.IPAddress ipaddress=(IPAddress)System.Net.Dns.Resolve(this.server).AddressList.GetValue(0);System.Net.IPEndPoint endpoint=new IPEndPoint(ipaddress,25);Connect(endpoint);//连接Smtp服务器ReceiveStream();//获取连接信息if (this.username!=null){ //开始进行服务器认证//如果状态码是250则表示操作成功if (!OperaStream("EHLO Localhost","250")){this.Close();return false;}if (!OperaStream("AUTH LOGIN","334")){ this.Close();return false;}username=AuthStream(username);//此处将username转换为Base64码if (!OperaStream(this.username,"334")){this.Close();return false;}password=AuthStream(password);//此处将password转换为Base64码if (!OperaStream(this.password,"235")){this.Close();return false;}return true;}else{ //如果服务器不需要认证if (OperaStream("HELO Localhost","250")){return true;}else{ return false;}}}catch(Exception ex){ return false;}}上面这个方法主要是用于和服务器取得联系,其中包含了针对两种不同服务器的连接方法,如果用户名不为空,那么我们首先进行ESMTP的连接,否则我
      

  4.   

    (接上篇)
    private string AuthStream(String strCmd){ try{byte[] by=Encoding.Default.GetBytes(strCmd.ToCharArray());strCmd=Convert.ToBase64String(by);}catch(Exception ex){return ex.ToString();}return strCmd;}上面的方法将数据转化为Base64编码字符串,大家如果觉得太抽象了,可以这样试一试,在CMD模式输入telnet smtp.sohu.com 25 然后回车,就可以连接sohu的SMTP服务器,sohu的SMTP服务器采用ESMTP协议,必须认证,大家可以试着操作一下。第三步:关于邮件的附件传递大家有发送邮件时,有时候会包含一些附件,那么本组件也考虑到了这一点。下面我们将会详细讲述如何对附件进行处理filelist=new DataTable();//已定义变量,初始化操作filelist.Columns.Add(new DataColumn("filename",typeof(string)));//文件名filelist.Columns.Add(new DataColumn("filecontent",typeof(string)));//文件内容public void LoadAttFile(String path){//根据路径读出文件流FileStream fstr=new FileStream(path,FileMode.Open);//建立文件流对象byte[] by=new byte[Convert.ToInt32(fstr.Length)];fstr.Read(by,0,by.Length);//读取文件内容fstr.Close();//关闭//格式转换String fileinfo=Convert.ToBase64String(by);//转化为base64编码//增加到文件表中DataRow dr=filelist.NewRow();dr[0]=Path.GetFileName(path);//获取文件名dr[1]=fileinfo;//文件内容filelist.Rows.Add(dr);//增加}通过这个方法将直接读取出文件的内容信息,然后存储在DataTable对象中,理论上可以读取无数个文件,当然,文件越大,发送时间也就越长。这个方法只是针对本地的附件加入,如果大家有兴趣,可以自己利用HttpRequest做一个网上文件抓取的程序,直接抓取网上的文件,不过一般来说,这种方法很少用得到。好了,闲话不谈,我们已经将文件读入,那么之后如何处理呢?请看下面的一个方法。1:private void Attachment()2:{ //对文件列表做循环3: for (int i=0;i<filelist.Rows.Count;i++)4: {5: DataRow dr=filelist.Rows;6: WriteStream("--unique-boundary-1");//邮件内容分隔符7: WriteStream("Content-Type: application/octet-stream;name=\""+dr[0].ToString()+"\"");//文件格式8: WriteStream("Content-Transfer-Encoding: base64");//内容的编码9: WriteStream("Content-Disposition:attachment;filename=\""+dr[0].ToString()+"\"");//文件名10: WriteStream("");11: String fileinfo=dr[1].ToString();12: WriteStream(fileinfo);//写入文件的内容13: WriteStream("");14: }15:}这个方法中我们就用到了WriteStream()方法,大家可能看的有些迷糊,好象无头无尾的,实际上这一段代码,将会在写完邮件的头部信息和文本内容之后再写入到服务器上,在下面的程序中大家可以看见前面的部分。那么在代码的第七行,表示了文件的类型,我这里用了一个偷懒的方式,采用application/octet-stream来代替所有的文件类型,实际上针对大部分的常用文件都有自己的一个格式,大家可以根据其文件名的扩展名进行判断,这里我给出其他的一些格式。扩展名   格式".gif" --->"image/gif" ".gz" --->"application/x-gzip" ".htm" --->"text/html" ".html" --->"text/html" ".jpg" --->"image/jpeg" ".tar" --->"application/x-tar" ".txt" --->"text/plain" ".zip" --->"application/zip" 我比较偷懒,如果有需要的朋友,可以补上一些判断,获取文件的原本格式。第四步:关于邮件的头信息前面讲了这么多,就像是吃大餐之前的甜点,现在我们要进入最重要的部份--邮件的头信息,实际上,这个东西我们见得非常的多,大家在收发邮件的时候,查看邮件的属性就会看见一大串代码,里面有一些邮件地址,IP地址什么的,这就是邮件的头信息。那么头信息的基本内容现在开讲:FROM:<姓名><邮件地址> 格式:FROM:管理员<[email protected]>TO:<姓名><邮件地址> 格式:TO:水生月<[email protected]>SUBJECT:<标题> 格式:SUBJECT:今天的天气很不错!DATE:<时间> 格式:DATE: Thu, 29 Aug 2002 09:52:47 +0800 (CST)REPLY-TO:<邮件地址> 格式:REPLY-TO:[email protected]:<邮件类型> 格式:Content-Type: multipart/mixed; boundary=unique-boundary-1X-Priority:<邮件优先级> 格式:X-Priority:3MIME-Version:<版本> 格式:MIME-Version:1.0Content-Transfer-Encoding:<内容传输编码> 格式:Content-Transfer-Encoding:Base64X-Mailer:<邮件发送者> 格式:X-Mailer:FoxMail 4.0 beta 1 [cn]如果大家安装了OutLook(一般都装了:)),自己给自己发一封信,收下来后,查看邮件的属性,然后会看到包含上面一些信息的数据,大家可以根据Outlook的头信息为参照。在这里,我重点要讲的是Content-Type这个头信息,实际上我们在邮件发送时常常包含了文本内容,Html超文本内容以及附件内容,那么此时邮件的格式也就是multipart/mixed,但是这么多内容你要是全放在一块,服务器是不会认识的,那么需要在不同的内容之间加入分隔符,一部分内容完了之后再加入一个结束分隔符,有点像Html。在Content-Type的例子中有一句话boundary=unique-boundary-1,这里就告诉系统我的分隔符叫什么名字。那么在一个邮件中,可以有多个分隔符,其余的分隔符实际上是在你给出的第一个分隔符下扩展的。说了这么多,看看程序:WriteStream("Date: "+DateTime.Now);//时间WriteStream("From: "+this.fromname+"<"+this.from+">");//发件人WriteStream("Subject: "+this.subject);//主题WriteStream("To:"+this.to);//收件人//邮件格式WriteStream("Content-Type: multipart/mixed; boundary=\"unique-boundary-1\""); WriteStream("Reply-To:"+this.from);//回复地址WriteStream("X-Priority:"+priority);//优先级WriteStream("MIME-Version:1.0");//MIME版本//数据ID,随意WriteStream("Message-Id: "+DateTime.Now.ToFileTime()+"@security.com"); WriteStream("Content-Transfer-Encoding:"+this.encode);//内容编码WriteStream("X-Mailer:DS Mail Sender V1.0");//邮件发送者WriteStream("");看看这段头信息,里面的变量是事先定义好的,在头信息结束的时候,在写入一段空信息,这样Smtp服务器才会认为你已经写完了。WriteStream(AuthStream("This is a multi-part message in MIME format."));WriteStream("");这里只是一端描述性内容。//从此处开始进行分隔输入WriteStream("--unique-boundary-1");//在此处定义第二个分隔符WriteStream("Content-Type: multipart/alternative;Boundary=\"unique-boundary-2\"");WriteStream("");//文本信息WriteStream("--unique-boundary-2");WriteStream("Content-Type: text/plain;charset="+this.charset);WriteStream("Content-Transfer-Encoding:"+this.encode);WriteStream("");WriteStream(body);WriteStream("");//一个部分写完之后就写如空信息,分段//html信息WriteStream("--unique-boundary-2");WriteStream("Content-Type: text/html;charset="+this.charset);WriteStream("Content-Transfer-Encoding:"+this.encode);WriteStream("");WriteStream(htmlbody);WriteStream("");WriteStream("--unique-boundary-2--");//分隔符的结束符号,尾巴后面多了--WriteStream("");//增加附件Attachment();//这个方法是我们在上面讲过的,实际上他放在这WriteStream("");WriteStream("--unique-boundary-1--")if (!OperaStream(".","250"))//最后写完了,输入“.”{this.Close(); //关闭连接}这就是一封邮件的核心部分,上面的变量都是已定义好的全局变量,由用户传递给对象。整个邮件组件的主要内容到此告一段落。手指都敲酸了,由于本人水平有限,可能有些地方不太让人满意,在此表示歉意。在研究邮件发送之前,在网上四处搜索资料,却没有收获,似乎大家都愿意把经验烂在肚子里,由于我肠胃不够强壮,所以希望能够和大家共同分享这顿美餐。最后我们看看如何应用。在aspx文件或者其他cs文件中引用:MailSend Ms=new MailSend();//构造对象Ms.SMTPServer=”smtp.sohu.com”;//传递参数……Ms.send();//发送邮件在此篇文章中我并没有给出完整的代码,而只是给出了代码片段,但是这已经足够整理出整个程序了。
    希望可以帮到你! ^-^
      

  5.   

    http://www.zdnet.com.cn/developer/code/story/0,2000081534,39070961,00.htm