用php發送E-MAIL

用來傳送 e-mail 的描述語言程式(Script)可說是網站上最常見的程式之一。雖然它很單純,但是在某些時候,它卻往往對程式設計師們造成極大的困擾。在 PHP 中有一個函式叫做 mail(),只要有收信者名稱以及訊息內容,就可以拿來傳送訊息。但是你還是需要針對 mail()做某些調整,才能讓mail()為你完成你想做的事。

首先,要讓 mail()能夠運作,你必須先有一個 SMTP 伺服器,好讓你的 PHP 連上去。雖然這個伺服器在電子郵件程式中佔有極其重要的地位,大部分的人還是對它一知半解。在這篇教學指南裡,我們會為你揭開 SMTP 的神秘面紗,並且同時解說關於使用 PHP 傳送電子郵件的某些常見問題。其中精采的內容還包括了:如何以迴圈的程式敘述,讀取電子郵件住址名單,同時針對其中的收件者一一傳送郵件,包括純文字格式以及 HTML 格式的郵件等等。

了解你的 SMTP 伺服器
SMTP 是 Simple Mail Transfer Protocol 的縮寫,而 SMTP 伺服器則是透過執行該通訊協定而傳送電子郵件的電腦。基本上,執行通訊協定指的是:如果你使用的是非 Windows 作業平台,執行的是 Sendmail 或 Qmail這類的電子郵件軟體。而如果這部機器使用的是 Windows 作業平台,那麼 SMTP 服務已經包括在 Windows NT Service Pack 中,或者內建在 Windows 2000 裡面,而且,這項服務通常就是正在執行中的電子郵件服務。

這並不是說,SMTP 軟體就只有那幾種,只是它們是最被廣為使用的。如果你的網站是 ISP 的虛擬主機(Vitual hosting)套件的一部分,SMTP 服務應該就已經安裝在主機上面了。如果你是位系統管理者,負責管理某台放在 ISP 或公司機房的專屬主機(Dedicated machine)的話,那麼你很可能會需要在那部機器安裝某種 SMTP daemon,特別用來處理網站伺服器的電子郵件傳遞。

然而,如果你只是一個單獨的使用者,只有一套網站伺服器開發平台在你的個人電腦上面,你可能沒有在你的機器上安裝 SMTP。這裡有個非常簡單但是精確的準則: 如果你是個 Windows 使用者,而你從來未曾聽過 SMTP 伺服器,那麼你就沒有安裝 SMTP。若果真如此,你有兩個選擇:安裝, 設定,並維護一個 SMTP 伺服器(如果你不知道那是什麼,我並不鼓勵你這樣做)或者直接使用已經在你手邊的東西。

「我沒有安裝,怎麼會說在我手邊呢?」你可能會這樣問。嗯,如果你的電腦是透過撥接上網的(或 DSL 或者 cable),你可以直接使用你的 ISP 的外寄郵件伺服器(outgoing mail server)。例如,如果你的開發平台是 Windows 98,以及一台 56Kbps 的數據機,並透過 EarthLink 上網, 那麼你可以用 mail.earthlink.net 當作你的 SMTP 伺服器。不管你使用的是哪一種電子郵件客戶端軟體 (Eudora,Outlook,Netscape Mail 等等),你的外寄郵件伺服器都可以在 PHP 程式碼中,指定為 SMTP 伺服器。要訣在於,你要告知 PHP 這件事情。

在 PHP 的主要設定檔,php.ini 中,有一些 directive 是你必須去設定,這樣一來 mail() 函式才能夠使用。在更改那些設定以前,你先看看它們是什麼。使用 phpinfo() 函式,可以顯示你的系統目前的設定, 做法是,建一個檔案,包括下列文字:

<? phpinfo() ?>

將檔案存起來,放在你的網站伺服器的文件根目錄中。然後用你的瀏覽器去看這個檔案。你應該會看到一個編排良好的現有設定列表。在這裡,你要注意的設定選項為:

SMTP
sendmail_from
sendmail_path
如果你用的不是 Windows,你只須擔心 sendmail_path directive。如果你用的是 Windows,你就要注意先前兩個 directive。

如果你用的是 Linux 或其他 Unix 變種系統,sendmail_path 應該差不多是這樣子設定的:

sendmail_path = /usr/sbin/sendmail

或者,如果你用的是 Qmail:

sendmail_path = /var/qmail/bin/sendmail

在這個 directive 裡面,你也可以設定某些 flag 來指明你的 queuing 做法,或者是用來明確的寫出你的 Return-Path 標題,就像這樣:

sendmail_path = /usr/sbin/sendmail -t [email protected]

如果你不是 Windows 使用者,你所需要做的就那麼多了。如果你使用的是 Windows,你還有一些事情要處理。你必須看看 SMTP 以及 sendmail_from 的值。不要被 sendmail_from 的 directive 名字中的 sendmail 給搞糊塗了。雖然你在 Windows 上面並沒有用一個叫做 Sendmail 的程式,這個只是 directive 的名字而已。不要緊張。

在phpinfo() 所顯示的結果中,注意一下 SMTP 以及 sendmail_from 原先的設定值 – 它們應該是空白的,或者只是虛值(dummy)。你必須將它們改為對你系統有意義的值。

如果你真的在你的機器上安裝並啟動 SMTP 伺服器,你的 php.ini 應該要有這樣的設定:

SMTP = localhost

然而,如果你要用你的 ISP 的外寄郵件伺服器(在這裡,我們用 EarthLink 做例子),那麼你的 php.ini 就要有這樣的設定:

SMTP = mail.earthlink.net

你也可以直接用 IP address 而非名字,因為電腦並不會區別這兩者的差異。

第二個我們要設定的 directive 是 sendmail_from,這個是設定在 From 標題(header)裡面所使用的 e-mail 位址。這個設定值可以用 mail 程式更改,但是通常這裡的設定值都被拿來當作內定值。以下是,如果你的電子郵件地址是 [email protected], 所應該做的設定值。

sendmail_from = [email protected]

在更改以上設定值之後,重新啟動你的網站伺服器,再用 phpinfo() 函式來確定這些設定已經被更改了。當你完成這些事情後, 你就已經準備好用 PHP 來傳送 e-mail 了。

傳送一個簡單的 e-mail
mail() 函式相當簡單:只有五個參數,而且其中兩個是選擇性的(optional)。這些參數是:
收件者地址
主旨
訊息
其他郵件標題(選擇性)
其他 SMTP 伺服器的設定選項(選擇性)
額外的郵件標題參數,是用來控制某些電子郵件功能,像是 CC,BCC,Reply-To fields,或其他 SMTP 通訊協定所規定的功能。 在這個例子裡,我只用 From 以及 Reply-To 電子郵件標題。

如果你要送 mail 給我,而你用的不是 Windows 系統,那麼它看起來會像這樣:

<? $to = "[url=mailto:[email protected]][email protected][/url]"; $subject = "ZDNet Developer article"; $msg = "I completely understand SMTP servers now!"; $headers = "From: [url=mailto:[email protected]][email protected][/url]\nReply-To: [url=mailto:[email protected]][email protected][/url]"; $config = "[url=mailto:[email protected]][email protected][/url]"; mail("$to", "$subject", "$msg", "$headers", "$config"); echo "finished!"; ?>

如果你用的是 Windows 的 SMTP 服務,那麼很可能你不需要設定第五個參數,以及額外的郵件標題參數 (即第四個參數),不過你要用 \r\n 而非 \n 將你的參數分開。因此,同樣的電子郵件,透過 Windows 的 SMTP 服務傳送,看起來會是這樣:

<? $to = "[url=mailto:[email protected]][email protected][/url]"; $subject = "ZDNet Developer article"; $msg = "I completely understand SMTP servers now!"; $headers = "From: [url=mailto:[email protected]][email protected][/url]\r\nReply-To: [url=mailto:[email protected]][email protected][/url]"; mail("$to", "$subject", "$msg", "$headers"); echo "finished!"; ?>

在以上程式中的 echo 敘述,是讓你的網頁瀏覽器在執行完這個程式後,回傳給你一個訊息。如果沒有這項敘述,你會收到一個「Document contains no data」對話方塊,因為沒有東西傳送到你的網頁瀏覽器上。

mail() 函式只要連到指定的 SMTP 伺服器,就會回傳 true。這並不意味著郵件已經成功抵達收件者了。mail() 函式並不會等 SMTP 伺服器告訴它傳送成功或失敗。

mail() 函式會回傳 false,並且送給你一個警告,像是「Couldn’t connect in line x」 或者是「Unknown error in line x」。如果你沒看到前面兩個訊息,檢查一下 php.ini 的 SMTP 設定值。有兩種可能性會導致這個訊息的產生:SMTP 伺服器當掉了,或者是 PHP 沒連到 SMTP 伺服器。當然,這兩種情況下, 你的電子郵件都不會被傳送出去。

這個程式用的參數都是寫死在程式中的。你可以透過一個簡單的 HTML 表格,將這些值送出去,然後再回傳給你一個回饋表格(feedback form)。

以迴圈讀取傳送名單
一旦你知道要怎樣傳送電子郵件給一個人,你或許會感到非常興奮而且想傳送同樣的訊息給很多收件者 --就像電子報一樣。你只要做一個簡單的迴圈敘述, 一一閱讀你名單上的名字,然後傳送電子郵件給他們。

mail 函式的格式是一樣的:

mail([recipient], [subject], [message], [any headers]);

你必須將 [recipient] 換成迴圈中你的名單的下一個名字。假設你有一個 e-mail 地址的陣列:

$addresses = array(“[email protected]”, “[email protected]”, “[email protected]”);

你只要以迴圈讀取這個 array, 取得新的電子郵件地址,然後傳送郵件。

如果你的電子郵件地址名單是存在資料庫裡面,你還是可以用同樣的方式:以迴圈一一讀取它們。

就是這麼簡單。顯然的,同樣的觀念可以運用到你特定的資料庫種類以及表格(table)架構, 雖然程式碼必須做一點修改。

這裡還有一個小小的訣竅,在以迴圈敘述讀取一串電子郵件名單的時候,似乎每一個人都忽略了它:如果你有多於五十個郵件地址,你的程式或許在還沒完成讀取名單的時候,就逾時(time out)了,因為 PHP 對每個程式的內建時間限制是三十秒。你可以修改這個時間限制, 但是要小心。試著將這個修改的效果限制在某些特定的程式中, 例如迴圈讀取電子郵件名單並且傳送郵件。否則的話,你可能會有一些伺服器程序 (server process) 一直在你的伺服器上,你的主機會幾乎停滯,整個世界就會停止。

要在程式裡面設定時間限制,使用 set_time_limit() 函式。你可以指定這個限制,例如六十秒(set_time_limit(60)),或者你可以讓它一直等下去,(set_time_limit(0))。

將這個放在你的程式中,你傳送電子郵件的迴圈敘述就會一直持續下去直到名單中所有的地址都傳送出去為止。

傳遞 HTML 格式的電子郵件
傳送 HTML 格式的 e-mail 是另一個看起來困難但是做起來簡單的事情。一旦你知道怎麼做,你或許會為了以前把它想得太困難而想打你自己一頓!

我們需要對先前用過的基本電子郵件敘述程式做兩個修改:

你的郵件訊息應該是 HTML 格式的。
你必須增加內容種類郵件標題(content-type header)。
這樣就可以了。使用者如果擁有可以讀取 HTML 格式郵件的電子郵件客戶端軟體的話,他所看到的郵件訊息會是大型的粗體字形。如果你傳送的 HTML 格式的電子郵件有影像的 tag 在裡面,你必須記得在 src 屬性中使用完整的 URL。例如:<img src="">。

記得,不是所有人都可以讀取 HTML 格式的電子郵件,如果使用的軟體不能讀取 HTML 格式的電子郵件,那麼收件者就只能看到 HTML 程式碼。這會讓人有點受不了,所以小心使用這項功能。

結論
你可以用幾乎你所能想像得到的所有各種不同的方式,使用 PHP 傳送電子郵件。這篇文章只有接觸到基本面而已:設定你的伺服器,並且傳送一些簡單的電子郵件。你也可以用 mail() 產生的電子郵件來傳送附件,修改很多不同的郵件標題。大致上說來,你也可以用 PHP 做任何現實生活中, 電子郵件客戶端軟體或郵件名單程式可以做到的事情。

linux 系統 4 個參數也可以的,隔開的話在linux上也可以使用\r 所以找個統一性的寫法就不怕代碼出現問題。

Windows 的 SMTP 設定如果是使用streamyx 的話用 smtp.streamyx.com 或 jaring的就填入 smtp.jaring.my, 而 sendmail_from 主要是填入你 streamyx 的帳號信箱,如 [email protected] 等作爲smtp認證

谢谢楼主分享资料… :slight_smile: