用c#寫的smtp郵件發送類

來源:互聯網
上載者:User
using System;using System.IO;using System.Text;using System.Net;using System.Net.Sockets;using System.Collections;using System.Collections.Specialized;using KSN.Exceptions;using KSN.Validate;namespace KSN.Web.Mail{ /// <summary> /// 郵件內容 /// </summary> public class MailMessage {  private string sender=null;  private StringCollection receivers=new StringCollection();  private string subject="";  private string xMailer="";  private StringCollection attachments=new StringCollection();  private MailEncodings mailEncoding=MailEncodings.GB2312;  private MailTypes mailType=MailTypes.Html;  private byte[] mailBody=null;  /// <summary>  /// 擷取或設定寄件者  /// </summary>  public string Sender  {   get{return this.sender;}   set{this.sender=value;}  }  /// <summary>  /// 擷取收件者地址集合  /// </summary>  public StringCollection Receivers  {   get{return this.receivers;}  }  /// <summary>  /// 擷取或設定郵件主題  /// </summary>  public string Subject  {   get{return this.subject;}   set{this.subject=value;}  }  /// <summary>  /// 擷取或設定郵件傳送者  /// </summary>  public string XMailer  {   get{return this.xMailer;}   set{this.xMailer=value;}  }  /// <summary>  /// 擷取附件列表  /// </summary>  public StringCollection Attachments  {   get{return this.attachments;}  }  /// <summary>  /// 擷取或設定郵件的編碼方式  /// </summary>  public MailEncodings MailEncoding  {   get{return this.mailEncoding;}   set{this.mailEncoding=value;}  }  /// <summary>  /// 擷取或設定郵件格式  /// </summary>  public MailTypes MailType  {   get{return this.mailType;}   set{this.mailType=value;}  }  /// <summary>  /// 擷取或設定郵件內文  /// </summary>  public byte[] MailBody  {   get{return this.mailBody;}   set{this.mailBody=value;}  } } /// <summary> /// 郵件編碼 /// </summary> public enum MailEncodings {  GB2312,  ASCII,  Unicode,  UTF8 } /// <summary> /// 郵件格式 /// </summary> public enum MailTypes {  Html,  Text } /// <summary> /// smtp伺服器的驗證方式 /// </summary> public enum SmtpValidateTypes {  /// <summary>  /// 不需要驗證  /// </summary>  None,  /// <summary>  /// 通用的auth login驗證  /// </summary>  Login,  /// <summary>  /// 通用的auth plain驗證  /// </summary>  Plain,  /// <summary>  /// CRAM-MD5驗證  /// </summary>  CRAMMD5 } /// <summary> /// 郵件發送類 /// </summary> public class KSN_Smtp {  #region "member fields"  /// <summary>  /// 連線物件  /// </summary>  private TcpClient tc;  /// <summary>  /// 網路流  /// </summary>  private NetworkStream ns;  /// <summary>  /// 錯誤的代碼字典  /// </summary>  private StringDictionary errorCodes=new StringDictionary();  /// <summary>  /// 操作執行成功後的響應代碼字典  /// </summary>  private StringDictionary rightCodes=new StringDictionary();  /// <summary>  /// 執行過程中錯誤的訊息  /// </summary>  private string errorMessage="";  /// <summary>  /// 記錄動作記錄  /// </summary>  private string logs="";  /// <summary>  /// 主機登陸的驗證方式  /// </summary>  private StringCollection validateTypes=new StringCollection();  /// <summary>  /// 換行常數  /// </summary>  private const string CRLF="\r\n";  private string serverName="smtp";  private string logPath=null;  private string userid=null;  private string password=null;  private string mailEncodingName="GB2312";  private bool sendIsComplete=false;  private SmtpValidateTypes smtpValidateType=SmtpValidateTypes.Login;  #endregion  #region "propertys"  /// <summary>  /// 擷取最後一此程式執行中的錯誤訊息  /// </summary>  public string ErrorMessage  {   get{return this.errorMessage;}  }  /// <summary>  /// 擷取或設定日誌輸出路徑  /// </summary>  public string LogPath  {   get   {    return this.logPath;   }   set{this.logPath=value;}  }  /// <summary>  /// 擷取或設定登陸smtp伺服器的帳號  /// </summary>  public string UserID  {   get{return this.userid;}   set{this.userid=value;}  }  /// <summary>  /// 擷取或設定登陸smtp伺服器的密碼  /// </summary>  public string Password  {   get{return this.password;}   set{this.password=value;}  }  /// <summary>  /// 擷取或設定要使用登陸Smtp伺服器的驗證方式  /// </summary>  public SmtpValidateTypes SmtpValidateType  {   get{return this.smtpValidateType;}   set{this.smtpValidateType=value;}  }  #endregion  #region "construct functions"  /// <summary>  /// 建構函式  /// </summary>  /// <param name="server">主機名稱</param>  /// <param name="port">連接埠</param>  public  KSN_Smtp(string server,int port)  {   tc=new TcpClient(server,port);   ns=tc.GetStream();   this.serverName=server;   this.initialFields();  }  /// <summary>  /// 建構函式  /// </summary>  /// <param name="ip">主機ip</param>  /// <param name="port">連接埠</param>  public KSN_Smtp(IPAddress ip,int port)  {   IPEndPoint endPoint=new IPEndPoint(ip,port);   tc=new TcpClient(endPoint);   ns=tc.GetStream();   this.serverName=ip.ToString();   this.initialFields();  }  #endregion  #region "methods"  private void initialFields() //初始化串連  {   logs="================"+DateTime.Now.ToLongDateString()+"    "+DateTime.Now.ToLongTimeString()+"==============="+CRLF;   //*****************************************************************   //錯誤的狀態代碼   //*****************************************************************   errorCodes.Add("421","服務未就緒,關閉傳輸通道");   errorCodes.Add("432","需要一個密碼轉換");   errorCodes.Add("450","要求的郵件操作未完成,郵箱不可用(如:郵箱忙)");   errorCodes.Add("451","放棄要求的操作,要求的操作未執行");   errorCodes.Add("452","系統儲存不足,要求的操作未完成");   errorCodes.Add("454","臨時的認證失敗");   errorCodes.Add("500","郵箱地址錯誤");   errorCodes.Add("501","參數格式錯誤");   errorCodes.Add("502","命令不可實現");   errorCodes.Add("503","命令的次序不正確");   errorCodes.Add("504","命令參數不可實現");   errorCodes.Add("530","需要認證");   errorCodes.Add("534","認證機制過於簡單");   errorCodes.Add("538","當前請求的認證機制需要加密");   errorCodes.Add("550","當前的郵件操作未完成,郵箱不可用(如:郵箱未找到或郵箱不能用)");   errorCodes.Add("551","使用者非本地,請嘗試<forward-path>");   errorCodes.Add("552","過量的儲存分配,制定的操作未完成");   errorCodes.Add("553","郵箱名不可用,如:郵箱地址的格式錯誤");   errorCodes.Add("554","傳送失敗");   errorCodes.Add("535","使用者身分識別驗證失敗");   //****************************************************************   //操作執行成功後的狀態代碼   //****************************************************************   rightCodes.Add("220","服務就緒");   rightCodes.Add("221","服務關閉傳輸通道");   rightCodes.Add("235","驗證成功");   rightCodes.Add("250","要求的郵件操作完成");   rightCodes.Add("251","非本機使用者,將轉寄向<forward-path>");   rightCodes.Add("334","伺服器響應驗證Base64字串");   rightCodes.Add("354","開始郵件輸入,以<CRLF>.<CRLF>結束");   //讀取系統回應   StreamReader reader=new StreamReader(ns);   logs+=reader.ReadLine()+CRLF;  }  /// <summary>  /// 向SMTP發送命令  /// </summary>  /// <param name="cmd"></param>  private string sendCommand(string cmd,bool isMailData)  {   if(cmd!=null && cmd.Trim()!=string.Empty)   {    byte[] cmd_b=null;    if(!isMailData)//不是郵件資料     cmd+=CRLF;     logs+=cmd;    //開始寫入郵件資料    if(!isMailData)    {     cmd_b=Encoding.ASCII.GetBytes(cmd);     ns.Write(cmd_b,0,cmd_b.Length);    }    else    {     cmd_b=Encoding.GetEncoding(this.mailEncodingName).GetBytes(cmd);     ns.BeginWrite(cmd_b,0,cmd_b.Length,new AsyncCallback(this.asyncCallBack),null);    }    //讀取伺服器響應    StreamReader reader=new StreamReader(ns);    string response=reader.ReadLine();    logs+=response+CRLF;    //檢查狀態代碼    string statusCode=response.Substring(0,3);    bool isExist=false;    bool isRightCode=true;    foreach(string err in this.errorCodes.Keys)    {     if(statusCode==err)     {      isExist=true;      isRightCode=false;      break;     }    }    foreach(string right in this.rightCodes.Keys)    {     if(statusCode==right)     {      isExist=true;      break;     }    }    //根據狀態代碼來處理下一步的動作    if(!isExist) //不是合法的SMTP主機    {     this.setError("不是合法的SMTP主機,或伺服器拒絕服務");    }    else if(!isRightCode)//命令沒能成功執行    {     this.setError(statusCode+":"+this.errorCodes[statusCode]);    }    else //命令成功執行    {     this.errorMessage="";    }    return response;   }   else   {    return null;   }  }  /// <summary>  /// 通過auth login方式登陸smtp伺服器  /// </summary>  private void landingByLogin()  {   string base64UserId=this.convertBase64String(this.UserID,"ASCII");   string base64Pass=this.convertBase64String(this.Password,"ASCII");   //握手   this.sendCommand("helo "+this.serverName,false);   //開始登陸   this.sendCommand("auth login",false);   this.sendCommand(base64UserId,false);   this.sendCommand(base64Pass,false);  }  /// <summary>  /// 通過auth plain方式登陸伺服器  /// </summary>  private void landingByPlain()  {   string NULL=((char)0).ToString();   string loginStr=NULL+this.UserID+NULL+this.Password;   string base64LoginStr=this.convertBase64String(loginStr,"ASCII");   //握手   this.sendCommand("helo "+this.serverName,false);   //登陸   this.sendCommand(base64LoginStr,false);  }  /// <summary>  /// 通過auth CRAM-MD5方式登陸  /// </summary>  private void landingByCRAMMD5()  {   //握手   this.sendCommand("helo "+this.serverName,false);   //登陸   string response=this.sendCommand("auth CRAM-MD5",false);   //得到伺服器返回的標識   string identifier=response.Remove(0,4);   //用MD5加密標識   KSN_MACTripleDES mac=new KSN_MACTripleDES();   mac.Key=this.Password;   mac.Data=Encoding.ASCII.GetBytes(identifier);   string hash=mac.GetHashValue();   //發送使用者帳號資訊   this.sendCommand(this.UserID+" "+hash,false);  }  /// <summary>  /// 發送郵件  /// </summary>  /// <returns></returns>  public bool SendMail(MailMessage mail)  {   bool isSended=true;   try   {    //檢測發送郵件的必要條件    if(mail.Sender==null)    {     this.setError("沒有設定發信人");    }    if(mail.Receivers.Count==0)    {     this.setError("至少要有一個收件者");    }    if(this.SmtpValidateType!=SmtpValidateTypes.None)    {     if(this.userid==null || this.password==null)     {      this.setError("當前設定需要smtp驗證,但是沒有給出登陸帳號");     }    }    //開始登陸    switch(this.SmtpValidateType)    {     case SmtpValidateTypes.None:      this.sendCommand("helo "+this.serverName,false);      break;     case SmtpValidateTypes.Login:      this.landingByLogin();      break;     case SmtpValidateTypes.Plain:      this.landingByPlain();      break;     case SmtpValidateTypes.CRAMMD5:      this.landingByCRAMMD5();      break;     default:      break;    }    //初始化郵件會話(對應SMTP命令mail)    this.sendCommand("mail from:<"+mail.Sender+">",false);    //標識收件者(對應SMTP命令Rcpt)    foreach(string receive in mail.Receivers)    {     this.sendCommand("rcpt to:<"+receive+">",false);    }    //標識開始輸入郵件內容(Data)    this.sendCommand("data",false);    //開始編寫郵件內容    string message="Subject:"+mail.Subject+CRLF;    message+="X-mailer:"+mail.XMailer+CRLF;    message+="MIME-Version:1.0"+CRLF;    if(mail.Attachments.Count==0)//沒有附件    {     if(mail.MailType==MailTypes.Text) //文字格式設定     {      message+="Content-Type:text/plain;"+CRLF+" ".PadRight(8,' ')+"charset=\""+       mail.MailEncoding.ToString()+"\""+CRLF;      message+="Content-Transfer-Encoding:base64"+CRLF+CRLF;      if(mail.MailBody!=null)       message+=Convert.ToBase64String(mail.MailBody,0,mail.MailBody.Length)+CRLF+CRLF+CRLF+"."+CRLF;     }     else//Html格式     {      message+="Content-Type:multipart/alertnative;"+CRLF+" ".PadRight(8,' ')+"boundary"       +"=\"=====003_Dragon310083331177_=====\""+CRLF+CRLF+CRLF;      message+="This is a multi-part message in MIME format"+CRLF+CRLF;      message+="--=====003_Dragon310083331177_====="+CRLF;      message+="Content-Type:text/html;"+CRLF+" ".PadRight(8,' ')+"charset=\""+       mail.MailEncoding.ToString().ToLower()+"\""+CRLF;      message+="Content-Transfer-Encoding:base64"+CRLF+CRLF;      if(mail.MailBody!=null)       message+=Convert.ToBase64String(mail.MailBody,0,mail.MailBody.Length)+CRLF+CRLF;      message+="--=====003_Dragon310083331177_=====--"+CRLF+CRLF+CRLF+"."+CRLF;     }    }    else//有附件    {     //處理要在郵件中顯示的每個附件的資料     StringCollection attatchmentDatas=new StringCollection();     foreach(string path in mail.Attachments)     {      if(!File.Exists(path))      {       this.setError("指定的附件沒有找到"+path);      }      else      {       //得到附件的位元組流       FileInfo file=new FileInfo(path);       FileStream fs=new FileStream(path,FileMode.Open,FileAccess.Read);       if(fs.Length>(long)int.MaxValue)       {        this.setError("附件的大小超出了最大限制");       }       byte[] file_b=new byte[(int)fs.Length];       fs.Read(file_b,0,file_b.Length);       fs.Close();       string attatchmentMailStr="Content-Type:application/octet-stream;"+CRLF+" ".PadRight(8,' ')+"name="+        "\""+file.Name+"\""+CRLF;       attatchmentMailStr+="Content-Transfer-Encoding:base64"+CRLF;       attatchmentMailStr+="Content-Disposition:attachment;"+CRLF+" ".PadRight(8,' ')+"filename="+        "\""+file.Name+"\""+CRLF+CRLF;       attatchmentMailStr+=Convert.ToBase64String(file_b,0,file_b.Length)+CRLF+CRLF;       attatchmentDatas.Add(attatchmentMailStr);      }     }     //設定郵件資訊     if(mail.MailType==MailTypes.Text) //文字格式設定     {      message+="Content-Type:multipart/mixed;"+CRLF+" ".PadRight(8,' ')+"boundary=\"=====001_Dragon320037612222_=====\""       +CRLF+CRLF;      message+="This is a multi-part message in MIME format."+CRLF+CRLF;      message+="--=====001_Dragon320037612222_====="+CRLF;      message+="Content-Type:text/plain;"+CRLF+" ".PadRight(8,' ')+"charset=\""+mail.MailEncoding.ToString().ToLower()+"\""+CRLF;      message+="Content-Transfer-Encoding:base64"+CRLF+CRLF;      if(mail.MailBody!=null)       message+=Convert.ToBase64String(mail.MailBody,0,mail.MailBody.Length)+CRLF;      foreach(string s in attatchmentDatas)      {       message+="--=====001_Dragon320037612222_====="+CRLF+s+CRLF+CRLF;      }      message+="--=====001_Dragon320037612222_=====--"+CRLF+CRLF+CRLF+"."+CRLF;     }     else     {      message+="Content-Type:multipart/mixed;"+CRLF+" ".PadRight(8,' ')+"boundary=\"=====001_Dragon255511664284_=====\""       +CRLF+CRLF;      message+="This is a multi-part message in MIME format."+CRLF+CRLF;      message+="--=====001_Dragon255511664284_====="+CRLF;      message+="Content-Type:text/html;"+CRLF+" ".PadRight(8,' ')+"charset=\""+mail.MailEncoding.ToString().ToLower()+"\""+CRLF;      message+="Content-Transfer-Encoding:base64"+CRLF+CRLF;      if(mail.MailBody!=null)       message+=Convert.ToBase64String(mail.MailBody,0,mail.MailBody.Length)+CRLF+CRLF;      for(int i=0;i<attatchmentDatas.Count;i++)      {       message+="--=====001_Dragon255511664284_====="+CRLF+attatchmentDatas[i]+CRLF+CRLF;      }      message+="--=====001_Dragon255511664284_=====--"+CRLF+CRLF+CRLF+"."+CRLF;     }    }    //發送郵件資料    this.mailEncodingName=mail.MailEncoding.ToString();    this.sendCommand(message,true);    if(this.sendIsComplete)     this.sendCommand("QUIT",false);   }   catch   {    isSended=false;   }   finally   {    this.disconnect();    //輸出記錄檔    if(this.LogPath!=null)    {     FileStream fs=null;     if(File.Exists(this.LogPath))     {      fs=new FileStream(this.LogPath,FileMode.Append,FileAccess.Write);      this.logs=CRLF+CRLF+this.logs;     }     else      fs=new FileStream(this.LogPath,FileMode.Create,FileAccess.Write);     byte[] logPath_b=Encoding.GetEncoding("gb2312").GetBytes(this.logs);     fs.Write(logPath_b,0,logPath_b.Length);     fs.Close();    }   }   return isSended;  }  /// <summary>  /// 非同步寫入資料  /// </summary>  /// <param name="result"></param>  private void asyncCallBack(IAsyncResult result)  {   if(result.IsCompleted)    this.sendIsComplete=true;  }  /// <summary>  /// 關閉串連  /// </summary>   private void disconnect()  {   try   {    ns.Close();    tc.Close();   }   catch   {    ;   }  }  /// <summary>  /// 設定出現錯誤時的動作  /// </summary>  /// <param name="errorStr"></param>  private void setError(string errorStr)  {   this.errorMessage=errorStr;   logs+=this.errorMessage+CRLF+"【郵件處理動作中止】"+CRLF;   this.disconnect();   throw new ApplicationException("");  }  /// <summary>  ///將字串轉換為base64  /// </summary>  /// <param name="str"></param>  /// <param name="encodingName"></param>  /// <returns></returns>  private string convertBase64String(string str,string encodingName)  {   byte[] str_b=Encoding.GetEncoding(encodingName).GetBytes(str);   return Convert.ToBase64String(str_b,0,str_b.Length);  }  #endregion }}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.