服务器升级后CakePHP无法发送邮件的排查求助
环境与配置背景
原正常运行环境
- 服务器系统:CentOS 6.10
- Web服务:Apache 2.2.15
- PHP版本:5.3.3
- CakePHP版本:2.7.7
原邮件配置(app/Config/email.php):
public $smtp = array( 'host' => 'startls://mail.xxx.com', 'port' => 587, 'username' => 'xxx@xxx', 'password' => 'xxx', 'transport' => 'Smtp', );
此环境下邮件可正常发送。
升级后环境
- 服务器系统:CentOS 7.x
- Web服务:Apache 2.4.47
- PHP版本:7.0.33
升级后邮件无法发送且无报错,修改后的邮件配置:
public $smtp = array( 'host' => 'mail.xxx.com', 'port' => 587, 'username' => 'xxx@xxx', 'password' => 'xxx', 'transport' => 'Smtp', 'tls' => true );
测试代码与错误信息
CakePHP测试控制器
创建MailTestController测试邮件发送:
<?php App::uses('AppController', 'Controller'); App::uses('CakeEmail', 'Network/Email'); class MailTestController extends AppController { public function index() { $this->autoRender = false; $receiver = 'xxx'; App::uses('CakeEmail', 'Network/Email'); $email = new CakeEmail(); $email->config('smtp'); $from_email_address = 'xxx@xxx'; $email->from($from_email_address); $email->to($receiver); $email->subject('MAIL TESTING'); $message = "mail sending test"; if (!$email->send($message)) { CakeLog::write('debug', $this->Email->smtpError); } } }
执行后出现错误:
Error: [SocketException] SMTP server did not accept the connection or trying to connect to non TLS SMTP server using TLS.
PHPMailer测试脚本
使用相同SMTP信息编写PHPMailer脚本,在升级后服务器执行php index.php可正常发送邮件:
<?php //导入PHPMailer类到全局命名空间 //这些必须在脚本顶部,不能放在函数内 use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\SMTP; use PHPMailer\PHPMailer\Exception; //加载Composer的自动加载器 require 'vendor/autoload.php'; //创建实例;传入`true`启用异常处理 $mail = new PHPMailer(true); try { //服务器设置 $mail->SMTPDebug = SMTP::DEBUG_SERVER; //启用详细调试输出 $mail->isSMTP(); //使用SMTP发送 $mail->Host = 'mail.xxx.com'; //设置要连接的SMTP服务器 $mail->SMTPAuth = true; //启用SMTP认证 $mail->Username = 'xxx@xxx'; //SMTP用户名 $mail->Password = 'xxx'; //SMTP密码 $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; //启用STARTTLS加密 $mail->Port = 587; //要连接的TCP端口;如果设置了`SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`则使用587 //收件人 $mail->setFrom('xxx@xxx', 'Mailer'); $mail->addAddress('xxx', 'John Doe'); //添加收件人 //内容 $mail->isHTML(true); //设置邮件格式为HTML $mail->Subject = 'Here is the subject'; $mail->Body = 'This is the HTML message body <b>in bold!</b>'; $mail->AltBody = 'This is the body in plain text for non-HTML mail clients'; $mail->send(); echo '邮件已发送'; } catch (Exception $e) { echo "邮件发送失败。错误信息: {$mail->ErrorInfo}"; }
问题
邮件服务商确认已开放587端口,PHPMailer可正常发送,但CakePHP应用发送失败,需排查应用服务器或邮件服务器的哪些内容?
排查方向
应用服务器端要查的点
CakePHP的TLS处理逻辑
CakePHP 2.7.7的SMTP传输组件和PHPMailer的TLS实现存在差异,原配置里的startls://前缀在PHP7环境下可能未被正确识别,后来添加的tls => true也未必触发了正确的STARTTLS流程。可以直接查看Cake/Network/Email/SmtpTransport.php源码,确认TLS启用的代码在PHP7环境下是否正常运行。PHP扩展和配置的差异
- 确认Web环境的PHP是否开启
openssl扩展:在浏览器中运行phpinfo()页面搜索openssl,对比CLI下php -m | grep openssl的结果——PHPMailer可用不代表Apache的PHP环境也开启了该扩展。 - 检查
allow_url_fopen配置:Web端PHP的该配置如果关闭,可能影响CakePHP的SMTP连接。 - 升级CakePHP补丁:2.7.7虽支持PHP7.0,但可能存在针对PHP7的SMTP bug,可升级到2.7.x系列的最新版本测试。
- Apache与CLI环境的区别
- SELinux限制:CentOS7默认开启SELinux,可能禁止Apache进程发起SMTP连接。临时执行
setenforce 0关闭SELinux测试,若能发送则配置永久规则:setsebool -P httpd_can_sendmail on。 - 环境变量差异:Apache运行的PHP和CLI的环境变量可能不同(如SSL库路径),导致加密连接失败。可在测试控制器中输出phpinfo()内容,与CLI下
php -i的结果对比排查。
- 日志排查
- 原测试代码中的
$this->Email->smtpError无效,因为使用的是CakeEmail而非旧版EmailComponent,应改为$email->transport()->smtpError获取真实错误信息并写入日志。 - 查看Apache错误日志
/var/log/httpd/error_log,检查是否存在连接超时、SSL握手失败等相关记录。
邮件服务器端要查的点
TLS版本兼容问题
CakePHP 2.7.7可能默认使用旧版TLS协议(如TLS1.0),但CentOS7的OpenSSL可能禁用了旧协议,导致与邮件服务器握手失败。可咨询服务商确认邮件服务器支持的TLS版本,或修改SmtpTransport代码强制指定兼容的协议版本。HELO/EHLO验证
部分邮件服务器对HELO字段格式要求严格,CakePHP默认发送的HELO内容可能不符合要求,可在配置中添加client参数指定主机名:
public $smtp = array( //...其他配置 'client' => '你的服务器主机名' );
- 连接限制
邮件服务器可能对同一IP的连接频率、来源有限制,比如Apache进程的连接被判定为恶意请求,可请求服务商查看邮件服务器日志,确认是否有拒绝该IP连接的记录。
内容的提问来源于stack exchange,提问作者Cloud

