首頁 > 後端開發 > php教程 > 用Socket發送電子郵件_PHP教程

用Socket發送電子郵件_PHP教程

WBOY
發布: 2016-07-21 16:09:06
原創
949 人瀏覽過


用Socket發送電子郵件 在筆者所申請的幾個PHP 主頁空間中,能夠提供mail功能的實在不多,總是調用完mail()函數之後就毫
無下文了。但是電子郵件在網路生活中的作用越來越大。想想網蟲上網不收郵件能叫真正的網蟲嗎?郵件
的作用我不想再說了,但是如果主頁空間不支援mail()發送那麼怎麼辦呢?我也想過透過socket來實現郵件
發送,但無奈對用php 進行socket編程不熟悉,再加上發送郵件要用到SMTP協議,又要讀不少的英文了,所
以一直也沒有去研究過。終於有一天我發現了一篇文章,關於用socket程式設計發送郵件。我如獲至寶般將其拷貝
貝下來,並將其改造成了一個php 可用的類,供大家使用。原來的文章只是一個簡單的例子,而且還有一
些錯誤,在我經過多次的實驗、改造終於將其改成了一個直接使用socket,向指定的郵箱發送郵件的類,如
果大家和前面關於發送MIME的文章結合起來,就可以實現在不支援mail()函數的網站上發送郵件了。因為發送
送郵件的過程需要時間,可能與mail()的處理機制還不完全一樣,所以速度要慢一些,但是可以解決需要發
送郵件功能的燃眉之急,同時你也可以學習用php 進行socket程式設計。以下就將這個類別的實作原理介紹給大家,
同時向大家講解一些關於SMTP的基本知識。

Socket程式介紹
向大家申明,本人不是一個TCP/IP程式專家,故在此只是講出了我的一點理解和體會。

使用fsockopen函數開啟一個Internet連接,函數語法格式:

int fsockopen(string hostname, int port, int [errno], string [errstr], int [timeout]);

參數的意思我想不用講了,這裡由於要使用SMTP協議,所以連接埠號碼為25。開啟連線成功後,會回傳一
個socket句柄,使用它就可以像使用檔案句柄一樣的。可使用的操作有fputs(),fgets(),feof(),fclose()
等。

很簡單介紹就到這裡吧。

SMTP的基礎
基於TCP/IP的因特網協定一般的命令格式都是透過請求/ 應答方式實現的,採用的都是文字訊息,所以
處理起來要容易一些。 SMTP是簡單郵件傳輸協定的簡稱,它可以實現客戶端向伺服器發送郵件的功能。所以
下面所講的命令是指客戶端向伺服器發出請求指令,而回應則是指伺服器回傳給客戶端的資訊。

SMTP分為命令頭和訊息體兩部分。命令頭主要完成客戶端與伺服器的連接,驗證等。整個過程由多條命
令組成。每個指令發到伺服器後,由伺服器給予回應訊息,一般為3 位數的回應碼和回應文字。不同的服
務器回傳的回應碼是遵守協定的,但是回應正文則不必。每個指令及回應的最後都有一個回車符,這樣讓
用fputs()和fgets()就可以進行指令與回應的處理了。 SMTP的命令及回應訊息都是單行的。訊息體則是郵件
的正文部分,最後的結束行應以單獨的"."作為結束行。

客戶端一些常用的SMTP指令為:

HELO hostname: 與伺服器打招呼並告知客戶端使用的機器名字,可以隨便填寫
MAIL FROM: sender_id : 告訴伺服器發送信人的地址
RCPT TO: receiver_id : 告訴伺服器收信人的地址
DATA : 下面開始傳輸信件內容,且最後要以只含有.的特殊行結束
RESET: 取消剛才的指令,從新開始
VERIFY userid: 校驗帳號是否存在(此指令為可選指令,伺服器可能不支援)
QUIT : 退出連接,結束
伺服器傳回的回應資訊為(格式為:回應碼空格解釋):

220 服務就緒(在socket連接成功時,會返回此資訊)
221 正在處理
250 請求郵件動作正確,完成(HELO,MAIL FROM,RCPT TO,QUIT指令執行成功會返回此訊息)
354 開始發送數據,結束以.(DATA指令執行成功會返回此訊息,客戶端應發送訊息)
500 語法錯誤,命令不能識別
550 命令不能執行,郵箱無效
552 中斷處理:用戶超出文件空間
下面給出一個簡單的命令頭(這是在打開socket之後做的),是我向stmp.263.net發郵件的測試結果:

HELO limodou
250 smtp.263.net
MAIL FROM: chatme@263.net
250 Ok
RCPT TO: chatme@263.net DATA
354 End data with .
To: chatme@263.net
From: chatme@263.net
Subject: test
From: chatme@263.net
test
.
QUIT
250 Ok: queued as C46411C5097E0

這就是一些SMTP的簡單知識。相關內容可參考RFC。

RFC 821定義了收/發電子郵件的相關指示。
RFC 822則制定了郵件內容的格式。
RFC 2045-2048制定了多媒體郵件內容的格式,
RFC 1113, 1422-1424則是討論如何增進電子郵件的保密性。

send_mail類別的實作
現在開始介紹我所寫的發送郵件類別。有了上面的預備知識了,以下就是實現了。

類別的成員變數

var $lastmessage; //記錄最後回傳的回應訊息
var $lastact; //最後的動作,字串形式
var $welcome ; //用在HELO後面,歡迎使用者
var $debug; //是否顯示偵錯資訊
var $smtp; //smtp伺服器
var $port; //smtp連接埠號碼
var $fp; //socket句柄

其中,$lastmessage和$lastact用於記錄最後一次回應資訊及執行的命令,當出錯時,使用者可以使用它
們。為了測試需要,我還定義了$debug變量,當其值為true時,會在運行過程中顯示一些執行信息,否則無
任何輸出。 $fp用於保存開啟後的socket句柄。

類別的構造


-------------------------------- ------------------------------------------------
function send_mail($smtp, $welcome="", $debug=false)
{
if(empty($smtp)) die("SMTP cannt be NULL!");
$this- >smtp=$smtp;
if(empty($welcome))
{
$this->welcome=gethostbyaddr("localhost");
}
else
$this ->welcome=$welcome;
$this->debug=$debug;
$this->lastmessage="";
$this->lastact="";
$this-> port="25";
}
------------------------------ ------- -------------------------------------------
這個建構子主要完成一些初始值的判定及設定。 $welcome用於HELO指令中,告訴伺服器使用者的名字。
HELO指令要求為機器名,但是不用也可以。如果使用者沒有給予$welcome,則自動尋找本地的機器名稱。

顯示偵錯資訊

----------------------------------- ---------------------------------------------
1 function show_debug($message, $inout)
2 {
3 if ($this->debug)
4 {
5 if($inout=="in") //回應訊息
6 {
7 $m='8 }
9 else
10 $m='>> ';
11 if(!ereg ("n$" , $message))
12 $message .= "
";
13 $message=nl2br($message);
14 echo "${m}$ {message}";
15 }
16 }
-------------------- -------- ------------------------------------------ -------- --
這個函數用來顯示偵錯資訊。可以在$inout中指定是上傳的指令還是傳回的回應,如果為上傳指令,則
使用"out";如果為傳回的回應則使用"in"。

第3行,判斷是否要輸出除錯資訊。
第5行,判斷是否為回應訊息,如果是,則在第7行將訊息的前面加上" ">> ; "來區別上傳指令。
第11-12行,判斷訊息字串最後是否為換行符,如不是則加上HTML換行標記。第13行將所以的換行符號轉換成HTML
的換行標記。
第14行,輸出整個訊息,同時將訊息顏色置為灰色以示區別。

執行一個指令


-------------------------------- ------------------------------------------------
1 function do_command($command, $code)
2 {
3 $this->lastact=$command;
4 $this->show_debug($this->lastact, "out ");
5 fputs ( $this->fp, $this->lastact );
6 $this->lastmessage = fgets ( $this->fp, 512 );
7 $this->show_debug( $this->lastmessage, "in");
8 if(!ereg("^$code", $this->lastmessage))
9 {
10 return false;
11 }
12 else
13 return true;
14 }
-------------------- ---------- ---------------------------------------- ----------
在編寫socket處理部分發現,一些命令的處理很相似,如HELO,MAIL FROM,RCPT TO,QUIT,DATA命令,
都要求根據是否顯示調試信息將相關內容顯示出來,同時對於返回的回應碼,如果是期望的,則應繼續處理,
如果不是期望的,則應中斷出理。所以為了清晰與簡化,專門對這些命令的處理寫了一個通用處理函數。
函數的參數中$code為期望的回應碼,如果回應碼與之相同則表示處理成功,否則出錯。

第3行,記錄最後執行指令。
第4行,將上傳指令顯示出來。
第5行,則使用fputs真正向伺服器傳換指令。
第6行,從伺服器接收回應訊息將放在最後回應訊息變數中。
第7行,將回應訊息顯示出來。
第8行,判斷回應訊息是否期待的,如果是則第13行回傳成功(true),否則在第10行回傳失敗(false)。

這樣,這個函數一方面完成指令及訊息的傳送顯示功能,別一方面對回傳的回應判斷是否成功。

郵件發送處理

下面是真正的秘密了,可要看仔細了。:)

------------------------------------------ -------------- -------------- ---------------------- -------------- --
1 個函數send( $to,$from ,$subject,$message)
2 {
3
4 / /連接伺服器
5 $this->lastact="連接”;
6
7 $this->show_debug("連接到 SMTP 伺服器:".$this->smtp, "out");
8 $this->fp = fsockopen ( $this->smtp, $this->port );
9 if ( $this->fp )
10 {
11
12 set_socket_blocking( $this->fp, true );
13 $this->lastmessage=fgets($this->fp,512);
14 $this->show_debug($this->lastmessage, "in");
15
16 if (!ereg ( "^220", $this->lastmessage ) )
17 {
18 return false;
19 }
20 else
21 {
22 $this->lastact="HELO " 。 $this->歡迎。 );
26 回傳 false;
27 }
28
29 $this->lastact="MAIL FROM: $from" 。 ($this->lastact, "250"))
31 {
32 fclose($this->fp);
33 回傳 false;
34 }
35
36 $this->lastact="RCPT TO: $to" 。 「n」;
37 if(!$this->do_commandmand" 。 ($this->lastact, "250"))
38 {
39 fclose($this->fp);
40 回傳 false;
41 }
42
43 // 傳送正文
44 $this->lastact="DATAn";
45 if(!$this->do_command($this->lastact, "354"))
46 {
47 fclose($this->fp);
48 回傳 false;
49 }
50
51 //處理Subject頭
52 $head="Subject: $subjectn";
53 if(!empty($subject) && !ereg($head, $message))
54 {
55 $message = $head.$message;
56 }
57
58 //處理From頭
59 $head="From: $fromn";
60 if(!empty($from) && !ereg($head, $message))
61 {
62 $message = $head.$message;
63 }
64
65 //處理To頭
66 $head="To: $ton";
67 if(!empty($to) && !ereg($head, $message))
68 {
69 $message = $head.$message;
70 }
71
72 //加上結束字串
73 if(!ereg("n.n", $message))
74 $message .= "n.n";
75 $this->show_debug($message, "out");
76 fputs($this->fp, $message);
77
78 $this->lastact="QUITn";
79 if(!$this->do_command($this->lastact, "250"))
80 {
81 fclose($this->fp);
82 回傳 false;
83 }
84 }
85 回傳 true;
86 }
87 else
88 {
89 $ $this-bug>"失敗!
90 回傳 false;
91 }
92 }
---------------------------- -- -------- ---------------------------------------- -- -
有些意思很清楚

這個函數共有四個參數,分別是$to表示收信人,$from表示發信人,$subject表求郵件主題和$message
表示郵件體。
第16行,判斷回應碼是否為220,如果是,則繼續處理,否則回傳錯誤。 34行,處理MAIL FROM指令,期望回應碼為250。為250。如果沒有,則加上主題部分。 66-70行,如果$to不為空,則查找郵件體中是否有收信人部分,如果沒有,則加上收信人部分。結束行,是否沒有則加上郵件體的結束行(以"."作為單獨的一行結的特殊行)。否與伺服器的連接,期望回應碼為250。為整個send_mail類別的實現,應該不難的。

郵件發送實例
先給一個最簡單的實例:
-------------------------- -------------------------------------------------- ----

1 include "sendmail.class.php3";
2 $email="Hello, this is a test letter!";
3 $sendmail=new send_mail( "smtp.263.net", "limodou", true); //顯示顯示訊息
4 if($sendmail->send("chatme@263.net", "chatme@263.net", " test", $email))
5 {
6 echo "發送成功!
";
11 }
?>
-------------------------------- ------------------------------------------------
第1行,裝入send_mail類別。
第3行,建立一個類別的實例,且設定顯示調示訊息,如果不想顯示,可以
$sendmail=new send_mail("smtp.263.net");。
第4行,發送郵件。


很簡單,不是嗎?下面再給合以前的發送MIME郵件的例子,給一個發送HTML附件的例子。

-------------------------------------------- ------------------------------------

include " MIME.class.php3";
//註,在發送MIME郵件一文中,這個類別檔案名為MIME.class,在此處我改成這樣的

$to = 'chatme@ 263.net'; //改為收信人的郵箱
$str = "Newsletter for ".date('M Y', time());

//訊息被我改少了
$html_data = '

'. $str. '

Hello! This is a test!

';

//產生MIME類別實例
$mime = new MIME_mail("chatme@263.net", $to, $str);

//新增HTML附件
$mime->attach($html_data, "", HTML, BASE64);

//註解掉,採用我的傳送郵件處理
//$mime->send_mail();

//產生郵件
$mime->gen_email();

//顯示郵件資訊
//echo $mime->email."
";

//包含sendmail檔案
include "sendmail.class.php3";

//建立實例
$sendmail=new send_mail("smtp.263.net", "limodou", true);

//發送郵件
$sendmail->send("chatme@263.net", " chatme@263.net", $str, $mime->email);

?>
---------------------- -------------------------------------------------- --------
註解寫的很清楚,就不再做更多的解釋了。如果實際應用中,請將send_mail建構函式中的debug設為
false或不寫即可。



http://www.bkjia.com/PHPjc/314658.html

www.bkjia.com

http: //www.bkjia.com/PHPjc/314658.htmlTechArticle用Socket發送電子郵件在作者所申請的幾個PHP 主頁空間中,能夠提供mail功能的實在不多,總是調用完mail()函數之後就毫無下文了。但電子...
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板