1、SMTP是由源地址到目的地址傳送郵件的一組規則,用來控制信件的中轉方式。
2、SMTP服務器是遵循SMTP協議的發送郵件服務器,用來發送或者中轉發出的郵件,客戶端通過SMTP命令與SMTP服務器進行交互。
3、連接和發送郵件步驟如下:
(1)建立TCP連接;
(2)客戶端發送HELO命令以標識發件人的身份,服務器以OK作為響應,表明准備接收;
(3)使用AUTH命令登錄SMTP服務器,輸入用戶名和密碼(用戶名和密碼要用base64進行加密);
(4)客戶端發送MAIL命令輸入發件人郵箱地址,服務器以OK作為響應;
(5)客戶端發送RCPT命令,標識該電子郵件的計划接收人,服務器以OK作為響應;
(6)協商結束后,使用DATA命令發送;
(7)以"."號表示結束,輸入內容一起發送出去,
(8)結束此次發送,用QUIT命令退出。
下面給出一個使用telnet創建一個smtp會話的例子
注意:上述命令不一定一次性成功,服務器可能會返回錯誤響應,如上圖,我輸入了很多次才成功的
4、上面我們進行了SMTP連接和發送,接下來我們認識下SMTP協議的常用命令
DATA:開始信息寫作
EXPN:驗證給定的郵箱列表是否存在,擴充郵箱列表,常被禁用
HELO:向服務器標識用戶身份,返回郵件服務器身份
HELP:查詢服務器支持什么命令,返回命令中的信息
MAIL FROM:在主機上初始化一個郵件回話
NOOP:無操作,服務器響應OK
QUIT:終止郵件會話
RCPT TO:標識單個的郵件接收人,MAIL命令后面可以有多個RCPT TO
RSET:重置會話,當前傳輸被取消
SAML FROM:發送郵件到用戶終端和郵箱
SEND FROM:發送郵件到用戶終端
SOML FROM:發送郵件到用戶終端或郵箱
TURN:接收端和發送端交換角色
5、下面我們看一個用socket發送郵件的例子,看完這個例子,基本上能理解清楚SMTP是如何發郵件的
首先,我們先來認識一個函數
fsockopen($hostname, $port, [$errno], [$errstr], [$timeout]);
$hostname:要連接的服務器路徑
$port:要綁定的端口
$errno:保存連接發生錯誤時的錯誤代號
$errstr:保存錯誤信息
$timeout:設置連接的超時時間,單位為秒
先創建一個smtp.class.php類
1 <?php 2 3 class smtp_email 4 { 5 private $host; //保存要連接的smtp服務器 6 private $port; //要綁定的端口,默認為25 7 private $user; //要登錄SMTP服務器的用戶名 8 private $pass; //要登錄SMTP服務器的密碼 9 private $debug = false; //標識是都開啟調試模式,默認關閉 10 private $sock; //保存與SMTP服務器連接的句柄 11 private $mail_format = 0; //表示使用什么格式發送郵件,0位普通文本,1為HTML郵件 12 13 //初始化 14 public function __construct($host, $port, $user, $pass, $format = 1, $debug = 0) 15 { 16 $this->host = $host; 17 $this->port = $port; 18 $this->user = base64_encode($user); 19 $this->pass = base64_encode($pass); 20 $this->mail_format = $format; 21 $this->debug = $debug; 22 23 $this->sock = fsockopen($this->host, $this->port, &$errno, &$errstr, 10); //使用fsockopen()連接服務器 24 25 if (!$this->sock) { 26 exit("Error Number:$errno, Error Message:$errstr"); 27 } 28 29 $response = fgets($this->sock); //獲取服務器信息 30 if (strstr($response, "220") == false) { 31 exit("server error:$response\n"); 32 } 33 } 34 35 //根據用戶是否開啟調試模式顯示調試信息 36 private function show_debug($message) 37 { 38 if ($this->debug) { 39 echo "<p>Debug:$message</p>\n"; 40 } 41 } 42 43 //把命令發送到服務器中執行,然后取的服務器的反饋信息 44 private function do_command($cmd, $return_code) 45 { 46 fwrite($this->sock, $cmd); 47 48 $response = fgets($this->sock); 49 if (strstr($response, $return_code) == false) { 50 $this->show_debug($response); 51 return false; 52 } 53 54 return true; 55 } 56 57 //驗證郵箱地址是否合法 58 private function is_email($email) 59 { 60 $pattern = '/^[^_][\w]*@[\w.]+[\w]*[^_]$/'; 61 if (preg_match_all($pattern, $email, $matches)) { 62 return true; 63 } else { 64 return false; 65 } 66 } 67 68 //發送郵件 $from:發件人email $to:收件人email $subject:郵件主題 $body:郵件內容 69 public function send_email($from, $to, $subject, $body) 70 { 71 if (!$this->is_email($from) || !$this->is_email($to)) { 72 $this->show_debug("please enter vaild from/to email."); 73 return false; 74 } 75 76 if (empty($subject) || empty($body)) { 77 $this->show_debug("please enter subject/content."); 78 return false; 79 } 80 81 $detail = "From:{$from}\r\n"; 82 $detail .= "To:{$to}\r\n"; 83 $detail .= "Subject:{$subject}\r\n"; 84 85 if ($this->mail_format == 1) { 86 $detail .= "Content-Type:text/html;\r\n"; 87 } else { 88 $detail .= "Content-Type:text/plain;\r\n"; 89 } 90 91 $detail .="charset = gb2312\r\n\r\n" ; 92 $detail .= "$body"; 93 94 $this->do_command("HELO smtp.qq.com\r\n", 250); 95 $this->do_command("AUTH LOGIN\r\n", 334); 96 $this->do_command($this->user."\r\n", 334); 97 $this->do_command($this->pass."\r\n", 235); 98 $this->do_command("MAIL FROM:<".$from.">\r\n", 250); 99 $this->do_command("RCPT TO<".$to.">\r\n", 250); 100 $this->do_command("DATA\r\n", 354); 101 $this->do_command($detail."\r\n.\r\n", 250); 102 $this->do_command("QUIT\r\n", 221); 103 104 return true; 105 } 106 } 107 108 109 ?>
接着創建一個sendEmail.php測試文件進行測試
1 <?php 2 3 include("smtp.class.php"); 4 5 $host = "smtp.163.com"; 6 $port = 25; 7 $user = "onedream_kelly@163.com"; 8 $pass = "**********"; 9 10 $from = "onedream_kelly@163.com"; 11 $to = "****@163.com"; 12 $subject = "記得收衣服啊"; 13 $content = "今天我不回家,你記得收到衣服,免得到時衣服淋濕了沒得穿"; 14 15 $mail = new smtp_email($host, $port, $user, $pass, 1); 16 $res = $mail->send_email($from, $to, $subject, $content); 17 if ($res == true) { 18 echo "send success"; 19 } else { 20 echo "send fail"; 21 } 22 ?>
發送成功!
其實,現成有一個比較有名氣的郵件類,Emailer,大家可以看看這個是如何實現郵件發送和郵件接收的,理解清楚了,基本上會應用此來發送郵件了。
接下來我們思考一個問題:PHP與C語言怎么交互呢??
你可能會想到用C語言寫擴展,或則使用exec、system等命令,但我們可以換一個思路,就是用C語言提供服務,用PHP請求這個服務,PHP就能借助C語言完成很多看似不能完成的任務了。現在流行的WebGame正是利用C語言、java等重量級語言在底層完成復雜的運算,通過Socket把接口提供給PHP使用。