socket编程之使用socket发送电子邮件(PHP)

    技术2022-06-12  45

    我们知道,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 class smtp { var $smtp_port;//邮件服务器的端口,邮件服务器的为25 var $host_name;//客户端主机名 var $relay_host;//邮件服务器地址 var $user;//用户名 var $pass;//密码 var $lastmessage;//服务器返回的信息 private $socket;//socket句柄,调用fsockopen后返回的,具体用法参阅PHP文档 //构造函数,初始化必要信息 function __construct($relay_host="",$smtp_port=25,$auth=false,$user,$pass) { $this->smtp_port=$smtp_port; $this->replay_host=$relay_host; $this->auth=$auth; $this->user=$user; $this->pass=$pass; $this->host_name="127.0.0.1"; } //执行指令的函数,相关函数用法请参阅PHP文档 function smtp_putcmd($cmd) { fputs($this->socket,$cmd."/r/n"); $this->lastmessage=str_replace("/r/n", "", fgets($this->socket, 512)); if((preg_match("/^[23]/",$this->lastmessage))<=0) {//如果邮件服务器返回的状态码不是2或者3开头,则表明出现错误,具体状态码意义请参阅上文 Return false; } else { Return true; } } //发送邮件所用的函数,the most important //$to表示收件人地址,$from表示发件人地址,$subject邮件主题,$body表示邮件主体 function sendmail($to,$from,$subject="",$body="") { $this->socket=fsockopen($this->replay_host,$this->smtp_port);//打开一个socket stream_set_blocking($this->socket,1); $this->lastmessage=fgets($this->socket,512); if((preg_match("/^220/",$this->lastmessage))<=0) { Return false; } else { //这里客户端开始向邮件服务器发送上文中讨论过的命令 if(!$this->smtp_putcmd("HELO ".$this->host_name)) { die('ERROR:sending HELO command/n'); } if($this->auth) { if(!$this->smtp_putcmd("AUTH LOGIN ".base64_encode($this->user))) { die('ERROR:sending HELO command/n'); } if(!$this->smtp_putcmd(base64_encode($this->pass))) { echo("falil"); die('ERROR:sending HELO command/n'); } } if(!$this->smtp_putcmd("MAIL FROM:<".$from.">")) { die("ERROR:sending MAIL FROM command"); } if(!$this->smtp_putcmd("RCPT TO:<".$to.">")) { die("ERROR:sending RCPT TO command"); } if(!$this->smtp_putcmd("DATA")) { die("ERROR:sending DATA command"); } $head="To: ".$to."/r/n"; $head.="From: $from<".$from.">/r/n"; $head.="Subject: ".$subject."/r/n"; //$body = preg_replace("/(^|(/r/n))(/.)/", "//1.//3", $body); $body.="/r/n./r/n"; fputs($this->socket,$head."/r/n".$body); if(!$this->smtp_putcmd("QUIT")) { die("Error:sending QUIT command"); } //关闭socket连接 fclose($this->socket); } } } ?> 

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

    <?php include('send_mail.php'); $sm=new smtp("smtp.163.com",25,true,"这里是您的用户名","这里是您的密码"); $sm->sendmail("这里填写您要发送的邮箱","这里是您的邮箱","邮件主题","邮件主体"); ?> 

    可以看到,实质上使用socket发送邮件是很简单的,其中最关键的地方是我们要理解邮件发送的原理。

     

     

     

     


    最新回复(0)