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账号发送邮件了,官方文档中还给出了例子,和我用的方法不太一样。
不过中文附件的问题依然没有解决,需要自己hack。
Related posts
Hi, sorry I dont speak chinese.
when I use your example from a gmail account works fine,
$mail->Host = ’ssl://smtp.gmail.com’; $mail->Port = 465; //default is 25, gmail is 465 or 587
I have my mail hosted in a google account, it use TLS instead of SSL and port 587 then
$mail->Host = ’tls://smtp.gmail.com’; $mail->Port = 587; $mail->Username =’me@mydomain.com’; $mail->Password = ‘mypass’;
GET Error: Language string failed to load: connect_host
Is there an special configuration for mails hosted on google (NO GMAIL) ?
Thanks, richard
Reply
To: Richard I think they work in the same way, have you try change tls: to ssl ? 465 for ssl do same thing to 587 for tls, I have tried in my google apps, just notice below settings, it works fine:
Reply
class.stmp.php这样改没错吧?
function get_lines() { $data = “”; while(!feof($this->smtp_conn) && $str = fgets($this->smtp_conn,515)) { if($this->do_debug >= 4) { echo “SMTP -> get_lines(): $data was \”$data\”" . $this->CRLF; echo “SMTP -> get_lines(): $str is \”$str\”" . $this->CRLF; }
Reply
你的主机可能不支持openssl, 也就是说ssl客户端没有安装
Reply
谢谢楼主的文章。我照猫画虎地试了一下,但是总是得到如下信息: SMTP -> FROM SERVER: SMTP -> FROM SERVER: SMTP -> ERROR: EHLO not accepted from server: SMTP -> FROM SERVER: SMTP -> ERROR: HELO not accepted from server: SMTP -> ERROR: AUTH not accepted from server: SMTP -> NOTICE: EOF caught while checking if connected The following From address failed: xxx@gmail.com 什么地方错了吗?
Reply
@geinizhe 好像是连接被服务器拒绝了,检查你向服务器提供的各个参数是否正确。
Reply
谢博主这是我用的代码:
require(“class.phpmailer.php”); $mail = new PHPMailer(); $mail->IsSMTP(); // telling the class to use SMTP $mail->SMTPDebug = true; $mail->Host = ‘smtp.gmail.com’; // SMTP server 注:我在class.smtp.php里加了’ssl://’。因为我加在这里的话总是”can not connect smtp server” $mail->Port = 465; $mail->SMTPAuth = true; // turn on SMTP authentication $mail->Username = “xxx@gmail.com”; // SMTP username $mail->Password = “xxx”;
$mail->From = “xxx@gmail.com”; $mail->FromName = “xxx”; $mail->AddAddress(“xxx@mydomain.com”);
$mail->Subject = “test msg”; $mail->Body = “hi, this is a test msg”;
$mail->Send();
请博主和大家指正。另外,我的HOSTING说我遇到的问题和他们没有关系。
Reply
@geinizhi 我用你的代码发邮件正常,可疑之处就是
$mail->SMTPDebug = true;这一句,可以去掉。Reply
我改用swiftmail。现在可以了。
Reply
$mail->Host = urlencode(‘ssl://smtp.gmail.com’);
$this->smtp_conn = fsockopen( urldecode($host) …
可以完成以上工作
Reply
function get_lines() { $data = “”; stream_set_timeout($this->smtp_conn,25); while(!feof($this->smtp_conn) && $str = fgets($this->smtp_conn,515)) { if($this->do_debug >= 4) { echo “SMTP -> get_lines(): $data was \”$data\”" . $this->CRLF; echo “SMTP -> get_lines(): $str is \”$str\”" . $this->CRLF; } $data .= $str; if($this->do_debug >= 4) { echo “SMTP -> get_lines(): $data is \”$data\”" . $this->CRLF; } # if the 4th character is a space then we are done reading # so just break the loop if(substr($str,3,1) == ” “) { break; } } $info = stream_get_meta_data($this->smtp_conn); if ($info['timed_out']) { echo ‘Connection timed out!’; } return $data; } 这样即使超时感觉也要好一些.
Reply
楼主,你好,我看了你们的修改方法,我完全是按照操作来的,还是不能不过,急死人了。 麻烦楼主能否把一个代码实例发送到我的邮箱:tandm@163.com,非常感激。
Reply
phpmailer的新版好像已经支持gmail邮件发送了,你去试试吧。 我这里只卖渔,不卖鱼。
Reply
it seems like e very good web site but my Chinese is not good. It would be great if it might be availible in English too. Thanks.
Reply
Chinese is my mother language, so if you need english version or some relate information, I’ll happy to provide with email, because obviously I have no enough time to translate them all to english.
Reply
i follow your steps but i cant work it always say no SSL support in this build in class.stmp.php line 122 can you help me to fix it?
Reply
@kent You need to enable openssl extension of php, or compile your php with openssl enabled.
Reply
昨天还没问题,今天这个phpmailer忽然不能使用gmail的ssmtp发邮件了,总是socket超时,普通的邮件软件没问题.
Reply