邮件发送在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:   webmaster@sina.com   
    
  这是告诉服务器发件人的邮件地址   
    
  RCPT   TO:<收件人地址>   例如:RCPT   TO:   webmaster@sina.com   
    
  这是告诉服务器收件人的邮件地址   
    
  DATA     
    
  输入这个命令后,服务器正式开始接受数据   
    
  .   
    
  数据输入完成后,必须输入命令“.”,服务器就会停止数据的接受.   
    
  QUIT   退出系统   
    
  上面是一些基本命令的描述,如果大家还有什么不懂的地方,可以参考TCP/IP有关的书籍,也可以到这个网站看看RFC文档:http://210.25.132.18/rfc/index.html   
    
  现在我们正式开始,看看在C# 中如何来进行工作。   
    
  第一步:创建一个类,命名为MailSend,这个类继承System.Net.Sockets.TcpClient   
    
  using   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为数据的字符语言编码,一般可以设置为GB2312   
    
  private   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;   
    
  else   
    
  page=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);//将数据写入到服务器上   
    
  }   
    
  }   
    
  else   
    
  TcpStream.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的连接,否则我Top

5 楼elizalz(幺幺妖)回复于 2002-11-19 17:22:36 得分 0

(接上篇)   
  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:管理员<webmaster@sina.com>   
    
  TO:<姓名><邮件地址>   格式:TO:水生月<1234@sina.com>   
    
  SUBJECT:<标题>   格式:SUBJECT:今天的天气很不错!   
    
  DATE:<时间>   格式:DATE:   Thu,   29   Aug   2002   09:52:47   +0800   (CST)   
    
  REPLY-TO:<邮件地址>   格式:REPLY-TO:webmaster@sina.com   
    
  Content-Type:<邮件类型>   格式:Content-Type:   multipart/mixed;   boundary=unique-boundary-1   
    
  X-Priority:<邮件优先级>   格式:X-Priority:3   
    
  MIME-Version:<版本>   格式:MIME-Version:1.0   
    
  Content-Transfer-Encoding:<内容传输编码>   格式:Content-Transfer-Encoding:Base64   
    
  X-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();//发送邮件   
    
  在此篇文章中我并没有给出完整的代码,而只是给出了代码片段,但是这已经足够整理出整个程序了。

******************************************************************************

c#发送需要smtp认证的邮件
时间: 2006-07-11 来自:canbo

-------------------------调用类 -----------------------------------
private void SendMaill(string username,string superpassword,string email) {
   string body="尊敬的用户:<br><br>您好!<br><br>&nbsp;&nbsp;你的登录用户名是:"+username+"这是你的超级密码:"+superpassword
    +"为了您的账号安全,我们建议您在收到邮件的72小时之内,到官方网站进行修改,并把该邮件删除。"
    +"<br><br>"
    +" 如有任何疑问,欢迎致电×××××发展有限责任公司客服热线:028-×××××××,我们将热情为您解答。"
    +" 感谢您的支持!<br><br>"
   +"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;××××××发展有限责任公司<br><br>"
   +"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"+System.DateTime.Now.Year+"年"+System.DateTime.Now.Month+"月"+System.DateTime.Now.Day+"日<br><br>" 
    +"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;官网:http://www.×××××.com<br><br>"
    +"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;××××:http://www.××××.com";
   
   lion_office.Data.Library.MailClass.ESmtpMail sm=new lion_office.Data.Library.MailClass.ESmtpMail();
   sm.Send("mail.××××.com",
     "×××@××××.com",
     "××客服",
     email,
     username,
    true,
    "×××官方网站密码找回邮件",
    body
        );

Session.Remove("dd");
   Response.Redirect("FindSPassOK.aspx");
    }

-------------------------基类---------------------

using System; 
using System.Text; 
using System.IO; 
using System.Net; 
using System.Net.Sockets; 
using System.Collections;

namespace lion_office.Data.Library.MailClass 

/*  
Create By lion  
2002-11-20 01:44  
Copyright (C) 2001,2002 www.LionSky.Net. All rights reserved. 
Web: http://www.Lionsky.net ;;
Email: lion-a@sohu.com 
Support .Net Framework Beta 2  
*/  
   public class ESmtpMail 
   { 
      private string enter="/r/n"; 
      /// <summary> 
      /// 设定语言代码,默认设定为GB2312,如不需要可设置为"" 
      /// </summary> 
      public string Charset="GB2312"; 
      /// <summary> 
      /// 发件人地址 
      /// </summary> 
      public string From=""; 
      /// <summary> 
      /// 发件人姓名 
      /// </summary> 
      public string FromName=""; 
      /// <summary> 
      /// 回复邮件地址 
      /// </summary> 
      //public string ReplyTo=""; 
      /// <summary> 
      /// 收件人姓名 
      /// </summary>    
      public string RecipientName=""; 
      /// <summary> 
      /// 收件人列表 
      /// </summary> 
      private Hashtable Recipient=new Hashtable(); 
      /// <summary> 
      /// 邮件服务器域名 
      /// </summary>    
      private string mailserver=""; 
      /// <summary> 
      /// 邮件服务器端口号 
      /// </summary>    
      private int mailserverport=25; 
      /// <summary> 
      /// SMTP认证时使用的用户名 
      /// </summary> 
      private string username=""; 
      /// <summary> 
      /// SMTP认证时使用的密码 
      /// </summary> 
      private string password=""; 
      /// <summary> 
      /// 是否需要SMTP验证 
      /// </summary>       
      private bool ESmtp=false; 
      /// <summary> 
      /// 是否Html邮件 
      /// </summary>       
      public bool Html=false; 
      /// <summary> 
      /// 邮件附件列表 
      /// </summary> 
      private System.Collections.ArrayList Attachments; 
      /// <summary> 
      /// 邮件发送优先级,可设置为"High","Normal","Low"或"1","3","5" 
      /// </summary> 
      private string priority="Normal"; 
      /// <summary> 
      /// 邮件主题 
      /// </summary>       
      public string Subject=""; 
      /// <summary> 
      /// 邮件正文 
      /// </summary>       
      public string Body=""; 
      /// <summary> 
      /// 收件人数量 
      /// </summary> 
      private int RecipientNum=0; 
      /// <summary> 
      /// 最多收件人数量 
      /// </summary> 
      private int recipientmaxnum=1; 
      /// <summary> 
      /// 密件收件人数量 
      /// </summary> 
      //private int RecipientBCCNum=0; 
      /// <summary> 
      /// 错误消息反馈 
      /// </summary> 
      private string errmsg; 
      /// <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(); 
      public ESmtpMail() 
      { 
         Attachments = new System.Collections.ArrayList(); 
      }       
      /// <summary> 
      /// 邮件服务器域名和验证信息 
      /// 形如:"user:paswww.server.com:25",也可省略次要信息。如"user:paswww.server.com"www.server.com" 
      /// </summary>    
      public string MailDomain 
      { 
         set 
         { 
            string maidomain=value.Trim(); 
            int tempint;

if(maidomain!="") 
            { 
               tempint=maidomain.IndexOf("@"); 
               if(tempint!=-1) 
               { 
                  string str=maidomain.Substring(0,tempint); 
                  MailServerUserName=str.Substring(0,str.IndexOf(":")); 
                  MailServerPassWord=str.Substring(str.IndexOf(":")+1,str.Length-str.IndexOf(":")-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>    
      public int MailDomainPort 
      { 
         set 
         { 
            mailserverport=value; 
         } 
      }

/// <summary> 
      /// SMTP认证时使用的用户名 
      /// </summary> 
      public string MailServerUserName 
      { 
         set 
         { 
            if(value.Trim()!="") 
            { 
               username=value.Trim(); 
               ESmtp=true; 
            } 
            else 
            { 
               username=""; 
               ESmtp=false; 
            } 
         } 
      }

/// <summary> 
      /// SMTP认证时使用的密码 
      /// </summary> 
      public string MailServerPassWord 
      { 
         set 
         { 
            password=value; 
         } 
      }

/// <summary> 
      /// 邮件发送优先级,可设置为"High","Normal","Low"或"1","3","5" 
      /// </summary> 
      public string Priority 
      { 
         set 
         { 
            switch(value.ToLower()) 
            { 
               case "high": 
                  priority="High"; 
                  break;

case "1": 
                  priority="High"; 
                  break;

case "normal": 
                  priority="Normal"; 
                  break;

case "3": 
                  priority="Normal"; 
                  break;

case "low": 
                  priority="Low"; 
                  break;

case "5": 
                  priority="Low"; 
                  break;

default: 
                  priority="Normal"; 
                  break; 
            } 
         } 
      }

/// <summary> 
      /// 错误消息反馈 
      /// </summary>       
      public string ErrorMessage 
      { 
         get 
         { 
            return errmsg; 
         } 
      }

/// <summary> 
      /// 服务器交互记录 
      /// </summary> 
      private string logs="";

/// <summary> 
      /// 服务器交互记录,如发现本组件不能使用的SMTP服务器,请将出错时的Logs发给我(lion-a@sohu.com),我将尽快查明原因。 
      /// </summary> 
      public string Logs 
      { 
         get 
         { 
            return logs; 
         } 
      }

/// <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","开始邮件输入,以<enter>.<enter>结束"); 
         RightCodeHT.Add("221","服务关闭传输信道"); 
         RightCodeHT.Add("334","服务器响应验证Base64字符串"); 
         RightCodeHT.Add("235","验证成功"); 
      }

/// <summary> 
      /// 将字符串编码为Base64字符串 
      /// </summary> 
      /// <param name="estr">要编码的字符串</param> 
      private string Base64Encode(string str) 
      { 
         byte[] barray; 
         barray=Encoding.Default.GetBytes(str); 
         return Convert.ToBase64String(barray); 
      }

/// <summary> 
      /// 将Base64字符串解码为普通字符串 
      /// </summary> 
      /// <param name="dstr">要解码的字符串</param> 
      private string Base64Decode(string str) 
      { 
         byte[] barray; 
         barray=Convert.FromBase64String(str); 
         return Encoding.Default.GetString(barray); 
      }

/// <summary> 
      /// 得到上传附件的文件流 
      /// </summary> 
      /// <param name="FilePath">附件的绝对路径</param> 
      private string GetStream(string FilePath) 
      { 
         //建立文件流对象 
         System.IO.FileStream FileStr=new System.IO.FileStream(FilePath,System.IO.FileMode.Open); 
         byte[] by=new byte[System.Convert.ToInt32(FileStr.Length)]; 
         FileStr.Read(by,0,by.Length); 
         FileStr.Close(); 
         return(System.Convert.ToBase64String(by)); 
      }

/// <summary> 
      /// 添加邮件附件 
      /// </summary> 
      /// <param name="path">附件绝对路径</param> 
      public void AddAttachment(string path) 
      { 
         Attachments.Add(path); 
      }

/// <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<recipientmaxnum) 
         { 
            Recipient.Add(RecipientNum,str); 
            RecipientNum++;             
            return true; 
         } 
         else 
         { 
            errmsg+="收件人过多"; 
            return false; 
         } 
      }

/// <summary> 
      /// 最多收件人数量 
      /// </summary> 
      public int RecipientMaxNum 
      { 
         set 
         { 
            recipientmaxnum = value; 
         } 
      }

/// <summary> 
      /// 添加一组收件人(不超过recipientmaxnum个),参数为字符串数组 
      /// </summary> 
      /// <param name="str">保存有收件人地址的字符串数组(不超过recipientmaxnum个)</param>    
      public bool AddRecipient(string[] str) 
      { 
         for(int i=0;i<str.Length;i++) 
         { 
            if(!AddRecipient(str[i])) 
            { 
               return false; 
            } 
         } 
         return true; 
      }

/// <summary> 
      /// 发送SMTP命令 
      /// </summary>    
      private bool SendCommand(string str) 
      { 
         byte[]  WriteBuffer; 
         if(str==null||str.Trim()=="") 
         { 
            return true; 
         } 
         logs+=str; 
         WriteBuffer = Encoding.Default.GetBytes(str); 
         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 str,string errstr) 
      { 
         if(str==null||str.Trim()=="") 
         { 
            return true; 
         } 
         if(SendCommand(str)) 
         { 
            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[] str,string errstr) 
      { 
         for(int i=0;i<str.Length;i++) 
         { 
            if(!Dialog(str[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[recipientmaxnum]; 
         for(int i=0;i<Recipient.Count;i++) 
         {

SendBuffer[i]="RCPT TO:<" + Recipient[i].ToString() +">" + enter;


         if(!Dialog(SendBuffer,"收件人地址有误")) 
            return false;

SendBufferstr="DATA" + enter; 
         if(!Dialog(SendBufferstr,"")) 
            return false;

SendBufferstr="From:" + FromName + "<" + From +">" +enter;

SendBufferstr += "To:=?"+Charset.ToUpper()+"?B?"+Base64Encode(RecipientName)+"?="+"<"+Recipient[0]+">"+enter; 
         SendBufferstr+="CC:"; 
         for(int i=0;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: Huolx.Pubclass" + enter; 
         SendBufferstr+="MIME-Version: 1.0" + enter;

SendBufferstr += "Content-Type: multipart/mixed;"+enter;//内容格式和分隔符 
         SendBufferstr += "   boundary=/"----=_NextPart_000_00D6_01C29593.AAB31770/""+enter; 
         SendBufferstr += "------=_NextPart_000_00D6_01C29593.AAB31770"+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+="Content-Transfer-Encoding: base64" + enter + enter;

SendBufferstr+= Base64Encode(Body) + enter; 
         if(Attachments.Count!=0) 
         { 
            foreach(string filepath in Attachments) 
            { 
                
               SendBufferstr += "------=_NextPart_000_00D6_01C29593.AAB31770"+enter; 
               SendBufferstr += "Content-Type: application/octet-stream"+enter; 
               SendBufferstr += "   name=/"=?"+Charset.ToUpper()+"?B?"+Base64Encode(filepath.Substring(filepath.LastIndexOf("//")+1))+"?=/""+enter; 
               SendBufferstr += "Content-Transfer-Encoding: base64"+enter; 
               SendBufferstr += "Content-Disposition: attachment;"+enter; 
               SendBufferstr += "   filename=/"=?"+Charset.ToUpper()+"?B?"+Base64Encode(filepath.Substring(filepath.LastIndexOf("//")+1))+"?=/""+enter+enter; 
               SendBufferstr += GetStream(filepath)+enter+enter; 
            } 
         } 
         SendBufferstr += "------=_NextPart_000_00D6_01C29593.AAB31770--"+enter+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(mailserver.Trim()=="") 
         { 
            errmsg="必须指定SMTP服务器"; 
            return false; 
         }

return SendEmail(); 
          
      }

/// <summary> 
      /// 发送邮件方法 
      /// </summary> 
      /// <param name="smtpserver">smtp服务器信息,如"username:passwordwww.smtpserver.com:25",也可去掉部分次要信息,如www.smtpserver.com"</param> 
      public bool Send(string smtpserver) 
      { 
          
         MailDomain=smtpserver; 
         return Send(); 
      }

/// <summary> 
      /// 发送邮件方法 
      /// </summary> 
      /// <param name="smtpserver">smtp服务器信息,如"username:passwordwww.smtpserver.com:25",也可去掉部分次要信息,如www.smtpserver.com"</param> 
      /// <param name="from">发件人mail地址</param> 
      /// <param name="fromname">发件人姓名</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 to,string toname,bool html,string subject,string body) 
      { 
         MailDomain=smtpserver; 
         From=from; 
         FromName=fromname; 
         AddRecipient(to); 
         RecipientName=toname; 
         Html=html; 
         Subject=subject; 
         Body=body; 
         return Send(); 
      } 
       
       
   } 
}

************************************

SendEMail 发送邮件相关推荐

  1. 如何使用sendEmail发送邮件

    为什么80%的码农都做不了架构师?>>>    sendEmail是一个轻量级,命令行的SMTP邮件客户端.如果你需要使用命令行发送邮件,那么sendEmail是非常完美的选择:使用 ...

  2. sendEmail发送邮件

    sendEmail发送邮件 sendEmail是一个轻量级,命令行的SMTP邮件客户端.如果你需要使用命令行发送邮件,那么sendEmail是非常完美的选择:使用简单并且功能强大.这个被设计用在php ...

  3. mail、sendEmail发送邮件命令

    申请临时邮箱地址 https://blog.csdn.net/u012206617/article/details/104632026 Centos centos自带mail工具 安装mail yum ...

  4. Shell使用sendemail发送邮件脚本

    原文地址:http://www.zixuephp.net/article-400.html shell发送邮件,这里要介绍的是sendemail工具,通过这个工具连接第三方的smtp服务器,进行邮件的 ...

  5. Linux 通过 sendEmail 发送邮件(shell批量发送邮件)

    sendEmail 是一个轻量级,命令行的SMTP邮件客户端.如果你需要使用命令行发送邮件,那么sendEmail是非常完美的选择 或者使用脚本临时发送批量邮件 #下载安装包 wget http:// ...

  6. 【转载】Git 常用命令大全

    一. Git 常用命令速查 git branch 查看本地所有分支 git status 查看当前状态  git commit 提交  git branch -a 查看所有的分支 git branch ...

  7. nagios配置安装

    Nagios官网:https://www.nagios.org/ nagios重状态和结果,支持告警,没有数据历史,不用数据库,不成图像,不支持web配置,也可以自己开发脚本定制个性化的监控,支持多插 ...

  8. Git 常用命令速查表(图文+表格)

    一. Git 常用命令速查 git branch 查看本地所有分支 git status 查看当前状态  git commit 提交  git branch -a 查看所有的分支 git branch ...

  9. ZABBIX3.0配置邮件报警

    环境介绍: zabbix版本:3.0.5 操作系统:Centos6.8 IP地址:192.168.10.150 2. 安装sendEmail sendEmail是一个免费.轻量级.命令行的SMTP邮件 ...

最新文章

  1. 伪基站识别技巧(一)
  2. 机器人扫地机吸狗毛最好的_狗狗掉毛扫地机不好使?看看人家美国人的评测
  3. 打印Show Attend and Tell的损失函数
  4. JavaScript实现squareMatrixRotation方阵旋转算法(附完整源码)
  5. AJAX并不神秘:揭密各种AJAX控件和类库
  6. Hibernate查询缓存
  7. 速览Java 7 MethodHandle及其用法
  8. 努力过头了,其实并不好
  9. Spark Structured SQL : NumberFormatException: Zero length BigInteger
  10. Madagascar的宏定义函数--取最值、取整
  11. ESP32 开发之旅② Arduino For ESP32说明
  12. Web开发入门型服务器使用心得
  13. 该来的还是要来,数据挖掘
  14. 谈谈深浅拷贝的问题(1)
  15. AJAX 简单例程示例
  16. 电脑桌面图标DIY --- 制作透明的快捷图标
  17. Deep Knowledge Tracing
  18. 比特大陆新一轮裁员50%,回应称系人员调整
  19. Dell T7920工作站 拆装硬盘
  20. java -version 自动被切换的问题 : C:\ProgramData\Oracle\Java\javapath;

热门文章

  1. 苹果6s能安装通讯测试软件么,iOS 13在iPhone 6S和SE上运行情况如何
  2. 遇到的坑-语法错误: Non-UTF-8 code starting with '\xe7' in file
  3. 教学软件推荐-极域数字语音教室
  4. android app 获得root 权限管理,获得Android App的“root”权限
  5. [Unity官方文档翻译]Downloading and Installing Unity下载和安装unity教程
  6. 模仿,类比,移植技法(创新技法5)
  7. linux kernel内存管理之/proc/meminfo下参数介绍
  8. 生信人迷惑的一天 bam转fq
  9. 关于文件格式识别转换
  10. JM编码器码率控制算法笔记:以JVT-G012r1为例