socket編程之使用socket寄送電子郵件(PHP)

來源:互聯網
上載者:User

我們知道,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<br /> class smtp {<br />var $smtp_port;//郵件伺服器的連接埠,郵件伺服器的為25<br />var $host_name;//用戶端主機名稱<br />var $relay_host;//郵件伺服器地址<br />var $user;//使用者名稱<br />var $pass;//密碼<br />var $lastmessage;//伺服器返回的資訊<br />private $socket;//socket控制代碼,調用fsockopen後返回的,具體用法參閱PHP文檔<br /> //建構函式,初始化必要資訊<br />function __construct($relay_host="",$smtp_port=25,$auth=false,$user,$pass) {<br />$this->smtp_port=$smtp_port;<br />$this->replay_host=$relay_host;<br />$this->auth=$auth;<br />$this->user=$user;<br />$this->pass=$pass;<br />$this->host_name="127.0.0.1";<br />}<br /> //執行指令的函數,相關函數用法請參閱PHP文檔<br />function smtp_putcmd($cmd) {<br />fputs($this->socket,$cmd."/r/n");<br /> $this->lastmessage=str_replace("/r/n", "", fgets($this->socket, 512));<br />if((preg_match("/^[23]/",$this->lastmessage))<=0) {//如果郵件伺服器返回的狀態代碼不是2或者3開頭,則表明出現錯誤,具體狀態代碼意義請參閱上文<br />Return false;<br />}<br />else {<br />Return true;<br />}<br />}<br /> //發送郵件所用的函數,the most important<br />//$to表示收件者地址,$from表示寄件者地址,$subject郵件主題,$body表示郵件主體<br />function sendmail($to,$from,$subject="",$body="") {<br />$this->socket=fsockopen($this->replay_host,$this->smtp_port);//開啟一個socket<br />stream_set_blocking($this->socket,1);<br />$this->lastmessage=fgets($this->socket,512);<br />if((preg_match("/^220/",$this->lastmessage))<=0) {<br />Return false;<br />}<br />else {<br />//這裡用戶端開始向郵件伺服器發送上文中討論過的命令<br />if(!$this->smtp_putcmd("HELO ".$this->host_name)) {<br />die('ERROR:sending HELO command/n');<br />}<br />if($this->auth) {<br />if(!$this->smtp_putcmd("AUTH LOGIN ".base64_encode($this->user))) {<br />die('ERROR:sending HELO command/n');<br />}<br />if(!$this->smtp_putcmd(base64_encode($this->pass))) {<br />echo("falil");<br />die('ERROR:sending HELO command/n');<br />}<br />}<br />if(!$this->smtp_putcmd("MAIL FROM:<".$from.">")) {<br />die("ERROR:sending MAIL FROM command");<br />}<br />if(!$this->smtp_putcmd("RCPT TO:<".$to.">")) {<br />die("ERROR:sending RCPT TO command");<br />}<br />if(!$this->smtp_putcmd("DATA")) {<br />die("ERROR:sending DATA command");<br />}<br />$head="To: ".$to."/r/n";<br />$head.="From: $from<".$from.">/r/n";<br />$head.="Subject: ".$subject."/r/n";<br />//$body = preg_replace("/(^|(/r/n))(/.)/", "//1.//3", $body);<br />$body.="/r/n./r/n";<br />fputs($this->socket,$head."/r/n".$body);<br />if(!$this->smtp_putcmd("QUIT")) {<br />die("Error:sending QUIT command");<br />}<br />//關閉socket串連<br />fclose($this->socket);<br />}<br />}<br /> }<br />?> 

下面,我們就可以發送郵件了:

<?php<br /> include('send_mail.php');<br /> $sm=new smtp("smtp.163.com",25,true,"這裡是您的使用者名稱","這裡是您的密碼");<br /> $sm->sendmail("這裡填寫您要發送的郵箱","這裡是您的郵箱","郵件主題","郵件主體");<br />?> 

可以看到,實質上使用socket發送郵件是很簡單的,其中最關鍵的地方是我們要理解郵件發送的原理。

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.