我在 PHP 7.0 上使用最新的 PHPMailer 5.2.24(问题与旧版本相同)。
使用 Exchange 2016 通过 SMTP 发送邮件。大约 95% 的邮件按预期工作,但只要 Exchange 对最终 DATA END 命令的 250 响应持续时间超过 30 秒,流似乎就会中止。
PHPMailer 中的超时设置为 300,在日志中我可以确认超时不是这里的问题。
事实上,据我所知,所有邮件都已成功发送(我在 30 个案例中的大约 30 个中确认了它)。
$this->mailer->isSMTP();
$this->mailer->Timeout = 300;
$this->mailer->Host = 'mail.myhost.com';
$this->mailer->SMTPAuth = true;
$this->mailer->Username = 'Domain\\Username';
$this->mailer->Password = '*****';
$this->mailer->SMTPSecure = 'tls';
$this->mailer->Port = 587;
低级日志示例:(我在 class.smtp.php 的 get_lines() 中添加了 2 个自定义调试输出,以显示 fgets() 返回 false 并显示 stream_get_meta_data())
2017-08-23 13:46:05 Level 1; message: CLIENT -> SERVER: .
2017-08-23 13:46:35 Level 4; message: SMTP -> get_lines(): $data is ""
2017-08-23 13:46:35 Level 4; message: SMTP -> get_lines(): $str === false
2017-08-23 13:46:35 Level 4; message: SMTP -> [timed_out => false, blocked => 1, eof => 1, stream_type => tcp_socket/ssl, mode => r+, unread_bytes => 0, seekable => false]
2017-08-23 13:46:35 Level 2; message: SERVER -> CLIENT:
2017-08-23 13:46:35 Level 1; message: SMTP ERROR: DATA END command failed:
在其他响应速度超过 30 秒的情况下,它看起来像:
2017-08-23 23:25:02 Level 1; message: CLIENT -> SERVER: .
2017-08-23 23:25:28 Level 4; message: SMTP -> get_lines(): $data is ""
2017-08-23 23:25:28 Level 4; message: SMTP -> get_lines(): $str is "250 2.6.0 <...> [InternalId=10677288697896, Hostname=myhost] 32443 bytes in 26.353, 1,202 KB/sec Queued mail for delivery"
2017-08-23 23:25:28 Level 2; message: SERVER -> CLIENT: 250 2.6.0 <...> [InternalId=10677288697896, Hostname=myhost] 32443 bytes in 26.353, 1,202 KB/sec Queued mail for delivery
2017-08-23 23:25:28 Level 1; message: CLIENT -> SERVER: QUIT
那么能有什么
$str = fgets($this->smtp_conn, 515);
当它不是流超时而不是 php 运行时超时时,导致在恰好 30 秒后(执行后 30 秒,而不是自脚本启动后)失败。(这里没有抛出异常,我从原始 PHPMailer 代码中的 fgets() 中删除了 @ 以确认这一点)
脚本在没有 max_execution_time 的情况下运行。
我的 Exchange 管理员不知道是什么导致了这种情况,我也没有开始的意义,因为我什至不知道流在哪里中断 - PHP、Webserver、Exchange,介于两者之间?
任何想法我还能检查什么或什么可能导致这种情况?