PHP发送邮件

我们知道,PHP发送邮件有两种方式,一个是mail()函数,另一个就是socket发送邮件。对于第一种方式,我不多做介绍,因为它的用法相对简单,只是说可能需要配置的东西比较多。详细可参加PHP文档。这里,我主要谈谈第二种方式。

讲到第二种方式,我首先要谈谈发送邮件的原理。

发送邮件是基于客户/服务器模式的,也就是说,客户端首先需要向服务器端发送连接请求,当双方连接后,再进行数据的传输,与此同时,我们又不能随便的进行传输,而是要遵守一定的规则,这里所说的规则我们称之为协议。

在邮件系统中,主要涉及三种协议,SMTP,POP3,MIME,我们这里谈前两种;

SMTP协议:简单文件栓出协议,发送邮件使用的协议;

POP3:接收邮件协议。

上面的实体图正是发送邮件的原理示意图。通常我们发送邮件给另一个好友,并非直接把邮件发送到对方的客户机上。它实际上是先发送到了发送方的邮件服务器,然后发送方的邮件服务器将邮件发送到接收方的邮件服务器,收件人再从接收方的邮件服务器中获得所需邮件。举个例子来说,我们有一个163邮箱,邮件地址是hl@163.com;现在我要向145642@qq.com的邮箱中发一封邮件。实际的发送流程为,我们在在客户端使用客户端代理(如outlook)编辑好邮件,然后点击发送,这时邮件便会发送到163的邮件服务器,163邮件服务器在合适的时间会将邮件发送到QQ的邮件服务器,QQ邮件服务器接收到邮件后,根据收件人地址,会通知收件人,这时,收件人便可以从QQ邮件服务器获得邮件。大致的原理就是这样,当然,内部的工作原理还是很复杂的。

再来谈谈发送邮件的过程中所涉及的协议。我们从客户代理将邮件发送到发送放邮件服务器时,使用的是SMTP协议,发送方邮件服务器讲邮件发送到接收方邮件服务器时,使用的也是SMTP协议。当接收方代理从接收方邮件服务器获得邮件时,使用的是POP3协议,总之一句话,发送使用SMTP协议,接收使用POP3协议。

而我们这里要讨论的socket发送邮件,实质上就是自己编写代码取代发送方邮件代理的功能,自己将邮件发送到发送方邮件服务器中,讲到这里,大家有点明白了吧。

下面,讨论具体实现:

由于我们只是关心如何发送邮件,而不需要关心接收方如何获得邮件,因此,我们在编写的代码就是如何实现SMTP。

SMTP分为命令头和信息体两部分。命令头主要完成客户端和服务器的连接,验证等。整个过程由多条命令组成。每个命令发送到服务器后,由服务器给出相应信息,一般为3位数字的响应码和响应文本。每个命令及响应的最后都有一个回车符,这样使用fputs和fgets就可以进行响应的处理了。

客户端向邮件服务器发出的一些常用的SMTP指令为:

HELO hostname 与服务器打招呼并且告知服务器客户端使用的机器名,这里可以随便填写;

AUTH LOGIN:user,pass 邮箱帐号,密码

MAIL FROM:sender 告诉邮件服务器发信人的地址;

RCPT TO:receiver 告诉邮件服务器收信人的地址;

DATA 开始发送邮件内容,并且最后只能含有"."为结尾字符的行结束。

QUIT 传输结束,退出连接;

客户端每发一条命令,服务器便会返回相应的相应信息,信息格式为(响应码+空格+解释)

一些常见的相应码为:

220 服务就绪(socket返回)

221 正在处理

250 请求邮件动作成功(HELO MAIL FROM,RCPT TO,QUIT指令成功后会返回此状态码)

354 开始发送数据,以“.”结束(DATA 指令执行成功后会返回此信息);

500 语法错误,命令不能识别

550 命令不能执行,邮箱无效

而我们使用socket发送邮件是指上就是通过客户端向邮件服务器发送以上的命令,从而实现SMTP协议来达到发送邮件的目的。实质上outbllook之类的客户端邮件代理发送邮件原理和我们要实现的代码是一样的,只是它们将这些操作都封装好,然后提供了一个友好的界面供我们操作。

下面是我实现的代码(有详细注释):网上有很多封装好了的比较完整的发送邮件类,我只是粗略实现了它的功能,还有很多没有实现,因此,这里只供参考:

[php]  view plain copy
  1. <?php  
  2.   class smtp {  
  3.     var $smtp_port;//邮件服务器的端口,邮件服务器的为25  
  4.     var $host_name;//客户端主机名  
  5.     var $relay_host;//邮件服务器地址  
  6.     var $user;//用户名  
  7.     var $pass;//密码  
  8.     var $lastmessage;//服务器返回的信息  
  9.     private $socket;//socket句柄,调用fsockopen后返回的,具体用法参阅PHP文档  
  10.     //构造函数,初始化必要信息  
  11.     function __construct($relay_host="",$smtp_port=25,$auth=false,$user,$pass) {  
  12.         $this->smtp_port=$smtp_port;  
  13.         $this->replay_host=$relay_host;  
  14.         $this->auth=$auth;  
  15.         $this->user=$user;  
  16.         $this->pass=$pass;  
  17.         $this->host_name="127.0.0.1";  
  18.     }  
  19.     //执行指令的函数,相关函数用法请参阅PHP文档  
  20.     function smtp_putcmd($cmd) {  
  21.         fputs($this->socket,$cmd."/r/n");  
  22.         $this->lastmessage=str_replace("/r/n"""fgets($this->socket, 512));  
  23.         if((preg_match("/^[23]/",$this->lastmessage))<=0) {//如果邮件服务器返回的状态码不是2或者3开头,则表明出现错误,具体状态码意义请参阅上文  
  24.             Return false;  
  25.         }  
  26.         else {  
  27.             Return true;  
  28.         }  
  29.     }  
  30.     //发送邮件所用的函数,the most important  
  31.     //$to表示收件人地址,$from表示发件人地址,$subject邮件主题,$body表示邮件主体  
  32.     function sendmail($to,$from,$subject="",$body="") {  
  33.         $this->socket=fsockopen($this->replay_host,$this->smtp_port);//打开一个socket  
  34.         stream_set_blocking($this->socket,1);  
  35.         $this->lastmessage=fgets($this->socket,512);  
  36.         if((preg_match("/^220/",$this->lastmessage))<=0) {  
  37.             Return false;  
  38.         }  
  39.         else {  
  40.             //这里客户端开始向邮件服务器发送上文中讨论过的命令  
  41.             if(!$this->smtp_putcmd("HELO ".$this->host_name)) {  
  42.                 die('ERROR:sending HELO command/n');  
  43.             }  
  44.             if($this->auth) {  
  45.                 if(!$this->smtp_putcmd("AUTH LOGIN ".base64_encode($this->user))) {  
  46.                     die('ERROR:sending HELO command/n');  
  47.                 }  
  48.                 if(!$this->smtp_putcmd(base64_encode($this->pass))) {  
  49.                     echo("falil");  
  50.                     die('ERROR:sending HELO command/n');  
  51.                 }  
  52.             }  
  53.             if(!$this->smtp_putcmd("MAIL FROM:<".$from.">")) {  
  54.                 die("ERROR:sending MAIL FROM command");  
  55.             }  
  56.             if(!$this->smtp_putcmd("RCPT TO:<".$to.">")) {  
  57.                 die("ERROR:sending RCPT TO command");  
  58.             }  
  59.             if(!$this->smtp_putcmd("DATA")) {  
  60.                 die("ERROR:sending DATA command");  
  61.             }  
  62.             $head="To: ".$to."/r/n";  
  63.             $head.="From: $from<".$from.">/r/n";  
  64.             $head.="Subject: ".$subject."/r/n";  
  65.             //$body = preg_replace("/(^|(/r/n))(/.)/", "//1.//3", $body);  
  66.             $body.="/r/n./r/n";  
  67.             fputs($this->socket,$head."/r/n".$body);  
  68.             if(!$this->smtp_putcmd("QUIT")) {  
  69.                 die("Error:sending QUIT command");  
  70.             }  
  71.             //关闭socket连接  
  72.             fclose($this->socket);  
  73.         }  
  74.     }  
  75.   }    
  76. ?>  

下面,我们就可以发送邮件了:

[php]  view plain copy
  1. <?php  
  2.   include('send_mail.php');  
  3.   $sm=new smtp("smtp.163.com",25,true,"这里是您的用户名","这里是您的密码");  
  4.   $sm->sendmail("这里填写您要发送的邮箱","这里是您的邮箱","邮件主题","邮件主体");  
  5. ?>  
  可以看到,实质上使用socket发送邮件是很简单的,其中最关键的地方是我们要理解邮件发送的原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值