首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 使用 Socket 技術發送郵件的完整實現

     編輯:PHP 綜合知識

前言

在 PHP 開發中,若伺服器未安裝或無法使用 mail() 函式,或是需要更底層的控制,透過 Socket 直接與 SMTP 伺服器通訊發送郵件是一種經典且高效的替代方案。本文提供一個完整的函式範例,展示如何使用 fsockopen() 實現 SMTP 協定流程,包括 EHLO、AUTH LOGIN 認證、發件人/收件人指定、資料傳輸等關鍵步驟。

核心程式碼解析

以下函式 send_mail($to, $subject, $body) 封裝了完整的 SMTP 互動邏輯:

function send_mail($to, $subject, $body) {
    // SMTP 伺服器設定(請替換為您的實際帳號資訊)
    $loc_host  = "your_hostname";
    $smtp_acc  = "your_smtp_username";
    $smtp_pass = "your_smtp_password";
    $smtp_host = "smtp.example.com";
    $from      = "sender@example.com";

    // 郵件標頭,指定編碼為 gb2312,內容採 Base64 編碼
    $headers = "Content-Type: text/plain; charset=\"gb2312\"\r\nContent-Transfer-Encoding: base64";
    $lb = "\r\n";
    $hdr = explode($lb, $headers);

    // 處理郵件主體:將每一行以 "." 開頭的轉義為 "..",並進行 Base64 編碼
    if ($body) {
        $bdy = preg_replace("/^\./", "..", explode($lb, $body));
    }

    // 定義 SMTP 指令序列:每個元素包含 [指令字串, 預期回應代碼, 錯誤提示前綴]
    $smtp = array(
        array("EHLO ".$loc_host.$lb, "220,250", "HELO error: "),
        array("AUTH LOGIN".$lb, "334", "AUTH error:"),
        array(base64_encode($smtp_acc).$lb, "334", "AUTHENTIFICATION error: "),
        array(base64_encode($smtp_pass).$lb, "235", "AUTHENTIFICATION error: ")
    );

    // 後續指令:MAIL FROM, RCPT TO, DATA, 郵件標頭/主體, 結束符 ".", QUIT
    $smtp[] = array("MAIL FROM: <".$from.">".$lb, "250", "MAIL FROM error: ");
    $smtp[] = array("RCPT TO: <".$to.">".$lb, "250", "RCPT TO error: ");
    $smtp[] = array("DATA".$lb, "354", "DATA error: ");
    $smtp[] = array("From: ".$from.$lb, "", "");
    $smtp[] = array("To: ".$to.$lb, "", "");
    $smtp[] = array("Subject: ".$subject.$lb, "", "");
    foreach ($hdr as $h) { $smtp[] = array($h.$lb, "", ""); }
    $smtp[] = array($lb, "", ""); // 空行分隔標頭與主體
    if ($bdy) {
        foreach ($bdy as $b) {
            $smtp[] = array(base64_encode($b.$lb).$lb, "", "");
        }
    }
    $smtp[] = array(".".$lb, "250", "DATA(end) error: ");
    $smtp[] = array("QUIT".$lb, "221", "QUIT error: ");

    // 建立 Socket 連線
    $fp = @fsockopen($smtp_host, 25);
    if (!$fp) return "<b>Error:</b> Cannot connect to ".$smtp_host."<br>";

    // 讀取伺服器歡迎訊息
    while ($result = @fgets($fp, 1024)) {
        if (substr($result, 3, 1) == " ") break;
    }

    $result_str = "";
    // 依序發送指令並檢查回應
    foreach ($smtp as $req) {
        @fputs($fp, $req[0]);
        if ($req[1]) {
            while ($result = @fgets($fp, 1024)) {
                if (substr($result, 3, 1) == " ") break;
            }
            if (!strstr($req[1], substr($result, 0, 3))) {
                $result_str .= $req[2].$result."<br>";
            }
        }
    }

    @fclose($fp);
    return ($result_str == "") ? "發送成功!!" : $result_str;
}

關鍵點說明

  • 認證機制:採用 AUTH LOGIN,帳號密碼均需 Base64 編碼。
  • 資料傳輸:郵件主體內容需逐行 Base64 編碼,且以單獨的一個點 . 結束 DATA 階段。
  • 回應碼檢查:每個關鍵指令後皆讀取伺服器回應,驗證前三位代碼是否符合預期(如 250, 334, 354 等),失敗則記錄錯誤。
  • 錯誤處理:函式最終回傳「發送成功!!」或累積的錯誤訊息,方便上層邏輯判斷。

使用建議

  1. 將範例中的 SMTP 設定(主機、帳號、密碼、發件人)替換為真實可用的值。
  2. 若發送中文內容,確保編碼設定(charset)與實際內容一致,或改用 UTF-8。
  3. 生產環境建議加入 SSL/TLS 支援(連接埠 465 或 587),可改用 fsockopen("ssl://smtp.host", 465) 或搭配 stream_socket_enable_crypto() 升級為 STARTTLS。
  4. 考慮加入超時設定與重試機制,提高穩定性。

此函式不依賴 PHP 的 mail() 或任何擴充套件,僅需核心的 sockets 功能即可運作,適合需要高度自訂或在受限環境下發送郵件的場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved