热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

*使用C#创建邮件发送组件(SMTP)

邮件发送在web应用中是屡见不鲜的,在asp时代大家多是利用一些第三方提供的组件如JMAIL、ASPMAIL等进行邮件发送。自从微软推出Asp.net后,
邮件发送在web应用中是屡见不鲜的,在asp时代大家多是利用一些第三方提供的组件如JMAIL、ASPMAIL等进行邮件发送。自从微软推出Asp.net后,很多程序员开始转向采用C#作为主要的开发语言。asp.net提供了更加强大的功能,同时也提供给了大家一个SMTP类作为邮件发送之用。但是,随着垃圾邮件的广泛传播,很多邮件服务提供商纷纷增加了SMTP 的认证手续,也就是ESMTP,而微软提供的SMTP类居然不支持认证发送。当然现在网上也出现了一些解决方案,利用其他的一些手段来发出认证信息。但我想,是不是还有更好的呢?为了解决这个问题,笔者两日茶饭不思,日以继夜,终于找到了一个方法:)。下面,我们将利用TCPCLIENT这个类直接与SMTP服务器通讯进行邮件的发送。
  
  
  实际上原理也就是利用套接字(Socket)和服务器进行对话通讯,按照SMTP协议的规范,和服务器建立联系。我们以往用的一些邮件组件都是这么做的。
  
  
  在开始之前,我们要对SMTP协议及其扩展ESMTP有个初步的了解。
  
  
  SMTP和ESMTP的一些主要命令格式有以下一些:
  
  
  HELO <信息发送端的名称> 例如&#xff1a;HELO Localhost
  
  
  这相当于和服务器打个招呼&#xff0c;你好&#xff0c;我是某某
  
  
  EHLO <信息发送端的名称> 例如&#xff1a;EHLO Localhost
  
  
  这是针对ESMTP服务器的接触方式&#xff0c;必须输入这个命令&#xff0c;系统才会开始认证程序
  
  
  AUTH LOGIN
  
  
  输入这个命令&#xff0c;系统的认证程序将会启动&#xff0c;同时系统会返回一个经过Base64处理过的字符串&#xff0c;意思是"请输入用户名"。接着必须发送用户名给服务器&#xff0c;用户名也必须经过Base64编码转换&#xff0c;服务器在通过用户名的认证之后会要求输入密码&#xff0c;此时输入经过Base64编码转换后的密码。成功后&#xff0c;即可运行下面的命令了。
  
  
  MAIL FROM:<发件人地址> 例如&#xff1a;MAIL FROM: webmaster&#64;sina.com
  
  
  这是告诉服务器发件人的邮件地址
  
  
  RCPT TO:<收件人地址> 例如&#xff1a;RCPT TO: webmaster&#64;sina.com
  
  
  这是告诉服务器收件人的邮件地址
  
  
  DATA
  
  
  输入这个命令后&#xff0c;服务器正式开始接受数据
  
  
  .
  
  
  数据输入完成后&#xff0c;必须输入命令"."&#xff0c;服务器就会停止数据的接受.
  
  
  QUIT 退出系统
  
  
  上面是一些基本命令的描述&#xff0c;如果大家还有什么不懂的地方&#xff0c;可以参考TCP/IP有关的书籍&#xff0c;也可以到这个网站看看RFC文档&#xff1a;http://210.25.132.18/rfc/index.html
  
  
  现在我们正式开始&#xff0c;看看在C# 中如何来进行工作。
  
  
  第一步&#xff1a;创建一个类&#xff0c;命名为MailSend&#xff0c;这个类继承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这个类&#xff0c;它的主要作用就是为TCP网络服务提供客户端的连接&#xff0c;大家可以看到&#xff0c;他来源于Sockets这个包&#xff0c;实际上是基于 Socket 类构建。不过他以更高的抽象程度提供 TCP 服务&#xff0c;操作起来也更简单。
  
  
  第二步&#xff1a;建立一些基本的变量及连接方法
  
  
  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;//邮件优先级
  
  
  以上定义的都是邮件发送所需的一些基本信息&#xff0c;可以将上述变量做为属性来传递。
  
  
  如&#xff1a;
  
  
  public String SMTPServer
  
  
  {
  
  
  set{this.server&#61;value;}
  
  
  }
  
  
  其余的也可如此.
  
  
  2、向服务器写入命令的方法
  
  
  变量strCmd为需要输入的命令或数据的字符串
  
  
  变量charset为数据的字符语言编码&#xff0c;一般可以设置为GB2312
  
  
  private void WriteStream(String strCmd,String charset)
  
  
  {
  
  
  Stream TcpStream;//定义操作对象
  
  
  strCmd &#61; strCmd &#43; "\r\n"; //加入换行符
  
  
  TcpStream &#61;this.GetStream();//获取数据流
  
  
  //将命令行转化为byte[]
  
  
  byte[] bWrite &#61; Encoding.GetEncoding(charset).GetBytes(strCmd.ToCharArray());
  
  
  //由于每次写入的数据大小是有限制的&#xff0c;那么我们将每次写入的数据长度定在&#xff17;&#xff15;个字节&#xff0c;一旦命令长度超过了&#xff17;&#xff15;&#xff0c;就分步写入。
  
  
  int start&#61;0;
  
  
  int length&#61;bWrite.Length;
  
  
  int page&#61;0;
  
  
  int size&#61;75;
  
  
  int count&#61;size;
  
  
  if (length>75)
  
  
  {
  
  
  //数据分页
  
  
  if ((length/size)*size
  
  page&#61;length/size&#43;1;
  
  
  else
  
  
  page&#61;length/size;
  
  
  for (int i&#61;0;i
  
  {
  
  
  start&#61;i*size;
  
  
  if (i&#61;&#61;page-1)
  
  
  count&#61;length-(i*size);
  
  
  TcpStream.Write(bWrite,start,count);//将数据写入到服务器上
  
  
  }
  
  
  }
  
  
  else
  
  
  TcpStream.Write(bWrite,0,bWrite.Length);
  
  
  }
  
  
  catch(Exception)
  
  
  {}
  
  
  }
  
  
  本方法中&#xff0c;我们最后用到的也就最重要的就是TcpStream.Write()这句话&#xff0c;前面所做的只是将数据分页&#xff0c;可以分步写入。另外在写入数据时&#xff0c;必须把字符串转化为byte[]类型。在这里我用的是Stream这个对象&#xff0c;同时你也可以使用NetworkStream这个对象来进行操作&#xff0c;实际效果是一致的。在下面的返回信息获取中&#xff0c;我就用到了NetworkStream&#xff0c;实际上这也是帮助大家熟悉流操作对象的一个过程。
  
  
  3、获取服务器的返回信息
  
  
  private string ReceiveStream()
  
  
  {
  
  
  String sp&#61;null;
  
  
  byte[] by&#61;new byte[1024];
  
  
  NetworkStream ns &#61; this.GetStream();//此处即可获取服务器的返回数据流
  
  
  int size&#61;ns.Read(by,0,by.Length);//读取数据流
  
  
  if (size>0)
  
  
  {
  
  
  sp&#61;Encoding.Default.GetString(by);//转化为String
  
  
  }
  
  
  return sp;
  
  
  }
  
  
  除了输入DATA命令之后&#xff0c;其余的时间向服务器发送命令&#xff0c;服务器都会返回一些信息&#xff0c;并同时有一个状态码返回&#xff0c;告诉你操作是否成功完成了。一旦输入DATA命令&#xff0c;也就是数据开始传递的这段时间中&#xff0c;服务器不会返回任何信息&#xff0c;直到输入"."结束传递&#xff0c;服务器才会返回信息。
  
  
  4、发出命令并判断返回信息是否正确&#xff0c;也就是看发出的命令服务器是否接受并通过了。
  
  
  本方法实际上将上面的两个方法结合来用&#xff0c;一个写&#xff0c;一个收&#xff0c;然后进行判断&#xff0c;看是否正确。这样我们就能够监控每步操作是否正常进行了。
  
  
  参数strCmd也就是需要输入的命令或者数据
  
  
  参数state为返回的表明操作成功的状态码
  
  
  private bool OperaStream(string strCmd,string state)
  
  
  { string sp&#61;null;
  
  
  bool success&#61;false;
  
  
  try
  
  
  {
  
  
  WriteStream(strCmd);//写入命令
  
  
  sp &#61; ReceiveStream();//接受返回信息
  
  
  if (sp.IndexOf(state)!&#61;-1)//判断状态码是否正确
  
  
  success&#61;true;
  
  
  }
  
  
  catch(Exception ex)
  
  
  {Console.Write(ex.ToString());}
  
  
  return success;
  
  
  }
  
  
  我们进行每一步操作时&#xff0c;都是通过状态码来确定是否成功的&#xff0c;那么如果操作成功&#xff0c;就会返回正确的状态码&#xff0c;根据这个原理&#xff0c;我们在这个方法中&#xff0c;同时输入命令和表明操作成功的状态码&#xff0c;通过获取的数据判断返回的是不是正确的状态码&#xff0c;以此来决定是否继续进行下一步操作。
  
  
  在这里我要告诉大家一些基本的状态码表示的含义。
  
  
  211 帮助返回系统状态
  
  
  214 帮助信息
  
  
  220 服务准备就绪
  
  
  221 关闭连接
  
  
  250 请求操作就绪
  
  
  251 用户不在本地&#xff0c;转寄到
  
  
  
  354 开始邮件输入
  
  
  421 服务不可用
  
  
  450 操作未执行&#xff0c;邮箱忙
  
  
  451 操作中止&#xff0c;本地错误
  
  
  452 操作未执行&#xff0c;存储空间不足
  
  
  500 命令不可识别或语法错
  
  
  501 参数语法错
  
  
  502 命令不支持
  
  
  503 命令顺序错
  
  
  504 命令参数不支持
  
  
  550 操作未执行&#xff0c;邮箱不可用
  
  
  551 非本地用户
  
  
  552 中止&#xff0c;存储空间不足
  
  
  553 操作未执行&#xff0c;邮箱名不正确
  
  
  554 传输失败
  
  
  写完以上的基本方法&#xff0c;我们可以开始和服务器进行连接了。由于现在的服务器有SMTP和ESMTP两种&#xff0c;不同的服务器连接的命令格式不一样&#xff0c;那么我们需要完成一个方法来取得服务器的连接。
  
  
  public bool getMailServer()
  
  
  {
  
  
  try
  
  
  {
  
  
  //域名解析
  
  
  System.Net.IPAddress ipaddress&#61;(IPAddress)System.Net.Dns.Resolve(this.server).AddressList.GetValue(0);
  
  
  System.Net.IPEndPoint endpoint&#61;new IPEndPoint(ipaddress,25);
  
  
  Connect(endpoint);//连接Smtp服务器
  
  
  ReceiveStream();//获取连接信息
  
  
  if (this.username!&#61;null)
  
  
  {
  
  
  //开始进行服务器认证
  
  
  //如果状态码是250则表示操作成功
  
  
  if (!OperaStream("EHLO Localhost","250"))
  
  
  {
  
  
  this.Close();
  
  
  return false;
  
  
  }
  
  
  if (!OperaStream("AUTH LOGIN","334"))
  
  
  {
  
  
  this.Close();
  
  
  return false;
  
  
  }
  
  
  username&#61;AuthStream(username);//此处将username转换为Base64码
  
  
  if (!OperaStream(this.username,"334"))
  
  
  {
  
  
  this.Close();
  
  
  return false;
  
  
  }
  
  
  password&#61;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;}
  
  
  }
  
  
  上面这个方法主要是用于和服务器取得联系&#xff0c;其中包含了针对两种不同服务器的连接方法&#xff0c;如果用户名不为空&#xff0c;那么我们首先进行ESMTP的连接&#xff0c;否则我们和服务器直接获取联系。在ESMTP连接时&#xff0c;用户名和密码必须为Base64编码&#xff0c;否则服务器不会识别。
  
  
  private string AuthStream(String strCmd)
  
  
  {
  
  
  try
  
  
  {
  
  
  byte[] by&#61;Encoding.Default.GetBytes(strCmd.ToCharArray());
  
  
  strCmd&#61;Convert.ToBase64String(by);
  
  
  }
  
  
  catch(Exception ex)
  
  
  {return ex.ToString();}
  
  
  return strCmd;
  
  
  }
  
  
  上面的方法将数据转化为Base64编码字符串&#xff0c;大家如果觉得太抽象了&#xff0c;可以这样试一试&#xff0c;在CMD模式输入telnet smtp.sohu.com 25 然后回车&#xff0c;就可以连接sohu的SMTP服务器&#xff0c;sohu的SMTP服务器采用ESMTP协议&#xff0c;必须认证&#xff0c;大家可以试着操作一下。
  
  
  第三步&#xff1a;关于邮件的附件传递
  
  
  大家有发送邮件时&#xff0c;有时候会包含一些附件&#xff0c;那么本组件也考虑到了这一点。下面我们将会详细讲述如何对附件进行处理
  
  
  filelist&#61;new DataTable();//已定义变量&#xff0c;初始化操作
  
  
  filelist.Columns.Add(new DataColumn("filename",typeof(string)));//文件名
  
  
  filelist.Columns.Add(new DataColumn("filecontent",typeof(string)));//文件内容
  
  
  public void LoadAttFile(String path)
  
  
  {
  
  
  //根据路径读出文件流
  
  
  FileStream fstr&#61;new FileStream(path,FileMode.Open);//建立文件流对象
  
  
  byte[] by&#61;new byte[Convert.ToInt32(fstr.Length)];
  
  
  fstr.Read(by,0,by.Length);//读取文件内容
  
  
  fstr.Close();//关闭
  
  
  //格式转换
  
  
  String fileinfo&#61;Convert.ToBase64String(by);//转化为base64编码
  
  
  //增加到文件表中
  
  
  DataRow dr&#61;filelist.NewRow();
  
  
  dr[0]&#61;Path.GetFileName(path);//获取文件名
  
  
  dr[1]&#61;fileinfo;//文件内容
  
  
  filelist.Rows.Add(dr);//增加
  
  
  }
  
  
  通过这个方法将直接读取出文件的内容信息&#xff0c;然后存储在DataTable对象中&#xff0c;理论上可以读取无数个文件&#xff0c;当然&#xff0c;文件越大&#xff0c;发送时间也就越长。这个方法只是针对本地的附件加入&#xff0c;如果大家有兴趣&#xff0c;可以自己利用HttpRequest做一个网上文件抓取的程序&#xff0c;直接抓取网上的文件&#xff0c;不过一般来说&#xff0c;这种方法很少用得到。好了&#xff0c;闲话不谈&#xff0c;我们已经将文件读入&#xff0c;那么之后如何处理呢&#xff1f;请看下面的一个方法。
  
  
  &#xff11;&#xff1a;private void Attachment()
  
  
  &#xff12;&#xff1a;{ //对文件列表做循环
  
  
  &#xff13;&#xff1a; for (int i&#61;0;i
  
  &#xff14;&#xff1a; {
  
  
  &#xff15;&#xff1a; DataRow dr&#61;filelist.Rows;
  
  
  &#xff16;&#xff1a; WriteStream("--unique-boundary-1");//邮件内容分隔符
  
  
  &#xff17;&#xff1a; WriteStream("Content-Type: application/octet-stream;name&#61;\""&#43;dr[0].ToString()&#43;"\"");//文件格式
  
  
  &#xff18;&#xff1a; WriteStream("Content-Transfer-Encoding: base64");//内容的编码
  
  
  9: WriteStream("Content-Disposition:attachment;filename&#61;\""&#43;dr[0].ToString()&#43;"\"");//文件名
  
  
  10: WriteStream("");
  
  
  11: String fileinfo&#61;dr[1].ToString();
  
  
  12: WriteStream(fileinfo);//写入文件的内容
  
  
  13: WriteStream("");
  
  
  14: }
  
  
  15:}
  
  
  这个方法中我们就用到了WriteStream()方法&#xff0c;大家可能看的有些迷糊&#xff0c;好象无头无尾的&#xff0c;实际上这一段代码&#xff0c;将会在写完邮件的头部信息和文本内容之后再写入到服务器上&#xff0c;在下面的程序中大家可以看见前面的部分。那么在代码的第七行&#xff0c;表示了文件的类型&#xff0c;我这里用了一个偷懒的方式&#xff0c;采用application/octet-stream来代替所有的文件类型&#xff0c;实际上针对大部分的常用文件都有自己的一个格式&#xff0c;大家可以根据其文件名的扩展名进行判断&#xff0c;这里我给出其他的一些格式。
  
  
  扩展名   格式
  
  
  ".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"
  
  
  我比较偷懒&#xff0c;如果有需要的朋友&#xff0c;可以补上一些判断&#xff0c;获取文件的原本格式。
  
  
  第四步&#xff1a;关于邮件的头信息
  
  
  前面讲了这么多&#xff0c;就像是吃大餐之前的甜点&#xff0c;现在我们要进入最重要的部份--邮件的头信息&#xff0c;实际上&#xff0c;这个东西我们见得非常的多&#xff0c;大家在收发邮件的时候&#xff0c;查看邮件的属性就会看见一大串代码&#xff0c;里面有一些邮件地址&#xff0c;IP地址什么的&#xff0c;这就是邮件的头信息。
  
  
  那么头信息的基本内容现在开讲&#xff1a;
  
  
  FROM:<姓名><邮件地址> 格式&#xff1a;FROM:管理员
  
  
  TO:<姓名><邮件地址> 格式&#xff1a;TO:水生月<1234&#64;sina.com>
  
  
  SUBJECT:<标题> 格式&#xff1a;SUBJECT:今天的天气很不错&#xff01;
  
  
  DATE:<时间> 格式&#xff1a;DATE: Thu, 29 Aug 2002 09:52:47 &#43;0800 (CST)
  
  
  REPLY-TO:<邮件地址> 格式&#xff1a;REPLY-TO:webmaster&#64;sina.com
  
  
  Content-Type:<邮件类型> 格式&#xff1a;Content-Type: multipart/mixed; boundary&#61;unique-boundary-1
  
  
  X-Priority:<邮件优先级> 格式&#xff1a;X-Priority:3
  
  
  MIME-Version&#xff1a;<版本> 格式&#xff1a;MIME-Version:1.0
  
  
  Content-Transfer-Encoding:<内容传输编码> 格式&#xff1a;Content-Transfer-Encoding:Base64
  
  
  X-Mailer:<邮件发送者> 格式&#xff1a;X-Mailer:FoxMail 4.0 beta 1 [cn]
  
  
  如果大家安装了OutLook&#xff08;一般都装了&#xff1a;&#xff09;&#xff09;&#xff0c;自己给自己发一封信&#xff0c;收下来后&#xff0c;查看邮件的属性&#xff0c;然后会看到包含上面一些信息的数据&#xff0c;大家可以根据Outlook的头信息为参照。在这里&#xff0c;我重点要讲的是Content-Type这个头信息&#xff0c;实际上我们在邮件发送时常常包含了文本内容&#xff0c;Html超文本内容以及附件内容&#xff0c;那么此时邮件的格式也就是multipart/mixed&#xff0c;但是这么多内容你要是全放在一块&#xff0c;服务器是不会认识的&#xff0c;那么需要在不同的内容之间加入分隔符&#xff0c;
  
  
  一部分内容完了之后再加入一个结束分隔符&#xff0c;有点像Html。在Content-Type的例子中有一句话boundary&#61;unique-boundary-1&#xff0c;这里就告诉系统我的分隔符叫什么名字。那么在一个邮件中&#xff0c;可以有多个分隔符&#xff0c;其余的分隔符实际上是在你给出的第一个分隔符下扩展的。说了这么多&#xff0c;看看程序&#xff1a;
  
  
  WriteStream("Date: "&#43;DateTime.Now);//时间
  
  
  WriteStream("From: "&#43;this.fromname&#43;"<"&#43;this.from&#43;">");//发件人
  
  
  WriteStream("Subject: "&#43;this.subject);//主题
  
  
  WriteStream("To:"&#43;this.to);//收件人
  
  
  //邮件格式
  
  
  WriteStream("Content-Type: multipart/mixed; boundary&#61;\"unique-boundary-1\"");
  
  
  WriteStream("Reply-To:"&#43;this.from);//回复地址
  
  
  WriteStream("X-Priority:"&#43;priority);//优先级
  
  
  WriteStream("MIME-Version:1.0");//MIME版本
  
  
  //数据ID,随意
  
  
  WriteStream("Message-Id: "&#43;DateTime.Now.ToFileTime()&#43;"&#64;security.com");
  
  
  WriteStream("Content-Transfer-Encoding:"&#43;this.encode);//内容编码
  
  
  WriteStream("X-Mailer:DS Mail Sender V1.0");//邮件发送者
  
  
  WriteStream("");
  
  
  看看这段头信息&#xff0c;里面的变量是事先定义好的&#xff0c;在头信息结束的时候&#xff0c;在写入一段空信息&#xff0c;这样Smtp服务器才会认为你已经写完了。
  
  
  WriteStream(AuthStream("This is a multi-part message in MIME format."));
  
  
  WriteStream("");
  
  
  这里只是一端描述性内容。
  
  
  //从此处开始进行分隔输入
  
  
  WriteStream("--unique-boundary-1");
  
  
  //在此处定义第二个分隔符
  
  
  WriteStream("Content-Type: multipart/alternative;Boundary&#61;\"unique-boundary-2\"");
  
  
  WriteStream("");
  
  
  //文本信息
  
  
  WriteStream("--unique-boundary-2");
  
  
  WriteStream("Content-Type: text/plain;charset&#61;"&#43;this.charset);
  
  
  WriteStream("Content-Transfer-Encoding:"&#43;this.encode);
  
  
  WriteStream("");
  
  
  WriteStream(body);
  
  
  WriteStream("");//一个部分写完之后就写如空信息&#xff0c;分段
  
  
  //html信息
  
  
  WriteStream("--unique-boundary-2");
  
  
  WriteStream("Content-Type: text/html;charset&#61;"&#43;this.charset);
  
  
  WriteStream("Content-Transfer-Encoding:"&#43;this.encode);
  
  
  WriteStream("");
  
  
  WriteStream(htmlbody);
  
  
  WriteStream("");
  
  
  WriteStream("--unique-boundary-2--");//分隔符的结束符号&#xff0c;尾巴后面多了--
  
  
  WriteStream("");
  
  
  //增加附件
  
  
  Attachment();//这个方法是我们在上面讲过的&#xff0c;实际上他放在这
  
  
  WriteStream("");
  
  
  WriteStream("--unique-boundary-1--")
  
  
  if (!OperaStream(".","250"))//最后写完了&#xff0c;输入"."
  
  
  {
  
  
  this.Close(); //关闭连接
  
  
  }
  
  
  这就是一封邮件的核心部分&#xff0c;上面的变量都是已定义好的全局变量&#xff0c;由用户传递给对象。整个邮件组件的主要内容到此告一段落。手指都敲酸了&#xff0c;由于本人水平有限&#xff0c;可能有些地方不太让人满意&#xff0c;在此表示歉意。在研究邮件发送之前&#xff0c;在网上四处搜索资料&#xff0c;却没有收获&#xff0c;似乎大家都愿意把经验烂在肚子里&#xff0c;由于我肠胃不够强壮&#xff0c;所以希望能够和大家共同分享这顿美餐。最后我们看看如何应用。
  
  
  在aspx文件或者其他cs文件中引用&#xff1a;
  
  
  MailSend Ms&#61;new MailSend();//构造对象
  
  
  Ms.SMTPServer&#61;"smtp.sohu.com";//传递参数
  
  
  ……
  
  
  Ms.send();//发送邮件
  
  
  在此篇文章中我并没有给出完整的代码&#xff0c;而只是给出了代码片段&#xff0c;但是这已经足够整理出整个程序了。这样做的目的是不希望大家看见了就直接拷贝过去使用&#xff0c;希望能够看清楚了&#xff0c;了解了其中的内容再去用&#xff0c;这样对于自己水平的提高才是有帮助的。邮件发送一直是一个比较困扰大家的问题&#xff0c;特别是加上认证程序后&#xff0c;速度又慢&#xff0c;所以我想现在很多邮件群发软件都支持免SMTP邮件发送&#xff0c;等什么时候有空了&#xff0c;也许会做一个免SMTP的邮件发送组件拿出来和大家分享。

转:https://www.cnblogs.com/dwjaissk/archive/2006/07/20/455481.html



推荐阅读
  • 本文介绍了Java后台Jsonp处理方法及其应用场景。首先解释了Jsonp是一个非官方的协议,它允许在服务器端通过Script tags返回至客户端,并通过javascript callback的形式实现跨域访问。然后介绍了JSON系统开发方法,它是一种面向数据结构的分析和设计方法,以活动为中心,将一连串的活动顺序组合成一个完整的工作进程。接着给出了一个客户端示例代码,使用了jQuery的ajax方法请求一个Jsonp数据。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文讨论了在ASP中创建RazorFunctions.cshtml文件时出现的问题,即ASP.global_asax不存在于命名空间ASP中。文章提供了解决该问题的代码示例,并详细解释了代码中涉及的关键概念,如HttpContext、Request和RouteData等。通过阅读本文,读者可以了解如何解决该问题并理解相关的ASP概念。 ... [详细]
  • c# java socketn 字节流_C#Socket编程详解(一)TCP与UDP简介
    一、TCP与UDP(转载)1、TCP1.1定义TCP(TransmissionControlProtocol)传输控制协议。是一种可靠的、面向连接的协议(eg:打电话)、传输效率低 ... [详细]
  • 2016年8月29日当初想的太简单~~~哎写在前面从3月份开始各大互联网类、游戏类、软件类等公司开始招暑期实习,9月份正式招聘,面临众多的工作选择和技术方向,我们不免有些眼花缭乱啊 ... [详细]
  • 软测管理工具实践04
    一.今日任务——安装完成QC9.0进过几天的安装,终于把QC9.0成功的安装在了自己win7系统的电脑上。其中遇到的困难很多,首先是QC的版本问题&#x ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • C#多线程解决界面卡死问题的完美解决方案
    当界面需要在程序运行中不断更新数据时,使用多线程可以解决界面卡死的问题。一个主线程创建界面,使用一个子线程执行程序并更新主界面,可以避免卡死现象。本文分享了一个例子,供大家参考。 ... [详细]
  • 本文介绍了在实现了System.Collections.Generic.IDictionary接口的泛型字典类中如何使用foreach循环来枚举字典中的键值对。同时还讨论了非泛型字典类和泛型字典类在foreach循环中使用的不同类型,以及使用KeyValuePair类型在foreach循环中枚举泛型字典类的优势。阅读本文可以帮助您更好地理解泛型字典类的使用和性能优化。 ... [详细]
  • 三小时掌握计算机网络基础(通俗易懂)
    目录1.网络层次划分2.OSI七层网络模型3.IP地址4.子网掩码及网络划分5.ARPRARP协议6.路由选择协议7.TCPIP协议8.UDP协议 9.DNS协议 ... [详细]
  • 适合小型网络环境的免费网络管理软件Intermapper
    InterMapper网络管理软件可支持监测5台以内的网络设备,特别适合安装使用在小型网络环境,可以实时了解网络运行状态和网络拓扑,支持多 ... [详细]
author-avatar
元顿20130208
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有