最简安装是composer require phpmailer/phpmailer,自动安装v6.x并配置PSR-4加载;v5已废弃且不兼容PHP 8+,混用命名空间会导致Class 'PHPMailer' not found。

直接用 composer require 装邮件扩展,关键不是“能不能装”,而是“装哪个、怎么配、装完为什么没反应”。不同扩展对 PHP 版本、依赖、DSN 格式和错误静默行为差异极大,硬敲命令不检查上下文,90% 的失败都卡在第一步之后。
PHPMailer:require 后要手动加载类,且 SMTP 配置易错
这是最轻量、兼容性最强的选择,适合非框架项目或需精细控制连接参数的场景。但它的配置全靠代码写死,稍不注意就发不出信。
-
composer require phpmailer/phpmailer成功后,必须在使用处use PHPMailer\PHPMailer\PHPMailer;和use PHPMailer\PHPMailer\Exception;,否则new PHPMailer(true)会报类未找到 -
$mail->SMTPSecure值必须与$mail->Port匹配:465 对应PHPMailer::ENCRYPTION_SMTPS(旧版写'ssl'),587 对应PHPMailer::ENCRYPTION_STARTTLS(旧版写'tls')——写反了会连不上,但只抛出模糊的“Could not connect to SMTP host” - Gmail 必须用应用专用密码(App Password),不是登录密码;163/qq 邮箱同理,要用“授权码”,且确保邮箱已开启 SMTP 服务
- 调试时把
$mail->SMTPDebug = 2(不是 0 或 1),才能看到真实的握手日志,否则连 TLS 失败都看不到原因
Symfony Mailer:require 失败常因 PHP 版本或冲突,DSN 空则静默丢信
它更现代、可插拔,但对环境更挑剔。装不上不是命令错了,而是约束没满足;装上了却发不出,大概率是 MAILER_DSN 没生效或格式错。
- 运行
php -v确认 PHP ≥ 8.1 ——symfony/mailer:^6.4强制要求,低于此版本要么升级 PHP,要么改用symfony/mailer:^5.4 - 执行
composer why-not symfony/mailer:^6.4查具体冲突包,比删vendor重装快得多;常见冲突来自旧版symfony/http-foundation或symfony/console -
MAILER_DSN必须带 scheme:smtp://user:pass@smtp.163.com:465?encryption=ssl,漏掉smtp://或写成smtp:会导致 Transport 构建失败并 fallback 到nulltransport —— 表现为调用$mailer->send()后无报错、无日志、无邮件 - 在非 Symfony 项目里手动构建,别自己 new SMTPTransport,要用
Transport::fromDsn($_ENV['MAILER_DSN']),否则 TLS 参数、连接池、重试逻辑全丢了
Laravel 项目别单独 require symfony/mailer
Laravel 9+ 已内置封装好的 Mailer,额外 composer require symfony/mailer 不仅多余,还会引发服务提供者重复注册、MailerInterface 绑定冲突等问题。
- 只需配置
.env:设置MAIL_MAILER=smtp,再填MAIL_HOST、MAIL_PORT、MAIL_USERNAME、MAIL_PASSWORD、MAIL_ENCRYPTION - 发信直接用
Mail::to('x@y.z')->send(new WelcomeMail()),底层自动适配symfony/mailer实例 - 如果想用 DSN 方式(比如对接 SendGrid),改
MAIL_MAILER=smtp为MAIL_MAILER=sendgrid,并确保已composer require symfony/sendgrid-mailer,否则 DSN 解析失败也会静默 fallback
最常被忽略的一点:所有扩展在开发环境默认不发真实邮件,但没人告诉你它们“假装成功”的机制完全不同——PHPMailer 抛异常,Symfony Mailer 降级到 null transport,Laravel 则可能走 log driver。不主动查日志、不设断点、不验证 MAILER_DSN 是否真被读取,就永远卡在“为什么没收到”。











