终于能够通过phpmailer使用gmail账号发送邮件了

phpmailer(现在的版本是1.73)是一个很好用的工具,可以很方便的使用php语言发送邮件,支持smtp及验证,我们一直都用它。

但是,由于gmail的smtp采用了ssl连接:

Outgoing Mail (SMTP) Server – requires TLS: smtp.gmail.com (use authentication) Use Authentication: Yes Use STARTTLS: Yes (some clients call this SSL) Port: 465 or 587

使用phpmailer就无法正常连接gmail的发信服务器了,并且这个问题一直没有得到phpmailer的官方解决,不过在sf.net上面的讨论里倒是找到了一点资料,采用下面这种方法就可以连接gmail了。

修改class.smtp.php,第101行,把

$this->smtp_conn = fsockopen($host, # the host of the server

改成

$this->smtp_conn = fsockopen(‘ssl://’ . $host, # the host of the server

这样就可以了,就是指定使用ssl协议连接主机,当然php的openssl模块必须打开:

extension=php_openssl.dll

但是这样就不能使用非ssl的主机了,我也不像在include目录下面放两份phpmailer,于是,又琢磨出了一种更好的方式:

打开class.phpmailer.php,在大概543行附近,函数SmtpConnect()中,找到:

$this->smtp->do_debug = $this->SMTPDebug; $hosts = explode(“;”, $this->Host); $index = 0; $connection = ($this->smtp->Connected()); // Retry while there is no connection while($index < count($hosts) && $connection == false) { if(strstr($hosts[$index], ":")) list($host, $port) = explode(":", $hosts[$index]); else { $host = $hosts[$index]; $port = $this->Port; }

这一段的部分功能就是,如果你输入的主机名中带有端口号,自动的识别出来,设想虽好,但就是这部分让我们无法直接在调用的时候使用ssl格式的主机名,因为“ssl://xxx”的形式会被误认为是主机:端口号的形式,另外端口号一般都比较固定,我们手工设置好了,也不必一定要和主机一起赋值,所以在上面的代码后面添加:

//Modify by Fwolf @ 2006-4-14, to enable ssl mail connection $host = $this->Host; $port = $this->Port;

就可以了,使用正常smtp主机的时候,用法不变,使用gmail的时候,使用ssl://smtp.gmail.com作为主机名就可以了,唯一稍微麻烦一些的就是端口需要手工指定——其实也不麻烦。

按照上面的配置更改后,使用gmail账号发送邮件时还会有一条警告信息:

Warning: fgets(): SSL: fatal protocol error in H:\php_includes\phpmailer_ssl\cla ss.smtp.php on line 1024

这各警告信息在php的帮助里面有,好像是在使用ssl连接的时候,读文件读到文件尾的时候出现的问题,需要手工屏蔽,或者人为控制读的长度,我们用最简单的方式禁止警告信息显示就可以了,找到class.smtp.php的1024行,在fgets($this->smtp_conn,515)函数前面加上个@就可以了。

下面是一个完整的使用phpmailer发送邮件的函数:

function send_mail($to_address, $to_name ,$subject, $body, $attach = ”) { //使用phpmailer发送邮件 require_once(“phpmailer/class.phpmailer.php”); $mail = new PHPMailer(); $mail->IsSMTP(); // set mailer to use SMTP $mail->CharSet = ‘utf-8’; $mail->Encoding = ‘base64’; $mail->From = ‘fwolf.mailagent@gmail.com’; $mail->FromName = ‘Fwolf’; //$mail->Sender = ‘fwolf.mailagent@gmail.com’; //$mail->ConfirmReadingTo = ‘fwolf.mailagent@gmail.com’; //回执? $mail->Host = ‘ssl://smtp.gmail.com’; $mail->Port = 465; //default is 25, gmail is 465 or 587 $mail->SMTPAuth = true; $mail->Username = “fwolf.mailagent@gmail.com”; $mail->Password = “xxx”; $mail->>ddAddress($to_address, $to_name); //$mail->AddReplyTo(‘fwolf.mailagent@gmail.com’, “Fwolf”); //针对gmail无用,gmail是In-Reply-To:,phpmailer默认生成的是Reply-to: $mail->WordWrap = 50; if (!empty($attach)) $mail->AddAttachment($attach); $mail->IsHTML(false); $mail->Subject = $subject; $mail->Body = $body; //$mail->AltBody = “This is the body in plain text for non-HTML mail clients”; if(!$mail->Send()) { echo “Mail send failed.\r\n”; echo “Error message: ” . $mail->ErrorInfo . “\r\n”; return false; } else { echo(“Send $attach to $to_name <$to_address> successed.\r\n”); return true; } //echo “Message has been sent”; // }

update @ 2006-11-3

感谢RainChen提供的fgets出错提示的更好解决办法(位置大概在class.smtp.php的1024行): 将:

fgets($this->smtp_conn,515)

改为:

!feof($this->smtp_conn) && $str = fgets($this->smtp_conn,515)

这样的代码就规范多了,极力不提倡使用@来屏蔽错误信息。 (未测试, 但有网友反映这种改法是不行的)

Update @ 2008-04-14

试了最新的phpMailer 2.1.0 Beta 2,不用作任何修改,就可以用gmail账号发送邮件了,[官方文档](http://phpmailer.codeworxtech.com/changelog.html)中还给出了例子,和我用的方法不太一样。

不过[中文附件的问题](176)依然没有解决,需要自己hack。

53 thoughts on “终于能够通过phpmailer使用gmail账号发送邮件了”

  1. 收信又怎么办呢? 老不成功。 我从一个php邮件系统中挖出来的收pop3的代码。 收其他的,如163,sohu的都完全正常。

  2. 用了你的方法, 但出现:

    Warning: fsockopen() [function.fsockopen]: unable to connect to ssl://smtp.gmail.com:465 (Unable to find the socket transport “ssl” – did you forget to enable it when you configured PHP?) in D:\www\phpgmailer\class.smtp.php on line 105 Message was not sent

    Mailer Error: SMTP Error: Could not connect to SMTP host.

    什么没改过来?

  3. 为什么我试的时候说 no SSL support in this build in 但是apache的ssl已经可以用了,php中的php_openssl.dll开启用了。

  4. no SSL support in this build in 感觉还是php的openssl没有正确启用 另外再检查一下php的errorlog,看看有没有其他的原因,记得开error E_ALL 一般都能找到有用的信息的

  5. Pingback: JL空间
  6. 我用了,可以发送邮件。但是感觉很慢,比普通的smtp连接,明显感觉慢很多。 但是也有问题: warning: fgets(): SSL: fatal protocol error in /var/www/pages/drupal-4.7.3/includes/phpmailer/class.smtp.php on line 1024.

    这个警告我一直去不掉。我在前面加了@还是不行。 每次发邮件都有错误,很不好啊。 我的php.ini也设置了不显示错误的啊。

  7. to popo: 两点感觉: 1、似乎openssl或者ssl协议支持的其他地方没有安装或者设置正确 2、php.ini是不是没有正确启用(这一点会同时影响到1)?如果是用命令行执行的话,有时候使用的是另外一个php.ini文件,和apache使用的不是一个文件,这一点至少在ubuntu里面是的。

  8. phpinfo() 显示 Configuration File (php.ini) Path /etc/php.ini (正确) …. openssl OpenSSL support enabled
    OpenSSL Version OpenSSL 0.9.8c 05 Sep 2006
    … 而且我的确是能发出信的啊,这个说明确实是openssl启用啊。

    /etc/php.ini 设置 display_errors = Off log_errors = On error_log = /var/log/php.error.log … 还是不能用。 哦,我明白了,你是windows,我是linux。

  9. fgets的修改建议改为: 将: fgets($this->smtp_conn,515) 改为: !feof($this->smtp_conn) && $str = fgets($this->smtp_conn,515)

    这样才是比较smooth的hack

  10. to rainchen: 我用照你的改了,可是还是老错误

    to SG: 不知道你用的php哪个版本,我用的是php5.2.0,发现只在php.ini里取消opensl前的注释是不够的,还应该复制php目录下的ssleay32.dll和libeasy32.dll到你的windows\system32目录下

    to 博主: 你的介绍很有用,谢谢 不过你也没有把怎么打开openssl说清楚,至少我是花了半天时间来启动openssl功能,而且在php4.4.*版本上还没成功.

  11. To zerofault: openssl的启用说明在php的手册上说的很清楚,你没有去查么?:) 我在很久以前遇到过这个问题,不过现在已经比较熟悉了 所以没有介绍,所以还要谢谢你的补充。

Leave a Reply

Your email address will not be published. Required fields are marked *