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



推荐阅读
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 在C#编程中,数值结果的格式化展示是提高代码可读性和用户体验的重要手段。本文探讨了多种格式化方法和技巧,如使用格式说明符、自定义格式字符串等,以实现对数值结果的精确控制。通过实例演示,展示了如何灵活运用这些技术来满足不同的展示需求。 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • 利用爬虫技术抓取数据,结合Fiddler与Postman在Chrome中的应用优化提交流程
    本文探讨了如何利用爬虫技术抓取目标网站的数据,并结合Fiddler和Postman工具在Chrome浏览器中的应用,优化数据提交流程。通过详细的抓包分析和模拟提交,有效提升了数据抓取的效率和准确性。此外,文章还介绍了如何使用这些工具进行调试和优化,为开发者提供了实用的操作指南。 ... [详细]
  • 如何精通编程语言:全面指南与实用技巧
    如何精通编程语言:全面指南与实用技巧 ... [详细]
  • 本文探讨了如何利用 jQuery 的 JSONP 技术实现跨域调用外部 Web 服务。通过详细解析 JSONP 的工作原理及其在 jQuery 中的应用,本文提供了实用的代码示例和最佳实践,帮助开发者解决跨域请求中的常见问题。 ... [详细]
  • C# .NET 4.1 版本大型信息化系统集成平台中的主从表事务处理标准示例
    在C# .NET 4.1版本的大型信息化系统集成平台中,本文详细介绍了主从表事务处理的标准示例。通过确保所有操作要么全部成功,要么全部失败,实现主表和关联子表的同步插入。主表插入时会返回当前生成的主键,该主键随后用于子表插入时的关联。以下是一个示例代码片段,展示了如何在一个数据库事务中同时添加角色和相关用户。 ... [详细]
  • 在 LeetCode 的“有效回文串 II”问题中,给定一个非空字符串 `s`,允许删除最多一个字符。本篇深入解析了如何判断删除一个字符后,字符串是否能成为回文串,并提出了高效的优化算法。通过详细的分析和代码实现,本文提供了多种解决方案,帮助读者更好地理解和应用这一算法。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 本文详细解析了Java类加载系统的父子委托机制。在Java程序中,.java源代码文件编译后会生成对应的.class字节码文件,这些字节码文件需要通过类加载器(ClassLoader)进行加载。ClassLoader采用双亲委派模型,确保类的加载过程既高效又安全,避免了类的重复加载和潜在的安全风险。该机制在Java虚拟机中扮演着至关重要的角色,确保了类加载的一致性和可靠性。 ... [详细]
  • 在C#中,一旦对象被实例化后,直接重新调用构造函数是不可行的。与C++不同,C#不支持在对象实例化后强制调用构造函数。为了实现类似的功能,可以通过定义一个重置方法或使用工厂模式来重新初始化对象的状态。例如,可以创建一个 `Reset` 方法,在该方法中重新设置对象的属性和状态,从而达到类似于重新调用构造函数的效果。这样不仅保持了代码的清晰性和可维护性,还避免了潜在的副作用。 ... [详细]
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • 在本节课程中,我们将深入探讨 JSP 编程中的实际案例,通过具体代码示例 `code316.java` 来解析数据库连接的实现。该示例展示了如何使用 Java 的 JDBC API 进行数据库操作,包括加载数据库驱动、建立连接等关键步骤。通过本课程的学习,读者将能够更好地理解和应用 JSP 中的数据库连接技术。 ... [详细]
  • 作为软件工程专业的学生,我深知课堂上教师讲解速度之快,很多时候需要课后自行消化和巩固。因此,撰写这篇Java Web开发入门教程,旨在帮助初学者更好地理解和掌握基础知识。通过详细记录学习过程,希望能为更多像我一样在基础方面还有待提升的学员提供有益的参考。 ... [详细]
  • 在 CentOS 6.5 系统上部署 VNC 服务器的详细步骤与配置指南
    在 CentOS 6.5 系统上部署 VNC 服务器时,首先需要确认 VNC 服务是否已安装。通常情况下,VNC 服务默认未安装。可以通过运行特定的查询命令来检查其安装状态。如果查询结果为空,则表明 VNC 服务尚未安装,需进行手动安装。此外,建议在安装前确保系统的软件包管理器已更新至最新版本,以避免兼容性问题。 ... [详细]
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社区 版权所有