亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

用Socket發送電子郵件(php)

2019-09-10 09:07:03
字體:
來源:轉載
供稿:網友

用Socket發送電子郵件

作者:limodou

  在作者所申請的幾個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句柄,使用它就可以象使用文件句柄一樣的??墒褂玫牟僮饔衒puts(),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
250 Ok
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("$", $message))
12 $message .= "<br>";
13 $message=nl2br($message);
14 echo "<font color=#999999>${m}${message}</font>";
15 }
16 }
--------------------------------------------------------------------------------
  這個函數用來顯示調試信息??梢栽?inout中指定是上傳的指令還是返回的響應,如果為上傳指令,則
使用"out";如果為返回的響應則使用"in"。

第3行,判斷是否要輸出調試信息。
第5行,判斷是否為響應信息,如果是,則在第7行將信息的前面加上"<< "來區別信息;否則在第10行加上
    ">> "來區別上傳指令。
第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 function send( $to,$from,$subject,$message)
2 {
3
4 //連接服務器
5 $this->lastact="connect";
6
7 $this->show_debug("Connect to SMTP server : ".$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->welcome . "";
23 if(!$this->do_command($this->lastact, "250"))
24 {
25 fclose($this->fp);
26 return false;
27 }
28
29 $this->lastact="MAIL FROM: $from" . "";
30 if(!$this->do_command($this->lastact, "250"))
31 {
32 fclose($this->fp);
33 return false;
34 }
35
36 $this->lastact="RCPT TO: $to" . "";
37 if(!$this->do_command($this->lastact, "250"))
38 {
39 fclose($this->fp);
40 return false;
41 }
42
43 //發送正文
44 $this->lastact="DATA";
45 if(!$this->do_command($this->lastact, "354"))
46 {
47 fclose($this->fp);
48 return false;
49 }
50
51 //處理Subject頭
52 $head="Subject: $subject";
53 if(!empty($subject) && !ereg($head, $message))
54 {
55 $message = $head.$message;
56 }
57
58 //處理From頭
59 $head="From: $from";
60 if(!empty($from) && !ereg($head, $message))
61 {
62 $message = $head.$message;
63 }
64
65 //處理To頭
66 $head="To: $to";
67 if(!empty($to) && !ereg($head, $message))
68 {
69 $message = $head.$message;
70 }
71
72 //加上結束串
73 if(!ereg(".", $message))
74 $message .= ".";
75 $this->show_debug($message, "out");
76 fputs($this->fp, $message);
77
78 $this->lastact="QUIT";
79 if(!$this->do_command($this->lastact, "250"))
80 {
81 fclose($this->fp);
82 return false;
83 }
84 }
85 return true;
86 }
87 else
88 {
89 $this->show_debug("Connect failed!", "in");
90 return false;
91 }
92 }
--------------------------------------------------------------------------------
  有些意思很清楚的我就不說了。

  這個函數一共有四個參數,分別是$to表示收信人,$from表示發信人,$subject表求郵件主題和$message
表示郵件體。如果處理成功則返回true,失敗則返回false。

第8行,連接郵件服務器,如果成功響應碼應為220。
第12行,設置阻塞模式,表示信息必須返回才能繼續。詳細說明看手冊吧。
第16行,判斷響應碼是否為220,如果是,則繼續處理,否則出錯返回。
第22-27行,處理HELO指令,期望響應碼為250。
第29-34行,處理MAIL FROM指令,期望響應碼為250。
第36-41行,處理RCPT TO指令,期望響應碼為250。
第44-49行,處理DATA指令,期望響應碼為354。
第51-76行,生成郵件體,并發送。
第52-56行,如果$subject不為空,則查找郵件體中是否有主題部分,如果沒有,則加上主題部分。
第59-63行,如果$from不為空,則查找郵件體中是否有發信人部分,如果沒有,則加上發信人部分。
第66-70行,如果$to不為空,則查找郵件體中是否有收信人部分,如果沒有,則加上收信人部分。
第73-74行,查找郵件體是否有了結束行,如果沒有則加上郵件體的結束行(以"."作為單獨的一行的特殊行)。
第76行,發送郵件體。
第78-83行,執行QUIT結否與服務器的連接,期望響應碼為250。
第85行,返回處理成功標志(true)。
第81-91行,與服務器連接失敗的處理。

  以上為整個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 "發送成功!<br>";
7 }
8 else
9 {
10 echo "發送失敗!<br>";
11 }
?>
--------------------------------------------------------------------------------
第1行,裝入send_mail類。
第3行,創建一個類的實例,且設置顯示調示信息,如果不想顯示,可以
    $sendmail=new send_mail("smtp.263.net");。
第4行,發送郵件。


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

--------------------------------------------------------------------------------
<?php

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

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

//信息被我改少了
$html_data = '<html><head><title>'. $str. '</title></head>
<body bgcolor="#ffffff">
Hello! This is a test!
</body>
</html>';

//生成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."<br>";

//包含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);

?>

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩高清av在线| 日韩精品免费电影| 久久精品视频在线观看| 亚洲成人免费网站| 亚洲国产成人91精品| 中文字幕亚洲国产| 成人精品在线观看| 日韩欧美在线中文字幕| 91欧美精品午夜性色福利在线| 91九色国产社区在线观看| 午夜剧场成人观在线视频免费观看| 精品国产福利在线| 中文字幕国产亚洲| 国产成+人+综合+亚洲欧洲| 欧美激情精品久久久久久久变态| 成人www视频在线观看| 一区二区三区四区在线观看视频| 国产精品美乳在线观看| 日韩欧美中文字幕在线播放| 日本aⅴ大伊香蕉精品视频| 欧美在线观看日本一区| 91精品国产综合久久香蕉| 欧美日本精品在线| 久久国产加勒比精品无码| 亚洲精品久久久久久久久久久久| 国产精品久久久久不卡| 国产拍精品一二三| 国产成人涩涩涩视频在线观看| 日韩av在线一区二区| 在线看欧美日韩| 欧美黄色www| 欧美中文在线观看国产| 国产精品最新在线观看| 国内精品一区二区三区四区| 午夜精品在线视频| 亚洲四色影视在线观看| 国产成人精品综合久久久| 欧美激情精品久久久久久免费印度| 亚洲精品视频在线观看视频| 久久亚洲私人国产精品va| 一区三区二区视频| 久久久久久亚洲| 国内精品久久久久久久久| 精品中文字幕久久久久久| 国产精品999| 91中文在线视频| 91亚洲精品一区| 国产精品久久久久久久7电影| 中文字幕欧美国内| 久久999免费视频| 欧美高清videos高潮hd| 欧美性猛交xxxx乱大交3| 久久久久久国产精品| 日韩精品高清在线观看| 亚洲第一精品夜夜躁人人爽| 国产美女扒开尿口久久久| 亚洲人成绝费网站色www| 在线一区二区日韩| 亚洲欧美中文日韩在线| 亚洲精品美女网站| 久久精品在线视频| 亚洲第一男人天堂| 亚洲偷欧美偷国内偷| 美日韩精品视频免费看| 国产精品男人爽免费视频1| 欧美高清在线观看| 久久人人爽人人爽爽久久| 久色乳综合思思在线视频| 亚洲美腿欧美激情另类| 国产精品一区久久| 亚洲视频自拍偷拍| 久久久久国产精品免费网站| 高清一区二区三区四区五区| 伊人伊成久久人综合网小说| 欧美激情一二三| 亚洲精品国产精品自产a区红杏吧| 日韩电影在线观看永久视频免费网站| 欧美激情亚洲精品| 亚洲精品美女久久| 久久视频精品在线| 日韩国产中文字幕| 国产精品久久av| 九九精品视频在线| 精品成人av一区| 国产精品日本精品| 亚洲一区二区久久| 日本中文字幕不卡免费| 日韩精品免费一线在线观看| 中文字幕国产亚洲2019| 91在线观看欧美日韩| 色视频www在线播放国产成人| 国产精品18久久久久久麻辣| 91精品久久久久久久久久久久久| 在线精品国产欧美| 亚洲美女免费精品视频在线观看| 久久久国产精彩视频美女艺术照福利| 欧美日韩一区二区精品| 日韩欧美在线一区| 亚洲新中文字幕| 成人免费福利视频| 亚洲一区免费网站| 欧美激情视频一区二区三区不卡| 久久视频在线看| 欧美成人免费一级人片100| 国产欧美日韩精品专区| 欧美激情在线有限公司| 久久久久久高潮国产精品视| 日韩高清a**址| 一本色道久久88亚洲综合88| 亚洲va久久久噜噜噜久久天堂| 国产一区二区三区在线看| 国产成人福利视频| 国产一区二区成人| 欧美一级bbbbb性bbbb喷潮片| 国产亚洲精品久久| 日本久久久久久| 欧美成人亚洲成人| 亚洲日本中文字幕| 91中文字幕在线观看| 亚洲欧美视频在线| 国产精品jizz在线观看麻豆| 欧美成人精品影院| 久久99热这里只有精品国产| 精品亚洲一区二区三区在线播放| 国产精品一区二区久久久| 久热精品视频在线观看| 欧美日韩国产激情| 欧美激情videoshd| 亚洲精品98久久久久久中文字幕| 91亚洲一区精品| 日韩一区av在线| 少妇高潮 亚洲精品| 中文字幕亚洲天堂| 超碰精品一区二区三区乱码| 欧美在线视频a| 久久全球大尺度高清视频| 欧美高清视频免费观看| 中文字幕日韩在线观看| 久久香蕉国产线看观看网| 成人在线国产精品| 欧美激情精品久久久久久黑人| 国产精品亚洲激情| 日韩免费在线免费观看| 懂色av中文一区二区三区天美| 日韩精品一二三四区| 欧美三级免费观看| 午夜精品在线观看| 国产一区二区三区视频免费| 欧美日韩亚洲91| 精品国产一区二区三区久久狼5月| 欧美性xxxx18| 亚洲国产精品久久久久秋霞不卡| 日韩在线视频播放| 久久九九亚洲综合| 久久精品国产亚洲精品| 成人欧美一区二区三区黑人| 成人福利在线观看| 亚洲自拍偷拍第一页| 亚洲欧美在线免费观看| 欧洲中文字幕国产精品| 美女国内精品自产拍在线播放| 91色在线视频| 亚洲国产欧美一区二区三区同亚洲| 久久av红桃一区二区小说|