根本原因是CI框架subject()方法默认使用Q-Encoding处理中文标题,而Q编码对长中文兼容性差;应改为Base64编码,即修改Email.php中subject()方法,用'=?'.$this->charset.'?B?'.base64_encode($subject).'?='替换原逻辑,并确保$config['charset']='utf-8'。

CI 框架发邮件时中文标题乱码,根本原因不是邮件内容本身,而是 subject() 方法默认用 Q-Encoding 处理标题,而多数邮箱客户端(尤其是 QQ、163、Outlook)对长中文标题的 Q 编码解析不稳定。直接改用 Base64 编码就能绕过这个问题。
为什么 subject() 会乱码,而 message() 不会
CI 的 message() 默认走 HTML 或纯文本路径,只要页面和数据库编码统一为 UTF-8,内容体基本不会出问题;但 subject() 是邮件头字段,受 RFC 2047 限制,必须做 MIME 编码。CI 旧版(3.1.x 及更早)硬编码调用 _prep_q_encoding(),Q 编码对中文支持弱,尤其连续汉字超过 12 个就容易截断或错位。
- Q 编码把中文转成
=E5=8C=97=E6=9E=81这类形式,中间不能断行,超长时会被某些 SMTP 中继截断 - Base64 编码(
?B?)把整段字符串一次性 base64_encode,兼容性更好 -
message()如果也乱码,大概率是 PHP 文件保存编码不是 UTF-8 无 BOM,或数据库连接没设 charset
修改 subject() 方法强制用 Base64 编码
打开 system/libraries/Email.php,定位到 public function subject($subject) 方法体,把原逻辑替换成:
AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。
public function subject($subject)
{
$subject = '=?' . $this->charset . '?B?' . base64_encode($subject) . '?=';
$this->set_header('Subject', $subject);
return $this;
}
- 别删掉
$this->charset—— 它来自你初始化时配置的$config['charset'] = 'utf-8' - 确保初始化时已设
$config['charset'] = 'utf-8',否则$this->charset可能是默认的iso-8859-1 - 不要手动在
base64_encode()前加mb_convert_encoding($subject, 'UTF-8')—— CI 已假设输入是 UTF-8,额外转换反而可能 double-encode
SMTP 配置里几个关键项不能漏
光改 subject() 不够,如果 SMTP 连接层或内容类型没对齐,正文也可能花掉:
-
$config['charset'] = 'utf-8'必须显式设置,不能依赖默认值 -
$config['mailtype'] = 'html'或'text'要跟实际message()内容一致;HTML 邮件记得在内容开头加<meta charset="utf-8"> -
$config['newline'] = "\r\n"和$config['crlf'] = "\r\n"必须是 Windows 风格换行,Linux 风格\n会导致部分企业邮箱拒收或解析异常 - Gmail/腾讯企业邮箱等要求开启 SSL/TLS,
$config['smtp_host']要写成'ssl://smtp.qq.com'或'tls://smtp.gmail.com',端口对应 465 或 587
调试时最该看的三处输出
乱码问题难复现,靠猜没用,发完立刻查这三项:
- 运行
$this->email->print_debugger(),重点看Subject:行是否显示为=?utf-8?B?...开头 —— 不是就说明subject()没生效 - 用 Webmail(如 QQ 邮箱网页版)打开收到的邮件,右键「查看原始邮件」,确认
Subject:头字段编码格式是否符合预期 - 检查 PHP 错误日志,如果出现
base64_encode() expects parameter 1 to be string,说明传给subject()的变量是null或数组,要前置判空
真正麻烦的不是改哪一行代码,而是改完之后忘了清浏览器缓存、忘了重启 Apache、或者开发机本地测试正常,一上生产环境又因为服务器 PHP 版本低(比如 5.3)不支持某些函数而静默失败 —— 这些细节比编码本身更容易卡住人。

















