无论你遇到什么问题,首先确保你正在使用最新的PHPMailer。如果你的代码是基于你在GitHub上其他地方找到的示例,则很可能是过时的 - 基于GitHub上示例文件夹中的示例来编写你的代码。大约90%的Stack Overflow上的问题都犯了这个错误,尤其是在PHPMailer 6.0发布后。
Composer 能节省大量工作 - 处理包依赖、更新和下载,并生成一个漂亮的自动加载器,这样你就不需要 require 自己手动加载类。 通过 composer 加载是使用 PHPMailer 的项目中推荐的方法。你只需要 require composer 的自动加载器:
require './vendor/autoload.php';
此文件仅在您使用 composer 安装 PHPMailer 时存在,它不是 PHPMailer 包的一部分。
如果你使用XOAUTH2认证,特别重要的是使用composer,因为它需要许多由composer满足的依赖类。默认情况下不包括这些依赖项,因为它们不是每个人都需要,并且它们无法在PHPMailer支持的较旧的PHP版本上运行,因此你会在PHPMailer的composer.json文件的“建议”部分找到它们。你应该将这些依赖项复制到你自己的composer.json部分,然后require来加载它们并添加到你的自动加载器中。composer update
如果你不这样做,你可能会看到这样的错误:
Fatal error: Class 'League\OAuth2\Client\Provider\Google' not found in PHPMailer/get_oauth_token.php on line 24要解决此问题,请按照上述说明配置 composer,或者下载该类及其所有依赖项,并自行手动加载。
这仅适用于旧的5.2分支。不久前,PHPMailer更改了其加载类的方式,使其与composer、许多框架以及PHP PSR-0自动加载标准更加兼容。请注意,由于5.2支持PHP 5.0版本,我们无法支持更近期的PSR-4标准,也无法使用命名空间。以前,PHPMailer显式加载SMTP类,如果您想提供自己的实现,这将导致问题。您可能见过旧脚本这样做:
require 'class.phpmailer.php';如果你只做那件事,SMTP发送将会失败并产生一个Class 'SMTP' not found错误。你需要显式包含class.smtp.php文件(阅读README了解你需要哪些文件),或者使用推荐的使用composer或提供的自动加载器的方法,如下所示:
require 'PHPMailerAutoload.php';如果您正在使用SMTP(即您正在调用isSMTP()),则可以使用SMTPDebug属性获取SMTP对话的详细记录。设置如下:
SMTP::DEBUG_OFF(0): 正常生产设置;无调试输出。SMTP::DEBUG_CLIENT(1): 仅显示客户端到服务器的消息。不要使用这个 - 很不可能对您有任何有用的信息。SMTP::DEBUG_SERVER(2): 显示客户端到服务器和服务器到客户端的消息 - 这通常是您想要的设置SMTP::DEBUG_CONNECTION(3): 与(2)相同,但还显示有关初始连接的详细信息;仅在您遇到连接问题时(例如连接超时)使用。SMTP::DEBUG_LOWLEVEL(4): 与(3)相同,但还显示详细的低级流量。仅在分析协议级错误时真正有用,非常详细,可能不是你需要的。
通过在脚本中包含如下类似行来设置此选项:
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
输出格式将根据命令行或HTML输出进行调整,但您可以使用Debugoutput属性覆盖此。如果您使用身份验证,用户ID和密码将在调试输出中被隐藏,除非您使用SMTP::DEBUG_LOWLEVEL(4)。
这可能也会显示为SMTP connect() failed,Called Mail() without being connected,Network is unreachable (101)在调试输出中。这通常被报告为PHPMailer问题,但几乎总是由于本地DNS失败、防火墙阻止(例如Godaddy这样做)、本地杀毒软件或您本地网络上的另一个问题。这意味着PHPMailer无法联系到您在Host属性中指定的SMTP服务器,但不具体说明原因。这也可以由没有加载openssl扩展(见下面的加密说明)引起的。
以下讨论了一些诊断此错误来源的技术。
美国知名主机提供商GoDaddy对发送邮件施加了非常严格的限制(几乎变得毫无用处)。他们阻止所有服务器(他们的除外)通过25、465和587端口进行outbound SMTP连接。这个问题是许多令人沮丧的Stack Overflow上的问题。如果你发现你的脚本在本地机器上可以正常工作,但在上传到GoDaddy后却不能,这就是你遇到的问题。GoDaddy对解决方案的文档非常不充分:你必须通过他们的服务器发送邮件,并且还要禁用所有安全功能、用户名和密码(真棒,对吧?),给你这个PHPMailer的配置:
$mail->isSMTP();$mail->Host = 'localhost';$mail->SMTPAuth = false;$mail->SMTPAutoTLS = false;
$mail->Port = 25;GoDaddy 也拒绝发送来自任何 From 地址,属于aol, gmail, yahoo, hotmail, live, aim, 或 msn域(见 他们的文档)。这是因为所有这些域都部署了SPF和DKIM防伪造措施,而伪造你的发件地址是伪造。
如果你设置SMTPDebug = SMTP::DEBUG_SERVER或更高,你将看到远程SMTP服务器的回复。这通常会告诉你具体的问题所在,例如“密码错误”,有时会提供一个帮助你诊断问题的页面链接。阅读回复内容。谷歌经常这样做 - 有关他们“允许不安全的应用”的设置信息,请参见下面。
这些通常被视为连接超时,或“名称解析临时失败”,“无法解析主机”,“getaddrinfo 失败”或类似错误。通过使用 dig 工具(来自 Debian/Ubuntu 的 dnsutils 包)来检查你的 DNS 是否正常工作:
dig +short smtp.gmail.com如果你的DNS正常工作,你将得到类似这样的结果:
gmail-smtp-msa.l.google.com.
173.194.67.108
173.194.67.109如果这失败了,PHPMailer将无法发送电子邮件,因为它无法获取正确的IP地址进行连接。如果你的DNS没有名称,你可以直接使用IP地址作为主机名。要解决这个问题,你需要弄清楚为什么你的DNS无法工作 - 也许你还没有设置你的解析器?
即使是一个禁用了所有服务的服务器通常也会对简单的ping做出响应,所以如果你知道你的DNS是好的,检查一下服务器是否真的在那里:
ping smtp.gmail.com你应该会看到类似这样的内容(按 ctrl-C 停止):
PING gmail-smtp-msa.l.google.com (74.125.133.108): 56 data bytes 64 bytes from 74.125.133.108: icmp_seq=0 ttl=43 time=72.636 ms 64 bytes from 74.125.133.108: icmp_seq=1 ttl=43 time=68.841 ms 64 bytes from 74.125.133.108: icmp_seq=2 ttl=43 time=68.500 ms
可能有其他服务正在运行您尝试连接的SMTP端口。您可以使用telnet工具来检查,如下所示(连接到gmail的提交服务端口):
telnet smtp.gmail.com 587
这应该会给你类似这样的结果:
Trying 173.194.67.109... Connected to gmail-smtp-msa.l.google.com. Escape character is '^]'. 220 mx.google.com ESMTP ex2sm16805587wjd.30 - gsmtp
(输入quit以退出)。如果端口587无法使用,您可以尝试端口465或端口25,并使用其中能正常工作的端口 - 但请注意,端口25通常不支持加密(见加密说明)。
如果它没有产生任何输出或者产生的不是以220开头的东西,那么要么你的服务器挂了,要么你找错了服务器。
如果您的系统没有安装 telnet,您可以使用 curl:
$ curl telnet://smtp.gmail.com:25
220 smtp.gmail.com ESMTP e15sm11606635wrx.86 - gsmtp
quit
221 2.0.0 closing connection e15sm11606635wrx.86 - gsmtp或者 nc (netcat):
$ nc -v smtp.gmail.com 25
Connection to smtp.gmail.com 25 port [tcp/smtp] succeeded!220 smtp.gmail.com ESMTP c18sm31847486wmk.0 - gsmtp
quit
221 2.0.0 closing connection c18sm31847486wmk.0 - gsmtp在这里需要注意的是,邮件服务器响应的名称应与您请求的服务器相关,正如上面的例子所示 - 我们请求了 smtp.gmail.com,得到了 gmail-smtp-msa.l.google.com这看起来像是与谷歌有关的事情 - 如果你看到的是你的 ISP 名称,那么可能意味着你的 ISP 防火墙正在透明地将你重定向到他们自己的邮件服务器,你可能会看到身份验证和 TLS 证书验证失败(见下文),因为你在登录错误的服务器。这很可能发生在端口 25,但在端口 465 和 587 上不太可能发生在这些端口,所以这是使用加密的又一个原因! 对于拥有 WHM 访问权限的 GoDaddy Cpanel 服务器,可以通过“Home »Security Center »SMTP Restrictions”禁用“SMTP 限制”(此功能防止用户绕过邮件服务器发送邮件。它将仅允许 MTA、mailman 和 root 连接到远程 SMTP 服务器。)
如果你看到像SMTP -> ERROR: Failed to connect to server: Permission denied (13)这样的错误,可能是SELinux阻止了PHP或网页服务器发送电子邮件。这在RedHat / Fedora / Centos上尤其常见。 使用getsebool命令我们可以检查httpd守护进程是否允许通过网络建立连接并发送电子邮件:
getsebool httpd_can_sendmail getsebool httpd_can_network_connect
这个命令将返回一个布尔值,开或关。如果它是关的,我们可以打开它:
sudo setsebool -P httpd_can_sendmail 1 sudo setsebool -P httpd_can_network_connect 1
如果你通过fastcgi运行PHP-FPM,你可能需要将此应用到fpm守护进程而不是httpd。
一些服务提供商(包括Digital Ocean)为服务器提供IPv6连接,但阻止通过IPv6的出站SMTP,而在IPv4上允许。可以通过将Host属性显式设置为一个IPv4地址来解决这个问题(gethostbyname函数仅进行IPv4查找):
$mail->Host = gethostbyname('smtp.gmail.com');这个方法的唯一问题是,你最终会要求连接到一个明确的IPv4地址,这通常会导致你无法通过证书名称检查。你可以禁用这个(见SMTPOptions此文档中的其他地方),但这应该被认为是一个糟糕的解决方案——正确的解决方案是修复你的网络。
注意:使用Digital Ocean服务时,请检查您的SMTP端口是否真的已解锁,因为这是一家总部位于美国的公司,它包含一系列指示以避免垃圾邮件,因此您应该请求解锁并按照步骤确认与Digital Ocean通过PHPMailer发送您的电子邮件的目的。
如果你的认证失败,有几个可能的原因:
您输入的用户名或密码错误
您的连接正在被重定向到不同的服务器(如上所述)
您已指定在没有加密的情况下进行身份验证
通常情况下,您不希望通过未加密的链接发送用户名或密码。一些SMTP身份验证方案确实会增加最低级别的安全性(发送短哈希而不是明文),但这些只提供最低限度的保护,因此大多数服务器不允许在没有加密的情况下进行身份验证。通过设置SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS和Port = 587以及设置Username和Password属性来解决这个问题。
从2014年12月开始,Google开始实施一种名为XOAUTH2的认证机制,基于OAuth2,用于访问其应用程序,包括Gmail。这个变化可能会破坏SMTP和IMAP访问Gmail,你可能会从许多邮件客户端(包括PHPMailer、Apple Mail、Outlook、Thunderbird等)收到认证失败(通常是“5.7.14 请通过您的网页浏览器登录并重试”或“用户名和密码不正确”)的错误信息。错误输出可能包括一个链接到https://support.google.com/mail/bin/answer.py?answer=78754,其中列出了可能的解决方法,或者https://support.google.com/mail/?p=BadCredentials,这基本没有帮助。在PHPMailer中,有两种主要的解决方案:
Gmail 不喜欢意外或不熟悉的客户端连接到 gmail 账户,因此它可能会要求您像往常一样在浏览器中登录您的 gmail 账户(这将在您设置
SMTPDebug = SMTP::DEBUG_SERVER时显示的错误输出中提到),或访问 解锁 CAPTCHA 页面,在他们的支持文档中提到。启用"允许不太安全的应用"通常可以解决PHPMailer的问题,并且不会显著降低你的应用安全性。据报道,更改此设置可能需要一小时或更长时间才能生效,因此不要期望立即修复。
PHPMailer在版本5.2.11中增加了对XOAUTH2的支持,不过你必须运行PHP 5.5或更高版本才能使用它。有关如何设置的文档可以在这个维基页面找到。
从2022年5月30日开始,Google已经完全暂停了基于密码的登录。这意味着您将不得不实现XOAUTH2身份验证,或者创建应用密码。您可能会发现后者更简单,因为一旦您设置好密码,它的工作方式与传统的用户名和密码方法一直相同。
微软可能会像谷歌一样以类似的方式禁用SMTP身份验证,根据他们的文档:
如果您在组织中启用了安全默认设置,那么 Exchange Online 中的 SMTP AUTH 已经被禁用。
不幸的是,它们不会提供任何反馈来告诉你正在发生什么,因此在调试输出中看起来就像一个普通的身份验证失败,无法与输入错误的ID或密码区分开来:
2020-11-15 13:08:25 SERVER -> CLIENT: 535 5.7.3 Authentication unsuccessful [HK0PR01CA0063.apcprd01.prod.exchangelabs.com]
如果他们已经做了这一点,您可以从 Outlook 管理门户重新启用单个用户账户的身份验证:
Admin / Users / Active users / [select user] / Mail tab / Mail apps
或者 对所有租户使用PowerShell(用户账户设置会覆盖租户设置)。
当使用XOAUTH2作为登录方法时,相关类可能会抛出异常。如果发生这种情况,您可能会收到一个“SMTP身份验证错误”,这并不提供很多关于实际出错信息。
实际抛出的异常可以通过使用$exception->getPrevious()并调试返回的异常来找到,该异常位于捕获的异常中。
try { $mailer->send();
} catch (\PHPMailer\PHPMailer\Exception $e) { // $e->getMessage() will show "SMTP authentication error"
$prev = $e->getPrevious(); if ($prev) { // $prev->getMessage() contains the actual error message to be used by developers
print $prev->getMessage();
}
}## Using encryptionYou should use encryption at every opportunity, otherwise you're inviting all kinds of unpleasant possibilities for phishing, identity theft, eavesdropping, stolen credentials etc.
PHPMailer uses TLS encryption; TLS is simply the "new" (since 1998!) name for SSL. The two names are interchangeable.
The TLS / SSL config you use for email has nothing to do with any certificate you may use on your web site; you can still use encrypted email even if your site does not have a certificate.### Check you have the openssl extensionTo use any kind of encryption you need the [`openssl` PHP extension](https://php.net/manual/en/book.openssl.php) enabled. If you don't have it installed, or it's misconfigured, you're likely to have trouble at the `STARTTLS` phase of connections. Check this by looking at the output of `phpinfo()` or `php -i` (look for an 'openssl' section), or `openssl` listed in the output of `php -m`, or run this line of code:```php
<?php echo (extension_loaded('openssl')?'SSL loaded':'SSL not loaded')."\n"; ?>有两种类型的电子邮件传输加密可供选择:
“SMTPS”
SMTPSecure = PHPMailer::ENCRYPTION_SMTPS,也称为“隐式”,因为它假定您从连接的开始就会使用加密。在PHPMailer中,此模式通过设置'ssl'(或Port = 465)来选择,并且通常需要。"SMTP+STARTTLS", 也称为"显式",因为它最初以不安全的方式连接,然后明确地请求开始使用加密。在PHPMailer中,通过设置
SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS(或'tls')来选择此模式,并且通常需要Port = 587(定义在RFC6409中),尽管它可以在任何端口上工作。这种方法的优点是,一个端口可以同时支持加密和未加密的连接。
SMTPS 在端口 465 上被废弃于 1998 年,主要只有微软使用;标准建议在端口 587 上使用 SMTP+STARTTLS。端口 465 上的隐式 TLS 在 2018 年再次成为推荐解决方案,见RFC8314,但这不是直接的取消废弃;原来的 SMTPS 是简单的通过 TLS 的SMTP,而 RFC6409 是通过显式 TLS 的稍微不同的SMTP 提交协议。RFC8314 是通过隐式 TLS 的相同 SMTP 提交协议。这种区别在很大程度上是学术性的,但最终结果是,端口 465 上提供加密的 SMTP 服务并不意味着它支持 SMTP 提交,假设它支持会导致脚本损坏。
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;$mail->Host = 'smtp.gmail.com';$mail->Port = 587;或
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;$mail->Host = 'smtp.gmail.com';$mail->Port = 465;不要混淆这些模式; SMTPS在端口587上或SMTP_STARTTLS在端口465上将无法工作.
PHPMailer 5.2.10 引入了机会性 TLS - 如果它看到服务器在广告 TLS 加密(在你连接到服务器之后),它会自动启用加密,即使你没有设置SMTPSecure。这可能会导致问题,如果服务器广告的 TLS 使用的是无效的证书,但你可以通过$mail->SMTPAutoTLS = false;将其关闭。
PHP 5.6 及以后的版本在 SSL 连接上验证证书。如果证书有问题,您将收到类似于此的错误:
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
你可能不会看到这个错误;在隐式加密模式(SMTPS)下,它可能会被隐藏,因为没有一种方法可以让通道显示消息 - 由于这个原因,SMTP+STARTTLS 通常更容易调试。在 SMTP 转录中,这通常会显示为尝试发送一个STARTTLS命令,立即接着一个QUIT命令。如果你设置了SMTPDebug = SMTP::DEBUG_CLIENT,它将不会显示;将其设置为至少SMTP::DEBUG_SERVER以看到服务器响应。
对于这个错误,有几个可能的解释和解决方案:
服务器发布了一个坏的、自签名的或已过期的证书 - 通过在邮件服务器上替换证书来修复。如果你没有访问权限,请询问管理员。你可以运行一些诊断测试,这将告诉你问题是出在你这边(如果测试通过)还是邮件服务器。
您的 ISP 透明地将您的 SMTP 交通重定向到不同的服务器 - 这实际上是一种中间人攻击,而 TLS 正是为此类情况而设计来保护您的。适当的解决方法是明确使用您的 ISP 的服务器 - 这对于 GoDaddy 尤其重要,但您可能会发现这会影响您使用某些从地址的能力,特别是如果您使用像 Gmail 或 Yahoo 这样的常见主机。
您的操作系统或PHP配置正在使用过时的CA(证书颁发机构)证书文件,这使得它无法验证来自服务器的完全有效的证书。
您的 PHP 版本太旧,不支持服务器支持的 TLS 版本。在这种情况下,即使禁用证书验证也没有用。
首先,找出你的PHP实例从哪里获取CA证书:
php -i | grep cafile openssl.cafile => /etc/ssl/cacert.pem => /etc/ssl/cacert.pem
您的位置可能不同,或者在您的 PHP 配置中未手动指定。如果它是空的,这意味着它依赖于您的操作系统默认位置的 CA 证书,并且您需要查阅操作系统文档以了解它们存储在哪里。
使用openssl测试连接,使用在CAfile参数中使用的任何CA证书捆绑路径:
echo QUIT | openssl s_client -crlf -starttls smtp -CAfile /etc/ssl/cacert.pem -connect smtp.gmail.com:587
一个成功的结果将如下所示,其中的 verify return 值都是 1:
CONNECTED(00000003) depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign verify return:1 depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3 verify return:1 depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = smtp.gmail.com verify return:1 --- Certificate chain 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 1 s:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
一个不好的结果(表明您需要更新或重新定位您的CA证书)是:
CONNECTED(00000003) depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3 verify error:num=20:unable to get local issuer certificate
OpenSSL的输出并不特别容易阅读 - 你可能会发现testssl.sh更好。像这样运行它:
./testssl.sh --starttls smtp smtp.gmail.com:587
要更新您的CA证书,请确保您的操作系统完全更新 - CA证书通常通过操作系统更新进行更新。或者,您可以从curl下载最新的CA证书文件,安装到某个可访问的位置(例如/etc/ssl/cacert.pem),并在您的php.ini文件中的openssl.cafile和curl.cainfo指令中指向它(根据您的操作系统和PHP配置,所需的位置会有所不同;具体位置超出PHPMailer的范围!):
openssl.cafile = /etc/ssl/cacert.pem curl.cainfo = /etc/ssl/cacert.pem
强烈推荐的替代方案是使用Certainty软件包,它确保您始终拥有最新的CA证书包。
如果无法做到这一点,您可以允许 不安全 连接通过 SMTPOptions 属性,该属性在 PHPMailer 5.2.10 中引入(在早期版本中,可以通过 子类化 SMTP 类 来实现),但是这 不推荐,因为这会失去使用安全传输的大部分意义:
$mail->SMTPOptions = [ 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true,
]
];你也可以在你的php.ini中全局更改这些设置,但这真的是一个很糟糕的主意;PHP 5.6因为非常好的原因进行了这个更改。
您可能会看到错误cURL error 60: SSL certificate problem: unable to get local issuer certificate。这可能是因为您的CA文件过期或丢失 - 请参阅上面的解决方案。
这个错误也可能发生在你的PHP使用了libressl编译的libcurl(在homebrew上这是一个常见的选项)时,libressl有一个与之相关的错误,而不是默认的openssl或OS X的内置Secure Transport - 运行curl -V将告诉你你的编译选项,如下所示:
curl 7.48.0 (x86_64-apple-darwin15.4.0) libcurl/7.48.0 OpenSSL/1.0.2g zlib/1.2.5 libssh2/1.7.0 nghttp2/1.9.2
标准的OS X安装将使用安全传输:
curl 7.43.0 (x86_64-apple-darwin15.0) libcurl/7.43.0 SecureTransport zlib/1.2.5
为了消除PHP配置或您的代码因加密问题而出现的问题,您可以使用本地安装的openssl直接测试配置,例如测试显式SMTP+STARTTLS配置,使用其内置的SMTP客户端:
echo QUIT | openssl s_client -starttls smtp -crlf -connect smtp.gmail.com:587
或者(如果你在使用端口465的隐式SSL)
echo QUIT | openssl s_client -connect smtp.gmail.com:465
当然,这不一定要是gmail的服务器 - 您可以在这些命令中替换任何邮件服务器名称。
你应该期望收到这样的回复:
CONNECTED(00000003) depth=2 /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA verify error:num=20:unable to get local issuer certificate verify return:0 --- Certificate chain 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com i:/C=US/O=Google Inc/CN=Google Internet Authority G2 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2 i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority --- Server certificate -----BEGIN CERTIFICATE----- MIIEgDCCA2igAwIBAgIIQKPDG0sroxQwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl ... 1cWGd2HMOapOHK+cyQP2Uuo4ZAo5Hgiy9nnDRMmvShT2dKbIv19JyrfXPguZ/E7I 6z/Z/Fi7ilSrrpx/Frd8XwRCNQJPWfd2cV6NqGLwNR2qSCA0gJaWdIvJYqITw0lL cAh6QQ== -----END CERTIFICATE----- subject=/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com issuer=/C=US/O=Google Inc/CN=Google Internet Authority G2 --- No client certificate CA names sent --- SSL handshake has read 3494 bytes and written 491 bytes --- New, TLSv1/SSLv3, Cipher is AES128-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES128-SHA Session-ID: 936F1A0663F5CE73943C00650C2FB2B9612E1F9819D38A7CD853DB9130D0E5EE Session-ID-ctx: Master-Key: C092C10C71219E0BE8358CD432120D94CA39B01EDDA8A7007B08D7E86A74B6A16B14345610255063E1B0A2DB55D86635 Key-Arg : None Start Time: 1460541074 Timeout : 300 (sec) Verify return code: 0 (ok) --- 250 SMTPUTF8
(只需输入“QUIT”即可退出)。请注意,验证返回代码为0,这表示验证成功。verify error:num=20:unable to get local issuer certificate这不是问题。
这意味着您的 PHP 安装没有正确配置调用 mail() 函数(例如 sendmail_path 在您的 php.ini 中没有正确设置),或者您没有安装和配置本地邮件服务器。要解决此问题,您需要按以下顺序执行这些操作之一或多个:
理想情况下,使用 和直接使用SMTP发送;这比使用 更快、更安全、更容易调试。
isSMTP()mail()安装本地邮件服务器(例如 postfix)。
确保你的
sendmail_path指向 sendmail 二进制文件(通常是/usr/sbin/sendmail)在你的php.ini中。请注意,在 Ubuntu/Debian 上,你可能在.ini文件中有多于一个的/etc/php5/mods-available和可能在其他位置。使用
isSendmail()并将路径设置到 sendmail 二进制文件在 PHPMailer ($mail->Sendmail = '/usr/sbin/sendmail';) 中。这个选项很少适用;请先评估其他解决方案。
如果你也看到消息 More than one "from" person,这可能是因为你的 php.ini 的 sendmail_path 属性已经包含了一个 -f 参数,因此你的代码试图添加第二个信封发件人,这是不允许的。
使用有效的电子邮件地址非常重要。PHPMailer接受电子邮件地址的每个地方,它都期望一个RFC821格式的地址,而不是一个RFC822格式的地址,例如user@example.com,而不是 Joe User <user@example.com>。所有接受电子邮件地址的函数,比如addAddress,如果地址被接受,将返回一个布尔值true。包含非ASCII字符的域名,比如café.com,将使用IDN 'punycode'格式,这在你要求PHPMailer进行send()之前无法正确评估,因此与它们相关的错误会比普通地址出现得晚。
大多数电子邮件提供商不允许您伪造/冒用发件地址。如果您发现致电setFrom没有效果,那可能是因为您试图从一个您不拥有的地址发送邮件。在Gmail上,您必须从登录时使用的地址(即您在Username属性中输入的地址)或您的Gmail账户中的预定义别名发送邮件 – 但这仍然不允许您从他人的地址发送邮件。
在联系表单中,为 和 使用你自己的地址,并在回复地址中使用提交者的地址,就像 联系表单示例 所做的那样。FromTo
如果上述任何检查失败,PHPMailer也将无法工作,并且通常PHPMailer对此无能为力。所以去修复你的网络,然后再试一次。如果你无法控制自己的防火墙或DNS,你可能需要向你的ISP提交支持请求来解决这个问题(他们通常会阻止或重定向25端口的出站流量)。如果他们不解决这个问题,你需要更换你的ISP。
有几处资源值得查看:
代码示例 与 PHPMailer 提供。基于这些代码示例编写你的代码,而不是来自 2003 年的古老示例。
代码本身 - 它有非常好的注释。
问题跟踪器 - 很可能之前已经发生过与您类似的问题,因此在 提交工单之前请先在里面搜索。如果您确实创建了一个问题,请确保包含您的代码,最好是最少的必要代码,以便我们有机会查看您所看到的问题 - 仅仅说“不工作”并不是一个错误报告!
StackOverflow - 这上面有很多关于PHPMailer的问题,其中大部分问题通过阅读此页面就可以解决!搜索问题,看看你看到的错误信息之前发布问题。如果你在StackOverflow上发布问题,请确保标记为
PHPMailer,这样我们能看到并回答你的问题。请不要在这里也提交问题。这里的 issue tracker 是为了 PHPMailer 的真实错误,而不是你的服务器问题。
Whatever problem you're having, first make sure you are using the latest PHPMailer. If you have based your code on an example you found somewhere other than here on GitHub, it's very probably outdated - base your code on the examples in the examples folder. About 90% of questions on Stack Overflow make this mistake, and is especially likely since the release of PHPMailer 6.0.
Composer saves a huge amount of work - handling package dependencies, updates and downloading, and generates a nice autoloader so you don't have to require classes yourself. Loading via composer is the preferred method of using PHPMailer in your project. All you need to do is require the composer autoloader:
require './vendor/autoload.php';
This file will only exist if you have used composer to install PHPMailer; it is not part of the PHPMailer package itself.
It's particularly important to use composer if you're using XOAUTH2 authentication since it requires many dependent classes that are satisfied by composer. The dependencies are not included by default because they are not needed by everyone and they don't work on the older PHP versions that PHPMailer supports, so you will find them in the 'suggest' section of PHPMailer's composer.json file. You should copy those dependencies to your own composer.json's require section, then composer update to load them and add them to your autoloader.
If you don't do this, you're likely to see errors like this:
Fatal error: Class 'League\OAuth2\Client\Provider\Google' not found in PHPMailer/get_oauth_token.php on line 24To fix this either configure composer as described or download this class and all its dependencies and load them manually yourself.
This only applies to the legacy 5.2 branch. Not so long ago, PHPMailer changed the way that it loaded classes so that it was more compatible with composer, many frameworks, and the PHP PSR-0 autoloading standard. Note that because 5.2 supports PHP back to version 5.0, we cannot support the more recent PSR-4 standard, nor can we use namespaces. Previously, PHPMailer loaded the SMTP class explicitly, and this causes problems if you want to provide your own implementation. You may have seen old scripts doing this:
require 'class.phpmailer.php';If you do only that, SMTP sending will fail with a Class 'SMTP' not found error. You need to either explicitly include the class.smtp.php file (read the README for info on which files you need), or use the recommended approaches of using composer or the supplied autoloader, like this:
require 'PHPMailerAutoload.php';If you're using SMTP (i.e. you're calling isSMTP()), you can get a detailed transcript of the SMTP conversation using the SMTPDebug property. The settings are as follows:
SMTP::DEBUG_OFF(0): Normal production setting; no debug output.SMTP::DEBUG_CLIENT(1): show client -> server messages only. Don't use this - it's very unlikely to tell you anything useful.SMTP::DEBUG_SERVER(2): show client -> server and server -> client messages - this is usually the setting you wantSMTP::DEBUG_CONNECTION(3): As 2, but also show details about the initial connection; only use this if you're having trouble connecting (e.g. connection timing out)SMTP::DEBUG_LOWLEVEL(4): As 3, but also shows detailed low-level traffic. Only really useful for analyzing protocol-level bugs, very verbose, probably not what you need.
Set this option by including a line like this in your script:
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
The output format will adapt itself to command-line or HTML output, though you can override this using the Debugoutput property. If you are using authentication, user IDs and passwords will be redacted in the debug output except when you use SMTP::DEBUG_LOWLEVEL (4).
This may also appear as SMTP connect() failed, Called Mail() without being connected, Network is unreachable (101) in debug output. This is often reported as a PHPMailer problem, but it's almost always down to local DNS failure, firewall blocking (for example as GoDaddy does), local anti-virus software, or another issue on your local network. It means that PHPMailer is unable to contact the SMTP server you have specified in the Host property, but doesn't say exactly why. It can also be caused by not having the openssl extension loaded (See encryption notes below).
Some techniques to diagnose the source of this error are discussed below.
Popular US hosting provider GoDaddy imposes very strict (to the point of becoming almost useless) constraints on sending an email. They block outbound SMTP to ports 25, 465 and 587 to all servers except their own. This problem is the subject of many frustrating questions on Stack Overflow. If you find your script works on your local machine, but not when you upload it to GoDaddy, this will be what's happening to you. The solution is extremely poorly documented by GoDaddy: you must send through their servers, and also disable all security features, username, and password (great, huh?!), giving you this config for PHPMailer:
$mail->isSMTP();$mail->Host = 'localhost';$mail->SMTPAuth = false;$mail->SMTPAutoTLS = false;
$mail->Port = 25;GoDaddy also refuses to send with a From address belonging to any aol, gmail, yahoo, hotmail, live, aim, or msn domain (see their docs). This is because all those domains deploy SPF and DKIM anti-forgery measures, and faking your from address is forgery.
If you set SMTPDebug = SMTP::DEBUG_SERVER or higher, you will see what the remote SMTP server says. Very often this will tell you exactly what is wrong - things like "Incorrect password", or sometimes a URL of a page to help you diagnose the problem. Read what it says. Google does this a lot - see below for info about their "Allow less secure apps" setting.
These are often seen as connection timeouts, or "Temporary failure in name resolution", "could not resolve host", "getaddrinfo failed" or similar errors. Check your DNS is working by using the dig tool (from the dnsutils package on Debian/Ubuntu):
dig +short smtp.gmail.comYou will get something like this if your DNS is working:
gmail-smtp-msa.l.google.com.
173.194.67.108
173.194.67.109If this fails, PHPMailer will not be able to send email because it won't be able to obtain the correct IP address to connect to. If perhaps you don't have a name in DNS, you can use an IP address directly as the hostname. To fix this you need to figure out why your DNS isn't working - perhaps you have not set up your resolvers?
Even a server with all services disabled will usually respond to simple pings, so if you know that your DNS is ok, check that the server is actually there:
ping smtp.gmail.comYou should see something like this (press ctrl-C to stop it):
PING gmail-smtp-msa.l.google.com (74.125.133.108): 56 data bytes 64 bytes from 74.125.133.108: icmp_seq=0 ttl=43 time=72.636 ms 64 bytes from 74.125.133.108: icmp_seq=1 ttl=43 time=68.841 ms 64 bytes from 74.125.133.108: icmp_seq=2 ttl=43 time=68.500 ms
It may be that some other service is running on the SMTP port you are trying to connect to. You can check this using the telnet tool, like this (connecting to gmail on its submission service port):
telnet smtp.gmail.com 587
This should give you something like this:
Trying 173.194.67.109... Connected to gmail-smtp-msa.l.google.com. Escape character is '^]'. 220 mx.google.com ESMTP ex2sm16805587wjd.30 - gsmtp
(Enter quit to get out of that). If port 587 doesn't work, you can try port 465 or port 25, and use whichever one works - though bear in mind that port 25 often doesn't support encryption (see encryption notes).
If it produces no output or something that doesn't start with 220, then either your server is down or you've got the wrong server.
If your system doesn't have telnet installed, you can use curl:
$ curl telnet://smtp.gmail.com:25
220 smtp.gmail.com ESMTP e15sm11606635wrx.86 - gsmtp
quit
221 2.0.0 closing connection e15sm11606635wrx.86 - gsmtpor nc (netcat):
$ nc -v smtp.gmail.com 25
Connection to smtp.gmail.com 25 port [tcp/smtp] succeeded!220 smtp.gmail.com ESMTP c18sm31847486wmk.0 - gsmtp
quit
221 2.0.0 closing connection c18sm31847486wmk.0 - gsmtpAnother thing to look out for here is that the name the mail server responds with should be related to the server you requested, as you can see in the above example - we asked for smtp.gmail.com and got gmail-smtp-msa.l.google.com, which looks like it's something to do with google - if instead you see something like the name of your ISP, then it could mean that your ISP's firewall is redirecting you transparently to their own mail servers, and you're likely to see authentication and TLS certificate verification failures (see below for more) because you're logging into the wrong server. This is very likely to happen on port 25, but less likely to happen on ports 465 and 587, so it's yet another reason to use encryption! For GoDaddy Cpanel servers with WHM access helps disabling "SMTP Restrictions" in "Home »Security Center »SMTP Restrictions" (This feature prevents users from bypassing the mail server to send mail. It will allow only the MTA, mailman, and root to connect to remote SMTP servers.)
If you see an error like SMTP -> ERROR: Failed to connect to server: Permission denied (13), you may be running into SELinux preventing PHP or the web server from sending email. This is particularly likely on RedHat / Fedora / Centos. Using the getsebool command we can check if the httpd daemon is allowed to make a connection over the network and send an email:
getsebool httpd_can_sendmail getsebool httpd_can_network_connect
This command will return a boolean on or off. If it's off, we can turn it on:
sudo setsebool -P httpd_can_sendmail 1 sudo setsebool -P httpd_can_network_connect 1
If you're running PHP-FPM via fastcgi, you may need to apply this to the fpm daemon rather than httpd.
Some service providers (including Digital Ocean) provide IPv6 connectivity for servers but block outbound SMTP over IPv6 while allowing it on IPv4. This can be worked around by setting the Host property to an IPv4 address explicitly (the gethostbyname function only does IPv4 lookups):
$mail->Host = gethostbyname('smtp.gmail.com');The only issue with this approach is that you end up asking to connect to an explicit IPv4 address, which will usually cause you to fail certificate name checks. You can disable that (see SMTPOptions elsewhere in this doc), but that should be considered a poor workaround - the right solution is to fix your network.
Note: When using the Digital Ocean service check if your SMTP port is actually unlocked, as it is a US based company it contains a series of directives not to fall into spam, so you should ask for the unlock and follow steps to confirm with Digital Ocean the Purpose of sending your emails with PHPMailer.
If your authentication is failing, there are several likely causes:
You have the wrong username or password
Your connection is being diverted to a different server (as above)
You have specified authentication without encryption
Generally, you do not want to send a username or password over an unencrypted link. Some SMTP authentication schemes do add a minimal level of security (sending short hashes rather than clear text), but these provide only minimal protection, and so most servers do not allow authentication without encryption. Fix this by setting SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS and Port = 587 as well as setting the Username and Password properties.
From December 2014, Google started imposing an authentication mechanism called XOAUTH2 based on OAuth2 for access to their apps, including Gmail. This change can break both SMTP and IMAP access to Gmail, and you may receive authentication failures (often "5.7.14 Please log in via your web browser and then try again" or "Username and Password not accepted") from many email clients, including PHPMailer, Apple Mail, Outlook, Thunderbird and others. The error output may include a link to https://support.google.com/mail/bin/answer.py?answer=78754, which gives a list of possible remedies, or https://support.google.com/mail/?p=BadCredentials, which is largely unhelpful. There are two main solutions to this in PHPMailer:
Gmail doesn't like unexpected or unfamiliar clients connecting to gmail accounts, so it may require you to log into your gmail account in your browser as usual (this will be mentioned in error output visible if you set
SMTPDebug = SMTP::DEBUG_SERVER), or to visit the unlock CAPTCHA page mentioned in their support doc.Enabling "Allow less secure apps" will usually solve the problem for PHPMailer, and it does not make your app significantly less secure. Reportedly, changing this setting may take an hour or more to take effect, so don't expect an immediate fix.
PHPMailer added support for XOAUTH2 in version 5.2.11, though you must be running PHP 5.5 or later in order to use it. Documentation on how to set it up can be found on this wiki page.
Starting from May 30th 2022, Google has suspended password based logins altogether. This means that you will either have to implement XOAUTH2 authentication, or create app passwords. You will probably find the latter is easier as once you have set up the password, it works exactly as the conventional username and password approach always did.
Microsoft may disable SMTP authentication in a similar way to Google. as per their docs:
If you've enabled security defaults in your organization, SMTP AUTH is already disabled in Exchange Online.
Unfortunately they do not provide any feedback letting you know that it's happening, so it just looks like a regular authentication failure in the debug output, indistinguishable from having the wrong id or password:
2020-11-15 13:08:25 SERVER -> CLIENT: 535 5.7.3 Authentication unsuccessful [HK0PR01CA0063.apcprd01.prod.exchangelabs.com]
If they have done this, you can re-enable authentication for an individual user account from the Outlook admin portal at:
Admin / Users / Active users / [select user] / Mail tab / Mail apps
or for the entire tenant using Powershell (the user account setting overrides the tenant setting).
When using XOAUTH2 as login method, exceptions can be thrown in the associated classes. If this happens, you'll likely get an "SMTP authentication error", which doesn't give you very much information about what actually went wrong.
The actual exception that was thrown is found within the caught exception by using $exception->getPrevious() and debugging the returned exception.
try { $mailer->send();
} catch (\PHPMailer\PHPMailer\Exception $e) { // $e->getMessage() will show "SMTP authentication error"
$prev = $e->getPrevious(); if ($prev) { // $prev->getMessage() contains the actual error message to be used by developers
print $prev->getMessage();
}
}## Using encryptionYou should use encryption at every opportunity, otherwise you're inviting all kinds of unpleasant possibilities for phishing, identity theft, eavesdropping, stolen credentials etc.
PHPMailer uses TLS encryption; TLS is simply the "new" (since 1998!) name for SSL. The two names are interchangeable.
The TLS / SSL config you use for email has nothing to do with any certificate you may use on your web site; you can still use encrypted email even if your site does not have a certificate.### Check you have the openssl extensionTo use any kind of encryption you need the [`openssl` PHP extension](https://php.net/manual/en/book.openssl.php) enabled. If you don't have it installed, or it's misconfigured, you're likely to have trouble at the `STARTTLS` phase of connections. Check this by looking at the output of `phpinfo()` or `php -i` (look for an 'openssl' section), or `openssl` listed in the output of `php -m`, or run this line of code:```php
<?php echo (extension_loaded('openssl')?'SSL loaded':'SSL not loaded')."\n"; ?>There are two "flavours" of transport encryption available for email:
"SMTPS", also referred to as "implicit" because it assumes that you're going to be using encryption right from the start of the connection. In PHPMailer this mode is selected by setting
SMTPSecure = PHPMailer::ENCRYPTION_SMTPS(or'ssl'), and usually requiresPort = 465."SMTP+STARTTLS", also referred to as "explicit" because it initially connects insecurely then explicitly asks for the connection to start using encryption. In PHPMailer this mode is selected by setting
SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS(or'tls'), and usually requiresPort = 587(defined in RFC6409), though it can work on any port. The advantage of this approach is that a single port can support both encrypted and unencrypted connections.
SMTPS on port 465 was deprecated in 1998 and was mostly only used by Microsoft; the standards recommended using SMTP+STARTTLS on port 587 instead. Implicit TLS on port 465 become a recommended solution again in 2018 in RFC8314, but this is not a straightforward undeprecation; the original SMTPS is simply regular SMTP over TLS, whereas RFC6409 is the subtly different SMTP Submission protocol over explicit TLS. RFC8314 is the same SMTP Submission protocol over implicit TLS. The difference is largely academic, but the net result is that the availability of an encrypted SMTP service on port 465 does not mean that it supports SMTP submission, and assuming that it does is a recipe for broken scripts.
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;$mail->Host = 'smtp.gmail.com';$mail->Port = 587;or
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;$mail->Host = 'smtp.gmail.com';$mail->Port = 465;Don't mix up these modes; SMTPS on port 587 or SMTP_STARTTLS on port 465 will not work.
PHPMailer 5.2.10 introduced opportunistic TLS - if it sees that the server is advertising TLS encryption (after you have connected to the server), it enables encryption automatically, even if you have not set SMTPSecure. This might cause issues if the server is advertising TLS with an invalid certificate, but you can turn it off with $mail->SMTPAutoTLS = false;.
PHP versions since 5.6 verify certificates on SSL connections. If there's a problem relating to the certificate, you will get an error like this:
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
You may not see this error; In implicit encryption mode (SMTPS) it may be hidden because there isn't a way for the channel to show messages - SMTP+STARTTLS is generally easier to debug because of this. In an SMTP transcript this will typically be shown as trying to send a STARTTLS command immediately followed by a QUIT command. It will also not be shown if you set SMTPDebug = SMTP::DEBUG_CLIENT; set it to at least SMTP::DEBUG_SERVER to see server responses.
There are several likely explanations and solutions for this error:
The server is publishing a bad, self-signed, or expired certificate - fix by replacing the certificate on your mail server. If you don't have access, ask whoever the admin is. You can run some diagnostic tests which will tell you whether the problem is at your end (if the tests pass) or the mail server's.
Your ISP is transparently redirecting your SMTP traffic to a different server - this is effectively a man-in-the-middle attack and is exactly the kind of thing that TLS is designed to protect you from. An appropriate fix here is to use your ISP's server explicitly - this is especially true for GoDaddy - but you may find this interferes with your ability to use some from addresses, especially if you're using common hosts like Gmail or Yahoo.
Your operating system or PHP configuration is using an out of date CA (certificate authority) certificate file, preventing it being able to verify a perfectly valid certificate from the server.
Your PHP version is so old that it lacks support for the TLS versions supported by the server. In this situation even disabling certificate verification will not help.
First of all find out where your PHP instance gets its CA certificates from:
php -i | grep cafile openssl.cafile => /etc/ssl/cacert.pem => /etc/ssl/cacert.pem
Your location may be different, or not specified manually in your PHP config. If it's empty, it means it's relying on your OS default locations for CA certificates, and you'll need to consult your OS docs to find out where they are kept.
Ask openssl to test the connection using whatever CA cert bundle path you're using in the CAfile parameter:
echo QUIT | openssl s_client -crlf -starttls smtp -CAfile /etc/ssl/cacert.pem -connect smtp.gmail.com:587
A successful result will look like this, where the verify return values are all 1:
CONNECTED(00000003) depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign verify return:1 depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3 verify return:1 depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = smtp.gmail.com verify return:1 --- Certificate chain 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 1 s:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
A bad result (suggesting you need to update or relocate your CA certs) would be:
CONNECTED(00000003) depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3 verify error:num=20:unable to get local issuer certificate
The OpenSSL output is not especially easy to read - you may find that testssl.sh is better. Run it like this:
./testssl.sh --starttls smtp smtp.gmail.com:587
To update your CA certificates, make sure your operating system is fully up to date - CA certs are usually updated via OS updates. Alternatively, you can download the latest CA cert file from curl, install it somewhere accessible (for example /etc/ssl/cacert.pem) and point at it from the openssl.cafile and curl.cainfo directives in your php.ini file (this location will vary according to your OS and PHP config; where you need to put it is beyond the scope of PHPMailer!):
openssl.cafile = /etc/ssl/cacert.pem curl.cainfo = /etc/ssl/cacert.pem
A highly recommended alternative is to use the Certainty package which ensures that you always have the latest CA cert bundle.
Failing that, you can allow insecure connections via the SMTPOptions property introduced in PHPMailer 5.2.10 (it's possible to do this by subclassing the SMTP class in earlier versions), though this is not recommended as it defeats much of the point of using a secure transport at all:
$mail->SMTPOptions = [ 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true,
]
];You can also change these settings globally in your php.ini, but that's a really bad idea; PHP 5.6 made this change for very good reasons.
You may see the error cURL error 60: SSL certificate problem: unable to get local issuer certificate. This may be because your CA file is out of date or missing - see above for how to fix that.
This error can also be caused if your PHP is using a libcurl compiled with libressl (a common option on homebrew), which has a bug relating to this, instead of the default openssl or OS X's built-in Secure Transport - running curl -V will tell you what yours is compiled with, like this:
curl 7.48.0 (x86_64-apple-darwin15.4.0) libcurl/7.48.0 OpenSSL/1.0.2g zlib/1.2.5 libssh2/1.7.0 nghttp2/1.9.2
A standard OS X installation will use Secure Transport:
curl 7.43.0 (x86_64-apple-darwin15.0) libcurl/7.43.0 SecureTransport zlib/1.2.5
In order to eliminate PHP config or your code from encryption issues, you can use your local openssl installation to test the config directly using its built-in SMTP client, for example to test an explicit SMTP+STARTTLS config:
echo QUIT | openssl s_client -starttls smtp -crlf -connect smtp.gmail.com:587
or (if you're using implicit SSL on port 465)
echo QUIT | openssl s_client -connect smtp.gmail.com:465
Of course this doesn't have to be gmail's server - you can substitute any mail server name in these commands.
You should expect a response like this:
CONNECTED(00000003) depth=2 /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA verify error:num=20:unable to get local issuer certificate verify return:0 --- Certificate chain 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com i:/C=US/O=Google Inc/CN=Google Internet Authority G2 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2 i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority --- Server certificate -----BEGIN CERTIFICATE----- MIIEgDCCA2igAwIBAgIIQKPDG0sroxQwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl ... 1cWGd2HMOapOHK+cyQP2Uuo4ZAo5Hgiy9nnDRMmvShT2dKbIv19JyrfXPguZ/E7I 6z/Z/Fi7ilSrrpx/Frd8XwRCNQJPWfd2cV6NqGLwNR2qSCA0gJaWdIvJYqITw0lL cAh6QQ== -----END CERTIFICATE----- subject=/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com issuer=/C=US/O=Google Inc/CN=Google Internet Authority G2 --- No client certificate CA names sent --- SSL handshake has read 3494 bytes and written 491 bytes --- New, TLSv1/SSLv3, Cipher is AES128-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES128-SHA Session-ID: 936F1A0663F5CE73943C00650C2FB2B9612E1F9819D38A7CD853DB9130D0E5EE Session-ID-ctx: Master-Key: C092C10C71219E0BE8358CD432120D94CA39B01EDDA8A7007B08D7E86A74B6A16B14345610255063E1B0A2DB55D86635 Key-Arg : None Start Time: 1460541074 Timeout : 300 (sec) Verify return code: 0 (ok) --- 250 SMTPUTF8
(just type "QUIT" to get out of that). Notice that the verify return code is 0, which indicates successful verification. The verify error:num=20:unable to get local issuer certificate is not a problem.
This means that your PHP installation is not configured to call the mail() function correctly (e.g. sendmail_path is not set correctly in your php.ini), or you have no local mail server installed and configured. To fix this you need to do one or more of these things (in order of preference):
Ideally, use
isSMTP()and send directly using SMTP; it's faster, safer, and easier to debug than usingmail().Install a local mail server (e.g. postfix).
Ensure that your
sendmail_pathpoints at the sendmail binary (usually/usr/sbin/sendmail) in yourphp.ini. Note that on Ubuntu/Debian you may have multiple.inifiles in/etc/php5/mods-availableand possibly other locations.Use
isSendmail()and set the path to the sendmail binary in PHPMailer ($mail->Sendmail = '/usr/sbin/sendmail';). It's very unlikely this option is appropriate; evaluate other solutions first.
If you also see the message More than one "from" person, it's likely that your php.ini's sendmail_path property already contains a -f parameter, and so your code is trying to add a second envelope sender, which is not allowed.
It's important that you use valid email addresses. Every place that PHPMailer accepts an email address property, it expects an RFC821-format address, not an RFC822 one, for example user@example.com, not Joe User <user@example.com>. All the functions that accept an email address, like addAddress will return a boolean true if the address was accepted. Domain names containing non-ascii chars like café.com will use IDN 'punycode' format, which can't be evaluated properly until you ask PHPMailer to send(), so errors relating to them will appear later than for regular addresses.
Most email providers do not let you forge/spoof the from address. If you find that calling setFrom doesn't do anything, it's probably because you're trying to send from an address that you don't own. On gmail you must send from either the address you log in with (i.e. what you put in the Username property), or predefined aliases in your gmail account – but that still doesn't allow you to send from other people's addresses.
On contact forms, use your own address for both From and To, and use the submitter's address in a reply-to address, which is what the contact form example does.
There is a separate document about deliverability and spam filtering.
If any of the above checks fail, PHPMailer will not work either, and usually there's nothing that PHPMailer can do about it. So go fix your network, then try again. If you are not in control of your own firewall or DNS, you probably need to raise a support ticket with your ISP to fix this (it's very common for them to block or divert port 25 outbound). If they won't fix it, you need to replace your ISP.
Several resources are worth checking:
The code examples provided with PHPMailer. Base your code on these, not some ancient example from 2003.
The code itself - it's very well commented.
The issue tracker - it's very likely a problem similar to yours has happened before, so search in there before opening a ticket. If you do create an issue, be sure to include your code, preferably the minimum necessary to reproduce or define the problem so that we have a chance to see what you're seeing - saying "It doesn't work" is not a bug report!
StackOverflow - there are a ton of PHPMailer questions on there, the vast majority of which could be fixed by reading this page! Search the questions for the error message you're seeing before posting a question. If you post a question on SO, make sure you tag it as
PHPMailerso that we will see it and please don't open an issue here as well. The issue tracker here is intended for actual bugs in PHPMailer, not problems with your server.

支付宝微信扫一扫,打赏作者吧~本文链接:https://kinber.cn/post/5842.html 转载需授权!
推荐本站淘宝优惠价购买喜欢的宝贝:


