因业务需要,今天做了一个简单的邮件发送功能,通过 PHPMailer
来实现。本地测试正常,部署到阿里云 ECS
后,报错:SMTP connect() failed
,本文简单记录下解决方案。
使用 SMTP
服务发送邮件,常用的端口有 25
和 465
,其中后者是 SSL
端口。一般来说,各云服务商都会封禁 25
端口,包括阿里云也不例外。阿里云可以在控制台申请解封 25
端口,但据网上反馈的信息,申请后基本没人处理,另外也完全没必要用 25
端口。因此,下文就仅针对 465
端口的情况进行说明。
代码部署到服务器后,调用发送邮件方法直接报错:SMTP connect() failed
。因为使用的阿里云,因此我们首先想到的就是去安全组添加白名单。在安全组中 出方向 中新增一条记录,端口对应 465/465
。添加完成后,我们可以在服务器上验证下。
[root@blog.phpha.com]# telnet smtp.mxhichina.com 465
Trying 140.205.94.10...
Connected to smtp.aliyun.com.
Escape character is '^]'.
我们使用的是阿里云企业邮箱,以上结果代表 465
端口已经开通权限。
再次执行发送邮件,依然报错:SMTP connect() failed
。这个错误相对来说比较粗糙,因此我们可以打开调试模式来查看发送过程中详细的日志。
只需要设置下 PHPMailer
的配置参数即可:$mail->SMTPDebug = 4
,再次执行可以看到如下详细的错误:
Connection: opening to ssl://smtp.mxhichina.com:465, timeout=300, options=array()
Connection failed. Error #2: stream_socket_client(): SSL operation failed with code 1.
OpenSSL Error messages:
error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed [/xxx/phpmailer/src/SMTP.php line 349]
Connection failed. Error #2: stream_socket_client(): Failed to enable crypto [/xxx/phpmailer/src/SMTP.php line 349]
Connection failed. Error #2: stream_socket_client(): unable to connect to ssl://smtp.mxhichina.com:465 (Unknown error) [/xxx/phpmailer/src/SMTP.php line 349]
SMTP ERROR: Failed to connect to server: (0)
SMTP connect() failed. https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting
重点是这个报错:tls_process_server_certificate:certificate verify failed
,看起来是跟证书相关。经过相关的搜索得知: PHP
在 5.6
及以后的版本中如使用 stream_socket_client() / fsockopen() / file_get_content()
等函数获取 HTTPS
站点的信息时,OPENSSL
会验证对方站点的 SSL
证书颁发机构是否可信,如果未配置 OPENSSL
根证书就会造成无法验证对方网站 SSL
证书是否可信,就无法获取到内容。因此,下面我们来配置下 OPENSSL
根证书。
# 下载最新根证书
[root@blog.phpha.com]# wget https://curl.haxx.se/ca/cacert.pem
# 移动到指定路径
[root@blog.phpha.com]# mv cacert.pem /usr/local/nginx/conf/ssl/cacert.pem
# 编辑 php.ini
[root@blog.phpha.com]# vim /usr/local/php/etc/php.ini
# 增加以下配置
openssl.cafile=/usr/local/nginx/conf/ssl/cacert.pem
之后重启 Nginx
或 Apache
,再次调用邮件发送的方法,即可正常发送。