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