PHP内置mail()函数不可靠,因依赖本地sendmail、易被拒收且不支持附件/HTML;PHPMailer通过SMTP认证和TLS加密解决这些问题,需用App Password、正确配置端口,并注意安全防护与错误捕获。

为什么不用内置的 mail() 函数?
直接调用 PHP 的 mail() 函数看似最快,但实际几乎不可靠:它依赖本地 sendmail 配置,多数共享主机禁用,Gmail 等 SMTP 服务会拒收无认证、无 TLS 的裸信,且无法发附件、HTML 内容或自定义发件人头。用 mail() 发出的邮件大概率进垃圾箱,或根本发不出。
所以「快速实现」不等于「写最少代码」,而是「绕过配置陷阱、一次跑通」——PHPMailer 正是为此设计的。
Composer 安装与最小可用配置
确保已安装 Composer,执行:
composer require phpmailer/phpmailer
之后在脚本中引入并初始化(注意路径和命名空间):
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
立即学习“PHP免费学习笔记(深入)”;
require 'vendor/autoload.php'; use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\SMTP; $mail = new PHPMailer(true); // true 启用异常模式 $mail->isSMTP(); $mail->Host = 'smtp.gmail.com'; $mail->SMTPAuth = true; $mail->Username = 'your@gmail.com'; $mail->Password = 'your-app-password'; // ⚠️ 不是邮箱密码,是 Google App Password $mail->SMTPSecure = PHPMailer::ENCRYPTION_TLS; $mail->Port = 587;
-
SMTPSecure和Port必须匹配:TLS + 587 或 SSL + 465,混用会导致连接超时 - Gmail 账户需开启「两步验证」后生成「App Password」,直接填登录密码会报
SMTP Error: Could not authenticate - 国内服务器直连 Gmail 可能被阻断,可临时换用腾讯企业邮箱(
smtp.exmail.qq.com,端口 465/SSL)测试连通性
发 HTML 邮件、附件和常见报错处理
设置内容类型和编码后,HTML 邮件和附件只需几行:
$mail->setFrom('your@gmail.com', 'Your Name');
$mail->addAddress('to@example.com');
$mail->Subject = '测试邮件';
$mail->isHTML(true);
$mail->Body = '<h2>你好</h2><p>这是一封 <strong>HTML</strong> 邮件</p>';
$mail->AltBody = '这是一封纯文本备选内容';
// 添加附件(路径必须是服务器上的绝对路径或相对 vendor 目录的路径)
$mail->addAttachment('/path/to/file.pdf');
$mail->send();
- 如果报
Could not instantiate mail function:说明没调用isSMTP(),误用了 PHP 内置 mail() 回退机制 - 如果报
Connection timed out:检查防火墙、云服务器安全组是否放行 587/465 端口,或尝试切换网络环境(如本地开发机 vs 阿里云 ECS) -
addAttachment()不支持 HTTP URL,必须传本地文件路径;若要发远程文件,先用file_get_contents()拉取再用addStringAttachment()
生产环境必须加的防护点
上线前漏掉这些,轻则被滥发邮件封号,重则触发 SMTP 服务商风控限流:
- 所有用户输入的收件人地址必须用
$mail->addAddress()单独校验,禁止拼接进Body或直接传入addAddress($user_input)—— 否则可能被注入额外收件人(to@example.com, attacker@evil.com) - 启用
$mail->SMTPOptions = ['ssl' => ['verify_peer' => false]];是危险操作,仅用于调试;生产环境必须保持证书校验开启 - 避免在循环里反复 new PHPMailer 实例,复用对象并调用
$mail->clearAddresses()和$mail->clearAttachments()重置状态更稳妥
最易被忽略的是错误捕获方式:必须用 try/catch 包裹 send(),否则 SMTP 认证失败等异常会直接崩掉整个请求,而不是返回友好的提示。


















