如何正确配置 PHPMailer - 目前在发送电子邮件时出错

How to properly configure PHPMailer - currently getting errors when sending emails

我无法使向客户发送发票的脚本可靠地工作。有一段时间,脚本运行得非常好,我们没有收到任何错误。但是,最近,我们的一位客户通知我们,他们在下订单后收到了错误输出,我已将其缩小到发送附有发票的电子邮件的脚本部分。

我们得到的错误是:

Warning:stream_socket_enable_crypto(): SSL operation failed with code 1. 
OpenSSL Error messages: error:14090086:SSL 
routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in 
path/to/phpmailer/phpmailer/class.smtp.php on line 355

当时我使用的 PHPMailer 配置是:

// enable SMTP debugging.
$mail->SMTPDebug = 0;
//Set PHPMailer to use SMTP
$mail->isSMTP();
//Set SMTP host name.
$mail->Host = "smtp.netregistry.net";
$mail->SMTPAuth = true;
// Username and Password;
$mail->Username = $email;
$mail->Password = $email_pw;
$mail->Port = 25;
// Message information bellow

根据一些研究,我发现端口 25 经常被阻止以试图防止垃圾邮件,它也被 ISP 使用(正确吗?)。所以我重新阅读了 NetRegistry 的邮件服务器文档,并与他们的支持进行了交谈。如果我想使用 SSL,我需要使用端口 465,否则我应该使用端口 587。

因此,在我使用 XAMPP 的本地 windows 机器上,我尝试使用以下配置:

// Server Settings
$mail->SMTPDebug = 2;
$mail->isSMTP();
$mail->Host = "smtp.netregistry.net";
$mail->SMTPAuth = true;
$mail->Username = $email;
$mail->Password = $email_pw;
$mail->SMTPSecure = "ssl";
$mail->Port = 465;

所有这些都放在一个 try catch 块中,我在其中根据我读到的有关 PHPMailer 如何处理错误和警告的内容捕获异常。

这在我的本地机器上工作得很好,我能够使用这些设置可靠地定期发送电子邮件。然而,当我将它上传到远程主机时,它没有发送任何电子邮件(自从我试过这个已经 4 天了),并且没有产生任何错误输出,尽管 catch 块回显了一个表明错误的字符串发生了。我已经 运行 将 SMTPDebug 参数设置为 2 的不同配置,这给了我以下内容。

当运行使用我的原始设置(端口 25)在远程主机上运行脚本失败时:

2019-03-25 21:10:12 SERVER -> CLIENT: 220 smtp.netregistry.net
2019-03-25 21:10:12 CLIENT -> SERVER: EHLO website.com.au
2019-03-25 21:10:12 SERVER -> CLIENT: 250-smtp-1.servers.netregistry.net Hello apache.netregistry.net [202.124.241.203]
                                      250-SIZE 52428800
                                      250-8BITMIME
                                      250-PIPELINING
                                      250-AUTH LOGIN PLAIN CRAM-MD5
                                      250-STARTTLS
                                      250 HELP
2019-03-25 21:10:12 CLIENT -> SERVER: STARTTLS
2019-03-25 21:10:12 SERVER -> CLIENT: 220 TLS go ahead
<br />
<b>Warning</b>:  stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed in <b>\path\to\vendor\phpmailer\phpmailer\class.smtp.php</b> on line <b>355</b><br />
2019-03-25 21:10:13 SMTP Error: Could not connect to SMTP host.
2019-03-25 21:10:13 CLIENT -> SERVER: QUIT
2019-03-25 21:10:13 SERVER -> CLIENT: �������A�;�   MNb���ʋ�]+�
                                      ���M�m3����Kz����f,�b�����<��t�٢��i�ޜ�w�k��PC����c�g�?���I��"r
                                      ��1���$����kKA�L�G����� ��z�<tC�� �s� BP����Tu�xڼH5����ɧ`���e��ڍF������i[�ql@����Gh�D=[���gh������pV����}������������P
2019-03-25 21:10:13 SMTP ERROR: QUIT command failed: �������A�;�    MNb���ʋ�]+�
                                      ���M�m3����Kz����f,�b�����<��t�٢��i�ޜ�w�k��PC����c�g�?���I��"r
                                      ��1���$����kKA�L�G����� ��z�<tC�� �s� BP����Tu�xڼH5����ɧ`���e��ڍF������i[�ql@����Gh�D=[���gh������pV����}������������P
2019-03-25 21:10:13 SMTP Error: Could not connect to SMTP host.
<strong> There was an error sending your packing slip</strong>

当我 运行 具有更新设置的脚本(端口 465 上的 SSL)时:

2019-03-25 22:15:21 SMTP ERROR: Failed to connect to server: Connection refused (111)
2019-03-25 22:15:21 SMTP connect() failed. https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting
<strong> There was an error sending your packing slip</strong>

我猜一个关键问题是我没有正确理解这里的某些内容,所以如果有人能帮助我理解我哪里出错了,那就太好了。

谢谢。

编辑: 我忘记提到的一件事是,在今天与 Net Registry 支持人员交谈时,他们建议将主机设置为 localhost,将端口设置为 25。这没有用。

我刚刚 运行 遇到了与 Netregistry 完全相同的问题。这似乎没有在任何地方记录,但这是对我们有用的。

目前所需的设置似乎取决于您在 NetRegistry CPanel 中设置的 PHP 版本。

使用 localhost 作为主机适用于 PHP 5.5 或更低版本。

对于原生版本或更高版本 (>= PHP 5.6) 我们必须将主机设置为 cpanel 地址,例如:

$mail->Host = "cpxxx.ezyreg.com";

这是 PHP 5.6 的完整工作设置(据我所知,netregistry 的默认设置)

$mail = new PHPMailer();
$mail->SMTPAuth = true;
$mail->IsSMTP(); 
$mail->Host = "cpxxx.ezyreg.com"; //for PHP 5.5 or less on NR this must be "localhost"
$mail->Port = 465;
$mail->IsHTML(true);
$mail->Username = $username;
$mail->Password = $password;
$mail->SMTPSecure = "ssl";  
$mail->Mailer = "smtp"; 

编辑: 我在 PHP 5.6 的另一个 NR CPanel 站点上遇到了同样的问题,我发现解决它的唯一方法是使用不安全的 SMTP 连接和本地主机。以下是该站点的工作设置。

$mail = new PHPMailer();
$mail->SMTPAuth = false;
$mail->SMTPSecure = false;
$mail->SMTPAutoTLS = false;
$mail->Host = "localhost";
$mail->Port = 25;
$mail->IsHTML(true);

//username and password below probably unused
//but this is a straight copy paste from our working site.
$mail->Username = $username;
$mail->Password = $pass;

$mail->Mailer = "smtp"; 
$mail->IsSMTP(); 

在花了一些时间了解握手的工作原理后,由于邮件服务器有时会提供 TLS,PHPMailer 将自动接受并开始使用 TLS。

我猜这会导致以某种方式验证 netregistry 的 ssl 证书时出现问题。

您可以通过 SMTPAutoTLS 标志阻止 PHPMailer 自动使用 TLS。但是,我确实必须继续使用端口 25。所以我的配置设置变成了:

$mail->SMTPDebug = 0;
$mail->isSMTP();
$mail->Host = "smtp.netregistry.net";
$mail->SMTPAuth = true;
$mail->Username = "email";
$mail->Password = "password";
$mail->Port = 25;
$mail->SMTPAutoTLS = false;

我认为也许 PHPMailer 应该改进他们的文档,因为它不是特别明显,但在 troubleshooting wiki 的加密部分,文档提到了它。 Radcore 对他的回答的编辑也包含了这个标志,但是我没有注意到它,也没有明确指出它,所以我创建了一个单独的答案来专门突出显示它。

我在尝试了解正在发生的事情时发现的另一个有用资源是 Amazon's guide to debugging SMTP Conversations。它让我更好地理解了所有调试输出的含义。