Yii2的邮件发送失败怎么排查_开启调试和日志记录【案例】

5次阅读

邮件发送失败时应优先检查 swift_transportexception 的 getprevious()->getmessage() 获取底层错误,确认 usefiletransport 与 transport 配置互斥、transport 参数完整、php openssl/sockets 扩展已启用,并排除 selinux、防火墙及云安全组的网络限制。

Yii2的邮件发送失败怎么排查_开启调试和日志记录【案例】

邮件发送失败时先看 Swift_TransportException 的具体错误信息

yii2 默认用 Swiftmailer 发邮件,失败时抛出的异常类型基本就是 Swift_TransportException,但它的 getMessage() 往往只显示“Connection could not be established with host”,真正有用的线索藏在 getTraceAsString() 或更关键的 getPrevious()->getMessage() 里——比如底层是 fsockopen() 超时,还是 TLS 握手失败。

实操建议:

  • try...catch 块中捕获 Swift_TransportException,并打印 $e->getPrevious() ? $e->getPrevious()->getMessage() : $e->getMessage()
  • 临时在 config/web.phplog 组件里加一条 ['class' => 'yiilogFileTarget', 'levels' => ['Error'], 'categories' => ['yiiswiftmailerMailer']],让所有 Mailer 错误进日志
  • 别只盯着 mail() 函数返回值,Yii2 默认走 SMTP,mail() 根本没调用

SMTP 配置里 useFileTransporttransport 别同时设错

开发环境常把 useFileTransport 设为 true 来避免真发信,但它和 transport 是互斥逻辑:设了 useFileTransport = true,Yii2 就直接跳过整个 SMTP 初始化,transport 配置再全也无效;反过来,如果忘了关 useFileTransport 却又在生产环境用文件传输,邮件就静默消失,连错误都不报。

实操建议:

  • 检查 config/main-local.php(开发)和 config/main.php(生产)是否各自覆盖了 useFileTransport,且值符合当前环境预期
  • transport 配置必须完整包含 classhostusernamepasswordportencryption,缺任意一项都可能静默失败
  • 腾讯企业邮箱要设 encryption => 'tls',而 Gmail 用 'ssl',端口也得对应(587 vs 465),写反了会卡在 CONNECTING

PHP 的 opensslsockets 扩展没启用会导致连接直接被拒

SwiftMailer 依赖 PHP 底层 socket 连接 SMTP 服务器,如果 php.ini 里禁用了 extension=opensslextension=sockets,哪怕配置全对,也会在 Swift_Transport_StreamBuffer->initialize() 阶段抛出 Call to undefined function openssl_encrypt() 或类似致命错误,但 Yii2 日志里可能只记成 “Failed to authenticate on SMTP server”。

实操建议:

  • 运行 php -m | grep -E 'openssl|sockets' 确认扩展已加载
  • 在控制器里加一行 var_dump(function_exists('fsockopen'), extension_loaded('openssl')); 快速验证
  • docker 环境容易漏装扩展,Alpine 镜像需额外 apk add php7-openssl php7-socketsubuntu 则是 apt-get install php-openssl php-sockets

防火墙、SELinux、云厂商安全组这三层网络限制最容易被忽略

本地能 telnet 通 SMTP 端口,不等于 PHP 进程能连——尤其是 centos 开启 SELinux 后,默认禁止 httpd/nginx 子进程发起 outbound 连接;阿里云/腾讯云的安全组也可能只放行 80/443,忘了开 587 或 465;甚至某些 IDC 会主动拦截发信端口防垃圾邮件。

实操建议:

  • sudo -u www-data php -r "fsockopen('smtp.qq.com', 587, $errno, $errstr, 5) && print 'OK';" 模拟 PHP 进程身份测试(注意替换用户和域名)
  • CentOS 下执行 setsebool -P httpd_can_network_connect 1 放行网络连接
  • 云服务器上检查安全组规则是否双向放行,不只是入站——出站规则同样要允许目标 SMTP IP 和端口

真正卡住的地方,往往不是代码写错了,而是 PHP 进程被系统或网络策略拦在了第一步连接上。调试时先确认它能不能发出第一个 TCP SYN 包,比翻配置快得多。

text=ZqhQzanResources