PEAR Mail无法连接到Gmail SMTP,无法连接到套接字。

18

事实

我正在使用 PEAR Mail,我想使用 gmail 的 SMTP 发送邮件。我拥有 Apache/2.4.27 (Win64) PHP/7.2.0beta3、PEAR 1.10.15、Mail 1.4.1、Net_SMTP 1.8.0 和 Net_Socket 1.2.2。

我进入了 php.ini,添加了 extension = php_openssl.dllerror.log 没有显示与 SSL 相关的错误。

这里是代码:

require_once "Mail.php";

$from = '<slevin@gmail.com>';
$to = '<slevinkelevra@gmal.com>';
$subject = 'Hi!';
$body = "Hi,\n\nHow are you?";

$headers = array(
    'From' => $from,
    'To' => $to,
    'Subject' => $subject
);

$smtp = Mail::factory('smtp', array(
        'host' => 'ssl://smtp.gmail.com',
        'port' => '465',
        'auth' => true,
        'username' => 'slevinmail@gmail.com',
        'password' => 'mypassword'
    ));

$mail = $smtp->send($to, $headers, $body);

if (PEAR::isError($mail)) {
    echo('<p>' . $mail->getMessage() . '</p>');
} else {
    echo('<p>Message successfully sent!</p>');
}

问题

我遇到了这个错误:

Failed to connect to ssl://smtp.gmail.com:465 [SMTP: Failed to connect socket: fsockopen(): unable to connect to ssl://smtp.gmail.com:465 (Unknown error) (code: -1, response: )]

但我不知道该怎么办,我在谷歌上搜索,但越来越困惑。

请指导如何解决此问题。谢谢。

更新

按照symcbean的说明,我得到了以下结果:

bool(true) 

array(5) { 
[0]=> string(31) "alt3.gmail-smtp-in.l.google.com" 
[1]=> string(26) "gmail-smtp-in.l.google.com" 
[2]=> string(31) "alt4.gmail-smtp-in.l.google.com" 
[3]=> string(31) "alt1.gmail-smtp-in.l.google.com" 
[4]=> string(31) "alt2.gmail-smtp-in.l.google.com" } 
IPV4 address = 64.233.188.27

If you've got this far without errors then problem is with your SSL config

Check you've got your cacerts deployed in one of the following locations
default_cert_file = C:\Program Files\Common Files\SSL/cert.pem
default_cert_file_env = SSL_CERT_FILE
default_cert_dir = C:\Program Files\Common Files\SSL/certs
default_cert_dir_env = SSL_CERT_DIR
default_private_dir = C:\Program Files\Common Files\SSL/private
default_default_cert_area = C:\Program Files\Common Files\SSL
ini_cafile = 
ini_capath = 

If all good so far, then this bit should work....
fsockopen 
Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed in C:\Apache24\htdocs\phptest2.php on line 28

Warning: fsockopen(): Failed to enable crypto in C:\Apache24\htdocs\phptest2.php on line 28

Warning: fsockopen(): unable to connect to ssl://smtp.gmail.com:465 (Unknown error) in C:\Apache24\htdocs\phptest2.php on line 28
bool(false) int(0) string(0) "" 

第28行是这一行:var_dump(fsockopen("ssl://smtp.gmail.com", 465, $errno, $errstr, 3.0));

再次感谢

更新#2

我仅谷歌了第一个警告的“fsockopen():SSL操作失败,代码为1。”

最终在这里找到了答案。我更改了AVG的邮件端口,就像答案中所说的那样。 symcbean的代码运行没有错误,但我的代码回复了以下内容 mail error : authentication failure [SMTP: Invalid response code received from server (code: 534, response: 5.7.14 Please log in via your web browser and 5.7.14 then try again. 5.7.14 Learn more at 5.7.14 https://support.google.com/mail/answer/78754 c1sm1243434wre.84 - gsmtp)]

因此,我谷歌搜索了code: 534,response: 5.7.14,并最终在这里找到了答案,按照emgh3i的第一个答案的说明启用了不太安全的连接,并允许访问我的Google帐户

现在它完美地工作。


你需要先尝试一些命令行工具。查看openssl client以了解如何建立测试连接。如果失败了,可能是因为有防火墙规则。如果只是从Apache/PHP失败了,可能是SELinux/AppArmor等问题。 - mario
phpinfo() 函数会显示有关 OpenSSL 的信息吗? - Don't Panic
@mario,我该如何检查openssl客户端以建立测试连接? - slevin
@Don'tPanic OpenSSL部分已经存在,已启用,并且还包括库版本、头文件版本、默认配置,但没有openssl.cafileopensll.capath的值。 - slevin
1
可能是防火墙的问题,你有没有任何阻止连接到互联网的东西? - Don't Panic
显示剩余4条评论
9个回答

6
你的host配置不应包含协议。失败的原因可能是因为它正在尝试在ssl://smtp.gmail.com上执行DNS查询并失败了。
更改如下:
'host' => 'ssl://smtp.gmail.com',

to

'host' => 'smtp.gmail.com',

如果我按照你说的编辑了“host”,年龄就根本不会加载,只是一直挂在那里,从未真正加载。 - slevin
主机名中的 ssl:// 显然是正确的。 - Don't Panic
不要惊慌:这是关于您链接的CodeIgniter电子邮件库的帖子,而不是Pear :: Mail。 - symcbean
@symcbean 是吗?该问题链接到一些CI代码,但他们没有说他们正在使用它。被接受的答案说这是PHP处理ssl://链接,而不是库或框架。此外,https://stackoverflow.com/questions/16642346/smtp-failed-to-connect-socket-unable-to-find-the-socket-transport-ssl - Don't Panic

6

1
除了“不安全的应用程序”与发送邮件无关之外,您是否在暗示只有通过gmail帐户才能向gmail发送电子邮件? - symcbean
@不要惊慌,你关于“较不安全的应用程序”的说法是正确的,但使用相同的用户名并非必要,我已经检查过了,它可以正常工作。 - slevin
@slevin 太棒了。祝你好运选出正确的答案! :-) - Don't Panic
我想选择你的,但我认为你应该编辑掉“from/username”部分,因为它是无关紧要的,而且可能会误导其他人。 - slevin
@symcbean,不,我没有建议那样做,也许你误读了。我的意思是,发送邮件时,“从”使用的地址与账户不同可能存在潜在问题。据我所知,Gmail对任何看起来像欺骗的东西特别敏感,尽管似乎这并非此次问题的原因。 - Don't Panic

6

您的代码正确无误

我尝试测试我的Gmail帐户,邮件发送成功。

检查您的套接字连接

<?php

error_reporting(E_ALL);

var_dump(fsockopen("ssl://smtp.gmail.com", 465, $errno, $errstr));
var_dump($errno);
var_dump($errstr);

类型为stream的第4个资源

整数0

空字符串


感谢您提供如此精彩的代码,这将成为我的一个调试工具。 - slevin
通过这个,我得到了$errno为0和$errstr为空,所以使用ssl时邮件无法工作。你能指导一下可能出了什么问题吗? - Dushyant Joshi
fsockopen测试只是在PHP中知道与Google服务器的套接字连接是否可能。如果没有套接字错误,您应该通过参考其他评论中提到的内容进行分析。 - Been Kyung-yoon

6

几个调试步骤:

1. 检查 phpinfo

我建议检查 phpinfo() 来确定所有模块是否已启用。检查邮件、fsocketopen。

2. 启用 debug 标志

启用 debug 标志以确切地查看问题所在。如下所示。

$smtp = Mail::factory('smtp', array(
        'host' => 'ssl://smtp.gmail.com',
        'port' => '465',
        'auth' => true,
        'debug' => true,
        'pipelining' => true,
        'username' => 'xxx@gmail.com',
        'password' => 'xxx'
    ));

在我的机器上运行以上代码后,我得到了以下回应。问题可能与你的不同,但调试对我有所帮助。由于我启用了双因素认证,它给了我一个错误。我也收到了一封邮件,说我的登录已被阻止。
DEBUG: Recv: 220 smtp.gmail.com ESMTP s65sm4891344pfi.36 - gsmtp DEBUG: Send: EHLO localhost DEBUG: Recv: 250-smtp.gmail.com at your service, [110.227.210.84] DEBUG: Recv: 250-SIZE 35882577 DEBUG: Recv: 250-8BITMIME DEBUG: Recv: 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH DEBUG: Recv: 250-ENHANCEDSTATUSCODES DEBUG: Recv: 250-PIPELINING DEBUG: Recv: 250-CHUNKING DEBUG: Recv: 250 SMTPUTF8 DEBUG: Send: AUTH LOGIN DEBUG: Recv: 334 VsadfSFcm5hbWU6 DEBUG: Send: cGF0ZWwuZ29wYhkafdaASFnbWFpbC5jb20= DEBUG: Recv: 334 UGFzc3dvcmQ6 DEBUG: Send: OWwzMy5zaHlAbTE4 DEBUG: Recv: 534-5.7.14 Please log in via your web browser and DEBUG: Recv: 534-5.7.14 then try again. DEBUG: Recv: 534-5.7.14 Learn more at DEBUG: Recv: 534 5.7.14 https://support.google.com/mail/answer/78754 s65sm4891344pfi.36 - gsmtp DEBUG: Send: RSET DEBUG: Send: QUIT DEBUG: Recv: 250 2.1.5 Flushed s65sm4891344pfi.36 - gsmtp DEBUG: Recv: 221 2.0.0 closing connection s65sm4891344pfi.36 - gsmtp
authentication failure [SMTP: Invalid response code received from server (code: 534, response: 5.7.14 Please log in via your web browser and 5.7.14 then try again. 5.7.14 Learn more at 5.7.14 https://support.google.com/mail/answer/78754 s65sm4891344pfi.36 - gsmtp)]

更新:

你的问题似乎是PHP无法连接到Gmail服务器。


4

当出现问题且我们不知道原因时,我们需要进行调试。因此,在这里,我不是提供答案,而是请求您执行一些测试。

  1. confirm system connectivity with internet: Open cmd terminal and type

    ping smtp.gmail.com
    
  2. confirm firewall: Enter following in cmd terminal

    telnet smtp.gmail.com 465
    
  3. confirm php setup: enter php -a at cmd terminal and on php prompt execute (copy / paste and then press enter) following code.

    $result = fsockopen('ssl://smtp.gmail.com', 465, $error_no, $error_message, 5);
    if ($result === false) {
      echo "error no: $error_no error message: $error_message";
      echo print_r($result, true);
    } else {
      echo 'success';
    }
    
  4. confirm Pear Mail library and Gmail SMTP access: again on cmd and php prompt php -a execute your own code (as you posted in this thread)

请告诉我们故障出现的位置以及错误信息,只有在了解这些情况后,我们才能提供帮助。


请查看我的原始帖子,更新#2。感谢您的努力。记录一下,ping smtp.gmail 工作正常,但 ping telnet 回复 'telnet' 不是内部或外部命令,可执行程序或批处理文件。第3步回复“成功”。第4步说:警告:在php shell代码中未捕获的错误:未找到类'PEAR':1 堆栈跟踪: #0 {main} 在php shell代码中抛出,位于第1行 - slevin

3

别人对解决这个问题的贡献并不显著,只有被庆勇做出了有意义的贡献(+1 给庆勇!)。我可以确认他的结果。我建议你也尝试一下。你目前正在尝试调试一个相当复杂的组件堆栈:

作为提问者,你的工作是创建一个最小、完整和可验证的示例,而不是让别人替你完成这个任务。

这将希望提供更有意义的诊断信息。

导致此失败的最可能原因是:

  • 您正在运行此程序的主机无法将出站连接路由到互联网(但是,由于您似乎正在使用台式电脑,我认为您现在可能已经注意到了)
  • 代码正在安全沙箱中运行(但是MSWindows实际上没有这样的东西)
  • 主机无法解析主机名(请参见第一个关于路由的要点)
  • 主机能够连接但无法验证证书

因此,您可以考虑使用更详细的测试脚本实现:

 <?php

 error_reporting(E_ALL);

 print "DNS\n";
 var_dump(getmxrr('gmail.com',$result));
 var_dump($result);
 $use_ip=gethostbyname($result[0]);
 print "IPV4 address = $use_ip\n";

 print "\nIf you've got this far without errors then problem is with your SSL config\n";
 $calocns=openssl_get_cert_locations();
 if (count($calocns)) {
     print "Check you've got your cacerts deployed in one of the following locations\n";
     foreach ($calocns as $k=>$v) print "$k = $v\n";
 } else {
     print "You've not configured your openssl installation on this host\n";
 }

 print "\nIf all good so far, then this bit should work....\n";
 print "fsockopen\n";
 var_dump(fsockopen("ssl://smtp.gmail.com", 465, $errno, $errstr, 3.0));
 var_dump($errno);
 var_dump($errstr);

这应该会给你一个像这样的响应:

 DNS
 bool(true)
 array(5) {
   [0]=>
   string(31) "alt1.gmail-smtp-in.l.google.com"
   [1]=>
   string(31) "alt2.gmail-smtp-in.l.google.com"
   [2]=>
   string(31) "alt4.gmail-smtp-in.l.google.com"
   [3]=>
   string(26) "gmail-smtp-in.l.google.com"
   [4]=>
   string(31) "alt3.gmail-smtp-in.l.google.com"
 }
 IPV4 address = 74.125.131.26

 If you've got this far without errors then problem is with your SSL config
 Check you've got your cacerts deployed in one of the following locations
 default_cert_file = /usr/lib/ssl/cert.pem
 default_cert_file_env = SSL_CERT_FILE
 default_cert_dir = /usr/lib/ssl/certs
 default_cert_dir_env = SSL_CERT_DIR
 default_private_dir = /usr/lib/ssl/private
 default_default_cert_area = /usr/lib/ssl
 ini_cafile =
 ini_capath =

 If all good so far, then this bit should work....
 fsockopen
 resource(4) of type (stream)
 int(0)
 string(0) ""

鉴于我们无法重现您的错误,因此无法给出明确的答案说明问题所在——但我猜测您尚未配置openSSL可能是问题所在。

感谢您的出色努力。请在更新部分查看我的原始帖子以获取结果。请记住,我是一个“后端新手”(如果这是一个术语的话),所以请给予建议。我无法得到提示,应该如何继续或下一步应该是什么。再次感谢。 - slevin
"证书验证失败" - 这意味着您与smtp.gmail.com的连接可能被中间人攻击(不太可能),或者您的cacerts未安装/更新。您可以在此处获取当前Mozilla策划的正确格式的CACert捆绑包:https://curl.haxx.se/docs/caextract.html - symcbean
请查看我的原始帖子,更新#2。所以,这最终是Gmail的问题吗?再次感谢。 - slevin
1
我的意思是连接被你的杀毒软件中间人攻击了。它无法读取加密流,因此它会将其解密,然后重新加密回您的应用程序。当您安装它时,它会将自己的CA证书注入到Microsoft证书存储中,因此使用它的任何应用程序都会认为证书是正确的 - 但它不会知道OpenSSL CA证书文件。 - symcbean
1
@symvbean,“Been Kyung-yoong是唯一做出有意义贡献的人”……你的评论侮辱了那些给出正确答案的人,这与你认为的问题无关。 - Altimus Prime
显示剩余4条评论

2

在我开始之前,我先声明一下,在你的服务器和谷歌服务器之间有很多可能的解决方案和结果,所以这些可能对不同的人起作用或者不起作用。

1) SMTP 不是非常安全,所以谷歌可能会拒绝你的请求。我在6个月前就遇到了这个问题,解决方法是在“myaccount.google.com”下启用不安全的应用程序。

enter image description here

2) 如果这对你不起作用,那么可以考虑切换协议。

'host' => 'ssl://smtp.gmail.com',

'host' => 'tls://smtp.gmail.com:587';


“SMTP并不是非常安全” - 它本来就不是为了安全而设计的 - 这就是AUTH,STARTTLS和SMTPS的作用。 “允许使用较不安全的应用程序”配置选项仅启用基本身份验证的IMAPS连接以在邮箱上启用 - 与发送邮件无关。 - symcbean
1
@symcbean。我的答案是正确的。它实际上解决了我自己和slevin的问题。 - Altimus Prime

0

这可能与问题直接无关,但对于任何使用Pear SMTP通过远程服务器发送电子邮件遇到问题的人来说,真正的问题可能不是防火墙配置,而是SELINUX。如果它开启了(这是默认设置),您可能会花费数天时间想知道为什么权限被拒绝。只需告诉selinux允许apache发送电子邮件即可:

setsebool -P httpd_can_sendmail 1

希望这能帮助到某些人避免麻烦。


0
在PHP5.3中,其他人提供的关于需要在Google Gmail帐户登录时激活的“不太安全的应用程序”的提示解决了我所有的问题。
在PHP7.2中,我需要做更多的工作:将“auth”设置为PLAIN,然后像这样为ssl socket_options添加“verify_peer”和“verify_peer_name”。
$mail= Mail::factory('smtp', array('host' => 'ssl://smtp.gmail.com',
                                   'port' => '465',
                                   'auth' => 'PLAIN',
                                   'socket_options' => array('ssl' => array('verify_peer' => false,
                                                                            'verify_peer_name' => false)),
                                   'username' => 'someAccount@gmail.com',
                                   'password' => 'myPassword'
));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接