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

PHP 發送帶附件郵件完整實現(原生 MIME 封裝)

     編輯:PHP 相關知識

PHP 內置 mail() 函數不直接支持附件,需手動構造符合 MIME 標準的多部件郵件體。本文提供一個完整的 CMailFile 類,演示如何構建包含文本內容與 Base64 編碼附件的郵件,並通過 mail() 發送。

核心原理:MIME Multipart 結構

帶附件郵件本質是 multipart/mixed 類型,包含兩個部分:

  1. 文本部分: text/plain 或 text/html,郵件正文。
  2. 附件部分: application/octet-stream 或具體 MIME 類型,內容經 Base64 編碼,並聲明 Content-Disposition: attachment。

各部分通過 Boundary(邊界字符串) 分隔,Boundary 需在 Header 中聲明且正文中唯一。

CMailFile 類完整代碼

<?php
class CMailFile {
    var $subject;
    var $addr_to;
    var $text_body;
    var $text_encoded;
    var $mime_headers;
    var $mime_boundary = "--==================_846811060==_"; // 唯一邊界標識
    var $smtp_headers;

    /**
     * 構造函數:組裝郵件各部分
     * @param string $subject 主題
     * @param string $to 收件人
     * @param string $from 發件人
     * @param string $msg 正文內容
     * @param string $filename 附件本地路徑
     * @param string $downfilename 附件下載顯示名
     * @param string $mimetype 附件 MIME 類型
     * @param string $mime_filename 附件在郵件中顯示的文件名(可選)
     */
    function CMailFile($subject, $to, $from, $msg, $filename, $downfilename, $mimetype = "application/octet-stream", $mime_filename = false) {
        $this->subject = $subject;
        $this->addr_to = $to;
        $this->smtp_headers = $this->write_smtpheaders($from);
        $this->text_body = $this->write_body($msg);
        $this->text_encoded = $this->attach_file($filename, $downfilename, $mimetype, $mime_filename);
        $this->mime_headers = $this->write_mimeheaders($filename, $mime_filename);
    }

    // 讀取文件並 Base64 編碼
    function encode_file($sourcefile) {
        if (is_readable($sourcefile)) {
            $fd = fopen($sourcefile, "r");
            $contents = fread($fd, filesize($sourcefile));
            $encoded = chunk_split(base64_encode($contents)); // 按 RFC 2045 每 76 字符換行
            fclose($fd);
            return $encoded;
        }
        return '';
    }

    // 構建附件部分
    function attach_file($filename, $downfilename, $mimetype, $mime_filename) {
        $encoded = $this->encode_file($filename);
        if ($mime_filename) $filename = $mime_filename;
        $out = "--" . $this->mime_boundary . "\n";
        $out .= "Content-Type: " . $mimetype . "; name=\"$filename\"\n";
        $out .= "Content-Transfer-Encoding: base64\n";
        $out .= "Content-Disposition: attachment; filename=\"$downfilename\"\n\n";
        $out .= $encoded . "\n";
        $out .= "--" . $this->mime_boundary . "--\n";
        return $out;
    }

    // 發送郵件
    function sendfile() {
        $headers = $this->smtp_headers . $this->mime_headers;
        $message = $this->text_body . $this->text_encoded;
        return mail($this->addr_to, $this->subject, $message, $headers);
    }

    // 構建文本正文部分
    function write_body($msgtext) {
        $out = "--" . $this->mime_boundary . "\n";
        $out .= "Content-Type: text/plain; charset=\"utf-8\"\n\n"; // 建議使用 UTF-8
        $out .= $msgtext . "\n";
        return $out;
    }

    // 構建 MIME 頭部
    function write_mimeheaders($filename, $mime_filename) {
        if ($mime_filename) $filename = $mime_filename;
        $out = "MIME-Version: 1.0\n";
        $out .= "Content-Type: multipart/mixed;\n";
        $out .= " boundary=\"$this->mime_boundary\"\n";
        $out .= "Content-Transfer-Encoding: 7BIT\n";
        $out .= "X-Attachments: $filename\n\n";
        return $out;
    }

    // 構建 SMTP 基礎頭部
    function write_smtpheaders($addr_from) {
        $out = "From: $addr_from\n";
        $out .= "Reply-To: $addr_from\n";
        $out .= "X-Mailer: PHP/" . phpversion() . "\n";
        $out .= "X-Sender: $addr_from\n";
        return $out;
    }
}
?>

使用示例

<?php
require_once('emailclass.php');

// 郵件參數
$subject = "測試帶附件郵件";
$sendto = 'recipient@example.com';
$replyto = 'sender@example.com';
$message = "這是郵件正文內容,支持中文。";
$filename = 'test.jpg';           // 服務器上的附件路徑
$downfilename = 'photo.jpg';      // 用戶下載時顯示的文件名
$mimetype = "image/jpeg";         // 附件 MIME 類型

$mail = new CMailFile($subject, $sendto, $replyto, $message, $filename, $downfilename, $mimetype);
if ($mail->sendfile()) {
    echo "郵件發送成功";
} else {
    echo "郵件發送失敗";
}
?>

關鍵細節與最佳實踐

項目說明建議
Boundary 生成固定字符串可能衝突使用 md5(uniqid(time())) 動態生成
字符編碼正文 charset 為 us-ascii改為 UTF-8,中文不會亂碼
大附件處理全量讀入內存大文件建議分塊讀取編碼,或改用 PHPMailer 流式處理
錯誤處理mail() 返回 bool生產環境應記錄錯誤日志,配合 SPF/DKIM 提高送達率
多附件支持類僅支持單附件擴展 attach_file 為循環調用,累加到 text_encoded

現代替代方案:PHPMailer / Symfony Mailer

雖然原生實現有助於理解 MIME 結構,但生產環境強烈建議使用成熟庫:

  • PHPMailer: 支持 SMTP 認證、TLS/SSL、多附件、HTML/文本替代體、嵌入圖片、郵件隊列等。
  • Symfony Mailer: 現代化組件,支持多傳輸、異步發送、模板引擎集成。
<?php
// PHPMailer 發送帶附件郵件(簡單幾行)
use PHPMailer\PHPMailer\PHPMailer;
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->Username = 'user';
$mail->Password = 'pass';
$mail->setFrom('from@example.com', 'Sender');
$mail->addAddress('to@example.com');
$mail->Subject = 'Subject';
$mail->Body = 'HTML body';
$mail->addAttachment('/path/to/file.jpg', 'photo.jpg');
$mail->send();
?>

理解原生 MIME 封裝原理有助於排查郵件發送問題,但實際項目中請優先選擇成熟庫,避免重複造輪子並踩坑。

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