CodeIgniter邮件发送错误处理:SMTP服务器重启时实现自动重连并重发邮件
解决CodeIgniter邮件发送中SMTP连接被强制关闭的重试问题
这个errno=10054错误太常见了——说白了就是SMTP服务器突然断开了连接(比如服务器重启、连接超时或者负载过高踢掉了你的连接)。你的原代码没处理这种突发情况,遇到错误就直接卡在当前邮件的失败分支了。咱们可以通过添加重试机制+每次重试时重新初始化邮件实例来解决,因为原来的邮件类实例已经持有失效的连接,必须重新创建新连接才行。
下面是修改后的健壮版代码,我会在后面拆解关键逻辑:
$config = array( 'protocol' => 'smtp', 'smtp_host' => 'example.com', 'smtp_port' => 587, 'smtp_user' => '******', 'smtp_pass' => '***', 'priority' => 1, 'smtp_timeout' => '30', 'mailtype' => 'html', 'charset' => 'utf-8', 'wordwrap' => true ); // 自定义最大重试次数,根据你的需求调整 $maxRetries = 3; $totalSent = 0; foreach($res2 as $email) { $retryCount = 0; $sentSuccessfully = false; // 循环重试,直到发送成功或用完重试次数 while ($retryCount < $maxRetries && !$sentSuccessfully) { try { // 关键1:每次重试都清空并重新初始化邮件类 $this->email->clear(true); // 清空所有邮件数据+关闭旧连接 $this->email->initialize($config); // 重新加载配置,创建新SMTP连接 // 组装邮件内容 $this->email->from($fromemail, $fromname); $this->email->to($email); $this->email->subject('Dummy Email'); $body = $emailDesign2; $this->email->message($body); // 关键2:抑制fwrite的警告错误,避免脚本直接终止 if (@$this->email->send()) { echo "Mail Sent to {$email}<br/>"; $totalSent++; $sentSuccessfully = true; } else { // 获取详细错误信息,方便排查问题 $errorDetail = $this->email->print_debugger(); echo "Attempt {$retryCount+1} failed for {$email}: {$errorDetail}<br/>"; $retryCount++; // 重试前加短暂延迟,给服务器恢复时间 sleep(2); } } catch (Exception $e) { // 捕获极端情况下的异常,让脚本更稳定 echo "Exception on attempt {$retryCount+1} for {$email}: {$e->getMessage()}<br/>"; $retryCount++; sleep(2); } } if (!$sentSuccessfully) { echo "All {$maxRetries} attempts failed for {$email}<br/>"; } } echo "Total mails sent: {$totalSent}<br/>";
关键逻辑拆解
$this->email->clear(true):这个方法不仅会清空邮件的收件人、内容等数据,还会关闭当前的SMTP连接(参数true的作用),确保下次初始化是全新的连接,不会复用已经失效的旧连接。- 重新初始化邮件类:每次重试都调用
initialize($config),相当于重新和SMTP服务器握手建立新连接,这是解决连接被强制关闭的核心。 - 重试循环+延迟:设置
maxRetries避免无限重试,每次失败后sleep(2)给服务器一点恢复时间,也避免频繁请求被服务器拉黑。 - 错误抑制与日志:用
@抑制fwrite的警告(不然可能直接终止脚本),同时通过print_debugger()获取详细错误日志,方便排查是连接问题还是邮件内容本身的问题。
额外小建议
- 可以开启
smtp_keepalive:如果你的邮件列表很长,开启这个能减少频繁建立连接的开销,但遇到服务器重启时还是需要重试机制兜底。 - 生产环境别用
echo输出:建议把日志写到文件里,用CodeIgniter自带的日志类($this->log->write_log())会更规范。 - 批量发送加间隔:短时间发大量邮件容易被服务器判定为垃圾邮件,循环里可以加个1-2秒的延迟,降低风险。
内容的提问来源于stack exchange,提问作者SAGAR BHISE
相关产品推荐
相关产品推荐

