Contents

MIME 信件標題亂碼問題

某一天專案升級 Java 8 的過程中,我遇到寄出的 Email 標題變成亂碼。乍看像是編碼設定壞掉,但實際往下查才發現,問題不只是字串是不是 UTF-8,而是信件標頭本來就必須遵守 MIME 編碼格式。

這篇把這個問題整理成比較好理解的版本,之後如果又遇到中文標題、寄件者名稱亂碼,應該可以更快判斷原因。

為什麼主旨會亂碼

Email 並不是單純把一串 UTF-8 文字塞進去就結束。像 Subject、From 顯示名稱這些欄位,屬於信件 header,header 要符合 MIME 的 encoded-word 格式,例如:

1
=?UTF-8?B?5ris5paH5Li76aGM?=

這段格式可以拆成:

  1. UTF-8:使用的字元編碼。
  2. B:編碼方式,B 代表 Base64,Q 代表 Quoted-Printable。
  3. 後面那一段:實際被編碼過的內容。

也就是說,很多時候不是應用程式本身不知道 UTF-8,而是你把原始中文直接塞進 header,Mail Client 不一定會照你想的方式解讀。

PHP 的處理方式

如果是自己組 header,可以手動把標題包成 MIME encoded-word:

1
$subject = "=?UTF-8?B?" . base64_encode($subject) . "?=";

將上面一句加進去之後,中文標題通常就能正常顯示。

Java 的處理方式

如果是 JavaMail,建議不要自己手刻 MIME 格式,而是交給函式庫處理:

1
return String.format("%1$s <%2$s>", MimeUtility.encodeText(name, "UTF-8", "B"), email);

這樣做的好處是比較不容易在特殊字元、空白或多段字串時出錯。

哪些欄位常常一起中招

除了 Subject 之外,下面欄位也很常遇到相同問題:

  1. 寄件者名稱 From
  2. 收件者顯示名稱 To
  3. 副本 Cc
  4. 附件檔名

只要這些位置出現中文、日文、特殊符號,就要懷疑是不是 MIME header 編碼沒處理。

常見誤解

1. 內文正常,不代表主旨也正常

Email body 和 Email header 是兩件事。你可能內文 UTF-8 正常,但主旨還是亂碼,因為兩者處理規則不同。

2. 不是所有亂碼都是 SMTP 問題

有時候 SMTP Server 沒問題,真正有問題的是應用程式在組信件標頭時沒有正確 encode。

3. 手動 Base64 不是萬靈丹

若你使用成熟的 mail 函式庫,優先交給函式庫處理,會比自己硬湊格式更安全。

小結

信件標題亂碼的核心原因,通常不是 UTF-8 壞掉,而是 MIME header 沒有按照規則編碼。簡單記法就是:

  1. 主旨、寄件者名稱這類 header 要特別處理。
  2. PHP 可手動組 =?UTF-8?B?…?=。
  3. Java 盡量用 MimeUtility.encodeText() 之類的內建工具。

之後如果再遇到信件主旨亂碼,先檢查 MIME header,比直接懷疑資料庫或 SMTP 服務更有效率。