先把这个结论砸在桌面上:PHP 项目发通知邮件,别碰内置的 mail() 函数,老老实实上 PHPMailer 直连 SMTP。否则邮件大概率被扔进垃圾箱、被对方服务器直接拒收,甚至连接都连不上——这真不是代码写错了,是协议和认证层面压根儿没到位。

PHPMailer 配置 SMTP 的关键参数组合
要跑通 PHPMailer,核心就四组参数,每一组都得和服务商的要求严丝合缝。错一个,你看到的要么是 SMTP connect() failed,要么是 535 Authentication failed:
Host必须精准:QQ 邮箱用smtp.qq.com,163 用smtp.163.com,Gmail 用smtp.gmail.com,别想当然写个smtp.qq.com却连到 163 的端口。Port和SMTPSecure必须成对出现:465 端口配'ssl',587 端口配'tls'。注意,'tls'不是'starttls',写错了直接报错。Username必须是完整邮箱地址,比如user@qq.com,别只写个user糊弄。Password不是你登录邮箱的密码,而是平台专门生成的「应用专用密码」:QQ 叫授权码,Gmail 叫应用专用密码,163 叫客户端授权码,16 位且区分大小写。填错了就等着看SMTP Error: Could not authenticate.吧。
这里有个常见坑:SMTP Error: Could not authenticate. 十有八九是 Username 和 setFrom() 不一致,或者密码直接填了登录密码。别问我怎么知道的,踩过的人太多了。
中文内容与 HTML 邮件必须显式设置
不设编码和格式,中文就会变成乱码,HTML 会被当成纯文本原样输出:
$mail->CharSet = 'UTF-8':强制字符集,标题和正文里的中文才能正常显示。$mail->isHTML(true):启用 HTML 解析,否则加粗会直接显示成文字,而不是加粗效果。- 主题里如果含中文,不需要额外 base64 编码,只要
CharSet设对了,它自己就能处理。
容易踩的坑:本地测试时看到 HTML 源码,八成是漏了 isHTML(true);主题显示成 “=?UTF-8?B?…” 这种乱码,是因为没设 CharSet,不是编码逻辑错了。
异常捕获必须带 $mail->ErrorInfo
别只靠 if ($mail->send()) 判断是否成功,失败时一定要立刻看到具体原因。正确的做法是用 try-catch 包住发送逻辑,在 catch 块里打印 $mail->ErrorInfo——这个信息比 PHP 的报错要精准十倍。
常见的返回值举例:
SMTP server error: AUTH command failed→ 认证失败,检查授权码和用户名。Connection timed out→ 端口不通,检查服务器防火墙或者端口号。Could not instantiate mail function→ 多半是 openssl 扩展没启用。
性能方面不用担心:每次发邮件都新建 PHPMailer 实例完全没问题,但别在循环里反复 require 'vendor/autoload.php'。Lara vel 等框架已经封装好了连接复用,不用手动优化。
Windows 本地开发想兼容旧代码?慎用 FakeSendmail
如果业务代码里全是 mail() 调用,实在不想改,FakeSendmail 是唯一可行的路径,但限制多到让人头疼:
- 只在 Windows 下稳定,Linux/macOS 基本不可靠。
sendmail_path在php.ini中必须是绝对路径,而且要带引号和-t参数,比如sendmail_path = "C:\xampp\sendmail\sendmail.exe -t"。sendmail.ini里smtp_server、auth_username、auth_password全要填,而且smtp_port和加密方式必须和服务商一致。- 每次改完配置,必须重启 Apache/Nginx + PHP-FPM,否则不生效。
真正容易卡住的地方是 openssl 和 sockets 扩展——很多新手折腾半天,最后发现是 extension=php_openssl.dll 没启用,或者路径写错了,却一直以为是邮件代码的问题。