PHPMailer 發送中文郵件出現亂碼,90% 是編碼設定不一致導致。本文提供經驗證的三步修正法,涵蓋核心庫配置、實例層級設定、標題專用編碼,確保 Gmail、Outlook、QQ 郵箱等國際/國內主流客戶端完美顯示。
編輯 vendor/phpmailer/phpmailer/src/PHPMailer.php (或舊版 class.phpmailer.php):
// 找到約第 100 行
public $CharSet = 'iso-8859-1'; // 預設西歐編碼
// 修改為
public $CharSet = 'UTF-8';
原理:ISO-8859-1 僅支援西歐字符,中文會被誤解析為亂碼。UTF-8 涵蓋全球所有語言,是郵件傳輸的國際標準編碼 (RFC 6532)。
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
$mail = new PHPMailer(true);
try {
// 核心編碼設定
$mail->CharSet = 'UTF-8'; // 郵件正文編碼
$mail->Encoding = 'base64'; // 內容傳輸編碼,避免 8bit 被郵遞伺服器截斷
// SMTP 設定 (以 Gmail 為例)
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@gmail.com';
$mail->Password = 'app_password'; // 應用程式密碼
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
// 寄件/收件
$mail->setFrom('your@gmail.com', '您的名稱');
$mail->addAddress('recipient@example.com');
// 內容
$mail->isHTML(true);
$mail->Subject = '測試中文標題';
$mail->Body = '這是 HTML 格式的中文正文內容。';
$mail->AltBody = '這是純文字備用內容。';
$mail->send();
echo '發送成功';
} catch (Exception $e) {
echo "發送失敗: {$mail->ErrorInfo}";
}
即使正文正常,標題若含中文,部分 MUAs (郵件用戶代理) 仍會亂碼。RFC 2047 規定標題需用 =?charset?encoding?encoded-text?= 格式。
// 手動編碼 (PHPMailer 6.5+ 內建支援,若版本舊請手動)
$subject = '中文標題測試';
$mail->Subject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
// 產生:=?UTF-8?B?5L2g5aW95Lit5b+D5Lq655S1?=
進階封裝函數:
function encodeMimeSubject(string $subject, string $charset = 'UTF-8'): string
{
return '=?' . $charset . '?B?' . base64_encode($subject) . '?=';
}
// 使用
$mail->Subject = encodeMimeSubject('訂單 #20240520 發貨通知');
| 錯誤做法 | 後果 | 正確做法 |
|---|---|---|
設定 $mail->CharSet = 'GBK' | Gmail/Outlook 顯示亂碼,僅國內客戶端可讀 | 統一使用 UTF-8 |
| 正文用 UTF-8,標題未編碼 | 標題亂碼,正文正常 | 標題必須 Base64/Quoted-Printable 編碼 |
HTML 正文未設 Content-Type charset | 瀏覽器/客戶端猜錯編碼 | $mail->CharSet='UTF-8' 自動生成正確 Header |
| 附件檔名中文未編碼 | 下載檔名亂碼 | $mail->addAttachment($path, encodeMimeSubject($filename)) |
Content-Type: text/html; charset=UTF-8 是否存在?Subject: =?UTF-8?B?....?= 格式是否正確?DATA 命令後內容截斷?(檢查 Encoding = 'base64')mb_check_encoding($str, 'UTF-8'))遵循「核心庫 UTF-8 + 實例 UTF-8 + 標題 Base64」三步法,PHPMailer 中文亂碼問題將徹底成為歷史。