热门标签 | 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



推荐阅读
  • D17:C#设计模式之十六观察者模式(Observer Pattern)【行为型】
    一、引言今天是2017年11月份的最后一天,也就是2017年11月30日,利用今天再写一个模式,争取下个月(也就是12月份& ... [详细]
  • 本文探讨了在AspNetForums平台中实施基于角色的权限控制系统的方法,旨在为不同级别的用户提供合适的访问权限,确保系统的安全性和可用性。 ... [详细]
  • 1<table>2<tr>3<th>ID<th>4 ... [详细]
  • 字符、字符串和文本的处理之Char类型
    .NetFramework中处理字符和字符串的主要有以下这么几个类:(1)、System.Char类一基础字符串处理类(2)、System.String类一处理不可变的字符串(一经 ... [详细]
  • 本文详细解析了Java中流的概念,特别是OutputStream和InputStream的区别,并通过实际案例介绍了如何实现Java对象的序列化。文章不仅解释了流的基本概念,还探讨了序列化的重要性和具体实现步骤。 ... [详细]
  • Redis: 高效的键值存储系统
    Redis是一款遵循BSD许可的开源高性能键值存储系统,它不仅支持多种数据类型的存储,还提供了数据持久化和复制等功能,显著区别于其他键值缓存解决方案。 ... [详细]
  • 本文详细介绍了Objective-C中的面向对象编程概念,重点探讨了类的定义、方法的实现、对象的创建与销毁等内容,旨在帮助开发者更好地理解和应用Objective-C的面向对象特性。 ... [详细]
  • 本文介绍了一个基本的同步Socket程序,演示了如何实现客户端与服务器之间的简单消息传递。此外,文章还概述了Socket的基本工作流程,并计划在未来探讨同步与异步Socket的区别。 ... [详细]
  • java datarow_DataSet  DataTable DataRow 深入浅出
    本篇文章适合有一定的基础的人去查看,最好学习过一定net编程基础在来查看此文章。1.概念DataSet是ADO.NET的中心概念。可以把DataSet当成内存中的数据 ... [详细]
  • 本文介绍了一种在 Android 开发中动态修改 strings.xml 文件中字符串值的有效方法。通过使用占位符,开发者可以在运行时根据需要填充具体的值,从而提高应用的灵活性和可维护性。 ... [详细]
  • 如何寻找程序员的兼职机会
    随着远程工作的兴起,越来越多的程序员开始寻找灵活的兼职工作机会。本文将介绍几个适合程序员、设计师、翻译等专业人士的在线平台,帮助他们找到合适的兼职项目。 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • Java EE 平台集成了多种服务、API 和协议,旨在支持基于 Web 的多层应用程序开发。本文将详细介绍 Java EE 中的 13 种关键技术规范,帮助开发者更好地理解和应用这些技术。 ... [详细]
  • Keepalived 提供了多种强大且灵活的后端健康检查机制,包括 HTTP_GET、SSL_GET、TCP_CHECK、SMTP_CHECK 和 MISC_CHECK 等多种检测方法。这些健康检查功能确保了高可用性环境中的服务稳定性和可靠性。通过合理配置这些检查方式,可以有效监测后端服务器的状态,及时发现并处理故障,从而提高系统的整体性能和可用性。 ... [详细]
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社区 版权所有