天天看點

使用Socket發送郵件

之前寫過一篇《使用PHP發送郵件》,方法是利用nette/mail元件發送郵件。

以下内容整理自《PHP核心技術與最佳實踐》。

PHP有一個自帶的mail()函數,但是要想使用SMTP協定發送郵件,需要安裝SMTP伺服器。如果不想安裝,可以使用Socket發送郵件。SMTP協定建立在TCP協定之上,是以原則上按照SMTP協定的規範,使用Socket跟SMTP伺服器進行互動。

SMTP連接配接與發送過程如下:

1)建立TCP連接配接。

2)用戶端發送HELO指令以辨別發件人自己的身份,用戶端發送MAIL指令。伺服器以OK作為響應,表明準備接收。

3)使用AUTH指令登陸SMTP伺服器,輸入使用者名和密碼(注意,使用者名和密碼都需要base64加密)。

4)用戶端發送RCPT指令,辨別該電子郵件的計劃接收人,可以有多個RCPT行。伺服器以OK作為響應,表示願意為收件人發送郵件。

5)協商結束後,使用DATA指令發送。

6)以”.”号表示結束,輸入内容一起發送出去,結束此次發送,用QUIT指令退出。

例如,使用Telnet建立一個SMTP會話,其中S代表伺服器,C代表用戶端,代碼如下:

C: open smtp.qq.com 
S:  esmtp4.qq.com Esmtp QQ Mail Server
C: HELO smtp qq.com
S:  esmtp4.qq.com
C: AUTH login
S:  VXNlcm5hbWU6
C: 這裡輸入使用base64加密過的使用者名
S:  UGFzc3dvcmQ6
C: 這裡輸入使用base64加密過的密碼
S: Authentication successful
C: MAIL FROM:<[email protected].com>
S:  sender <[email protected].com> OK
C: RCPT TO:<[email protected]>
S:  recipient <[email protected]> OK
C: DATA
S:  Enter mail,end with "." on a line by itself
C: This is example from smtp protocol
C:.
S:  message sent
C: QUIT
S:  goodbye
           

本來想用qq郵箱發郵件,但是qq郵箱開啟SMTP後頁面老是出錯,使用163郵箱可以正常發送郵件,郵箱需開啟POP3/SMTP服務。

代碼:

smtp_mail.php

<?php

class smtp_mail{
    private $host;
    private $port=;
    private $user;
    private $pwd;
    private $debug=false;   //是否開啟調試模式 預設不開啟
    private $sock;          //儲存與SMTP伺服器連接配接的句柄
    private $mail_format=; //郵件格式 0為普通文本 1為HTML郵件

    public function smtp_mail($host,$port,$user,$pwd,$mail_format=,$debug=false){
        $this->host=$host;
        $this->port=$port;
        $this->user=$user;
        $this->pwd=$pwd;
        $this->mail_format=$mail_format;
        $this->debug=$debug;
        //連接配接SMTP伺服器
        /**
         * fsockopen() 初始化一個套接字連接配接到指定主機
         * 最後一個參數為timeout,連接配接時限
         */
        $this->sock=fsockopen($this->host,$this->port,$errno,$errstr,);
        if (!$this->sock){//連接配接失敗
            exit("Error number: $errno, Error message: $errstr\n");
        }
        //取得伺服器資訊
        $response=fgets($this->sock);
        //若包含220,表示已經成功連接配接到伺服器
        if (strstr($response,"220")===false){//首次出現位址|false
            exit("Server error: $response\n");
        }
    }

    //将指令發送到伺服器,然後取得伺服器回報資訊,判斷指令是否執行成功
    private function do_command($cmd,$return_code){
        fwrite($this->sock,$cmd);
        $response=fgets($this->sock);
        if (strstr($response,"$return_code")===false){
            $this->show_debug($response);
            return false;
        }
        return true;
    }

    //發送郵件
    public function send_mail($from,$to,$subject,$content){
        //判斷收發件郵箱位址是否合法
        if (!$this->is_email($from) or !$this->is_email($to)){
            $this->show_debug('Please enter valid from/to email.');
            return false;
        }
        //判斷主題内容是否為空
        if (empty($subject) or empty($content)){
            $this->show_debug('Please enter subject/content.');
            return false;
        }
        //整合郵件資訊,發送郵件主體時要以\r\n.\r\n作為結尾
        $detail="From:".$from."\r\n";
        $detail.="To:".$to."\r\n";
        $detail.="Subject:".$subject."\r\n";

        if ($this->mail_format==){
            $detail.="Content-Type: text/html;\r\n";
        }else{
            $detail.="Content-Type: text/plain;\r\n";
        }

        $detail.="charset=utf-8\r\n\r\n";
        $detail.=$content;

        //此處應該有判斷指令是否執行成功
        $this->do_command("HELO smtp.qq.com\r\n",);
        $this->do_command("AUTH LOGIN\r\n",);
        $this->do_command("$this->user\r\n",);
        $this->do_command("$this->pwd\r\n",);
        $this->do_command("MAIL FROM:<".$from.">\r\n",);
        $this->do_command("RCPT TO:<".$to.">\r\n",);
        $this->do_command("DATA\r\n",);
        $this->do_command($detail."\r\n.\r\n",);
        $this->do_command("QUIT\r\n",);
        return true;
    }

    //判斷是否為合法郵箱
    private function is_email($emial){
        if(filter_var($emial,FILTER_VALIDATE_EMAIL)){
            return true;
        }else{
            return false;
        }
    }

    //顯示調試資訊
    private function show_debug($message){
        if ($this->debug){
            echo "<p>Debug: $message</p><br/>";
        }
    }

}
           

index.php

<?php
include_once "smtp_mail.php";
$host="smtp.163.com";
$port=;
$user="你的賬戶名@163.com";
$pwd="授權碼";
$from="你的賬戶名@163.com";
$to="目标郵箱";
$subject="Test Smtp Mail";
$content="This is example email for you.";
$mail=new smtp_mail($host,$port,base64_encode($user),base64_encode($pwd),,true);
$mail->send_mail($from,$to,$subject,$content);
           

繼續閱讀