ThinkPHP 6 的 SMTP 配置必须写在 config/mail.php 中才生效,.env 文件中的 MAIL_HOST 等变量需通过 env() 函数显式读取,否则无效;且需注意加密方式与端口匹配、授权码使用及 OpenSSL 扩展启用。

SMTP配置写在哪个文件里才生效
ThinkPHP 6 的邮件发送配置不走 .env 文件默认支持,必须显式写进 config/mail.php。如果你只改了 .env 里的 MAIL_HOST 等变量,但没在 mail.php 中用 env() 读取,那全无效。
正确做法是:打开 config/mail.php,确保 'host'、'username'、'password' 等字段直接或间接取自环境变量:
return [
'default' => 'smtp',
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'host' => env('MAIL_HOST', 'smtp.qq.com'),
'port' => env('MAIL_PORT', 587),
'username' => env('MAIL_USERNAME', ''),
'password' => env('MAIL_PASSWORD', ''),
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'test@example.com'),
'name' => env('MAIL_FROM_NAME', 'Test'),
],
],
],
];
- ThinkPHP 6.1+ 使用的是
symfony/mailer底层,不认旧版thinkphp/think-mail的配置方式 -
MAIL_ENCRYPTION填ssl时端口通常是465,填tls时对应587,混用会卡在连接阶段,错误信息类似Connection could not be established with host smtp.qq.com - QQ 邮箱、163 邮箱等要求开启 SMTP 并生成「授权码」,不是登录密码;授权码要填进
MAIL_PASSWORD,不是账号密码
发信失败时先看哪几个关键报错
常见失败不是代码写错,而是网络或认证环节断在底层。别急着改逻辑,先盯住异常堆栈最顶上那一行:
-
Expected response code 250 but got code "535"→ 认证失败,大概率MAIL_USERNAME或MAIL_PASSWORD错,或没开 SMTP 授权 -
Connection timed out→ DNS 解析失败或防火墙拦截,可试telnet smtp.qq.com 587看通不通 -
Failed to authenticate on SMTP server→ 和第一个类似,但有时是加密方式不匹配,比如 QQ 邮箱强制ssl+465,你配了tls+587 -
Unable to connect with TLS→ OpenSSL 扩展未启用,或 PHP 版本太低(symfony/mailer要求 PHP >= 8.0)
测试配置是否生效的最小验证代码
别用业务逻辑测邮件,写个独立脚本直连发信流程:
立即学习“PHP免费学习笔记(深入)”;
<?php
require __DIR__ . '/vendor/autoload.php';
$app = new \think\App();
$mailer = $app->mailer->getMailer();
try {
$message = (new \Symfony\Component\Mime\Email())
->to('your@email.com')
->subject('TP6 SMTP test')
->text('This is a test.');
$mailer->send($message);
echo "OK\n";
} catch (\Exception $e) {
echo "ERROR: " . $e->getMessage() . "\n";
}
- 运行前确认
config/mail.php已加载(可通过var_dump(config('mail'))检查值是否正确) - 如果提示
Class 'think\App' not found,说明没走框架启动流程,此时应改用new \Symfony\Component\Mailer\Mailer(...)手动构造,绕过 ThinkPHP 容器 - 测试时关掉队列异步发送,确保是同步执行,避免日志里看不到真实错误
多环境 SMTP 切换容易漏掉的点
开发用本地 MailHog,生产用腾讯企业邮箱,测试用 163 —— 这种场景下光靠 .env 不够,还得检查配置加载顺序:
-
config/mail.php是硬编码入口,所有环境都走它;不要在其中写if (App::isProduction()) { ... },会破坏配置缓存机制 - 真正该做环境区分的地方是
.env文件本身:.env.production、.env.testing,再配合php think optimize:config生成对应缓存 - 线上部署后记得清空
runtime/config/目录,否则旧配置缓存还在,改了.env也无效 - 某些云服务器(如阿里云 ECS)默认屏蔽 25/465/587 端口,需提工单解封,这不是代码问题,但最容易被当成“配置不对”反复折腾
SMTP 配置真正卡住人的,从来不是语法,而是授权、端口、加密方式、网络策略这四层嵌套验证。每层都得单独确认,不能假设上一层过了,下一层就自动 OK。


















