问题
[Bug] 后台 SMTP 测试邮件通过 `_include()` 加载过期 SMTP 缓存,导致与注册邮件配置不一致
环境
### 环境
- XiunoX 1.1.1
- PHP 8.2
- SMTP:QQ 邮箱,SMTPS / 465
- 仅配置了 1 条 SMTP 记录
### 现象
注册验证码邮件可以正常发送,但后台「SMTP 设置 → 发送测试邮件」始终失败,提示:
```text
SMTP Error: Could not authenticate.
SMTP server error: QUIT command failed
SMTP 服务、端口、SSL、授权码和服务器网络均正常。使用相同的 SMTP 配置通过 PHPMailer 直接认证并完整发送邮件均成功。
根因
注册邮件和后台测试邮件读取 SMTP 配置的方式不一致。
注册邮件
注册流程通过 xn_smtp_get() 读取:
$confile = APP_PATH . 'conf/smtp.conf.php';
$smtplist = include $confile;
因此读取的是最新保存的配置:
conf/smtp.conf.php
注册邮件可以正常发送。
后台测试邮件
后台测试接口位于:
admin/route/setting.php
原代码:
$smtplist = include _include(APP_PATH.'conf/smtp.conf.php');
_include() 是插件源码编译缓存机制。它会将文件编译到:
tmp/conf_smtp.conf.php
且只在缓存文件不存在、DEBUG > 1 或 cache_disable 启用时重新生成:
if(!is_file($tmpfile) || DEBUG > 1 || !empty($conf['cache_disable'])) {
// compile source to tmp file
}
因此后台 SMTP 测试可能读取历史缓存,而不是刚在后台保存的新 SMTP 配置。
本次实际排查结果:
文件 | SMTP 用户名状态 |
|---|---|
| 当前正确的 QQ 邮箱账号 |
| 历史用户名(非当前邮箱账号) |
两份配置中的授权码字段仍然存在,但由于后台测试使用了旧用户名,QQ SMTP 拒绝认证,最终报 Could not authenticate。QUIT command failed 是认证失败后 PHPMailer 关闭 SMTP 会话时附带的次级错误,不是根因。
为什么只有测试邮件失败
注册/找回密码等邮件:直接读取
conf/smtp.conf.php,所以正常;后台测试邮件:通过
_include()使用tmp/conf_smtp.conf.php,所以使用了历史配置并失败。
建议修复
SMTP 凭据属于运行时配置,不应该经过插件模板/源码编译缓存。
将:
$smtplist = include _include(APP_PATH.'conf/smtp.conf.php');
替换为:
$smtplist = include APP_PATH.'conf/smtp.conf.php';
并建议检查其它运行时配置文件是否也被 _include() 包装加载,避免出现保存后仍使用旧配置的情况。
补充:相关的错误处理问题
xiunophp/xn_send_mail.func.php 中:
return xn_error(-1, $error_msg);
但 xn_error() 默认返回 FALSE,会使调用方拿不到 $error_msg 字符串。建议改为:
xn_error(-1, $error_msg);
return $error_msg;
同时后台测试页可回退读取全局 $errstr,防止错误信息被丢失。
临时解决方法
删除以下缓存文件后重新测试:
tmp/conf_smtp.conf.php
tmp/admin_route_setting.php
但根本修复应是后台测试接口直接读取 conf/smtp.conf.php。
