使用Gmail SMTP的PHPMailer在发送电子邮件时速度很慢

时间:2013-11-19 10:03:44

标签: php windows phpmailer

我发现很少有较旧的线程有类似的问题,但大多数没有答案,或者如果有的话,这些建议与我的情况无关。

我在PHP邮件功能的一个点上有一个完整的设置,它工作得很好。我不得不在一点上格式化硬盘并从头开始设置服务器。之后,PHP邮件功能变得缓慢。在研究解决方案时,我发现大多数人都推荐使用PHPMailer。我改用了,但问题仍然存在。

大多数情况下,我每页至少发送两封电子邮件,但是使用相同的对象。大约有3-4秒的延迟。请在下面找到相关代码($ email1和$ email2是包含有效电子邮件地址的数组):

function sendEmail ($email1, $subject1, $message1, $email2, $subject2, $message2) 
{
    require_once('../PHPMailer/class.phpmailer.php');

    $mail = new PHPMailer();
    $mail->IsSMTP(); 
    $mail->SMTPDebug = 0; 
    $mail->SMTPAuth = true; 
    $mail->SMTPSecure = 'ssl';
    $mail->Host = "smtp.gmail.com";
    $mail->Port = 465; 
    $mail->IsHTML(true);
    $mail->Username = $gmail_username;
    $mail->Password = $gmail_password;
    $mail->SetFrom($gmail_address,$email_title);

    $mail->Subject = $subject1;
    $mail->Body = $message1;
    foreach($email1 as $k => $v) {  $mail->AddAddress($v);  }       
    if(!$mail->Send()) {    $emailreturn['cust'] = 0;   } else {    $emailreturn['cust'] = 1;   }
    $mail->ClearAddresses();

    $mail->Subject = $subject2;
    $mail->Body = $message2;
    foreach($email2 as $k => $v) {  $mail->AddAddress($v);  }
    if(!$mail->Send()) {    $emailreturn['partner'] = 0;    } else {    $emailreturn['partner'] = 1;    }
    $mail->ClearAddresses();
}

我没有通过调试和消息看到任何错误,发送电子邮件只需要比平时更长的时间。

我尝试了什么:

  • 我关闭防火墙只是为了测试它,它也是一样的。
  • 切换到'tls',这使得它更慢
  • 使用对象发送每封电子邮件,每封电子邮件的延迟时间为3-4秒
  • 使用可选配置,注释掉或设置为false,所有结果都相同

邮件程序设置中是否还有其他内容,或者是否有一些我应该检查的幕后配置? 感谢

6 个答案:

答案 0 :(得分:20)

缓慢(或由于超时导致的失败)是因为Google支持IPv6寻址,但您的网络却不支持。 (例如Digital Ocean尚不支持IPv6用于SMTP流量)。所以,使用这个:

$mail->Host = gethostbyname("smtp.gmail.com");

gethostbyname()将返回IPv4地址。

对我来说,我的PHPMailer脚本从执行时间约为2分钟到<4秒

答案 1 :(得分:6)

如果发送电子邮件之间的延迟确实是一个关键问题,您是否考虑过实施多线程?每条消息的延迟可能是相同的,但如果你一次发送两个enails,它基本上会减少一半。

执行此操作的简单方法是实现队列,并通过非阻塞HTTP / SQL调用发送消息。通过这种方式,您可以以最小的延迟发送任意数量的内容。

我还建议,如果可能的话,找到延迟最低的gmail服务器并将其添加到您的hosts文件中以消除DNS查找。

还有一些性能提示:您只需要require_once()作为包含文件,但是您在每次调用时都需要它(顺便说一句,include_once()更快)。为什么不只创建一个$ mail对象并在需要调用sendemail()时重用它?

另外为什么不将message1,subject1等作为一个数组传递,将message2,subject2等作为第二个数组传递?在程序调用期间传递一些参数(至少在经典编程中)往往会加快速度。

暂时不说 - 不知道这是否可行 - 也许有一种方法可以保持与smtp.gmail.com的持续连接。这也将消除大量开销。

此外,是通过您自己的meial服务器中继您的消息吗?它消除了延迟。

最后,我遇到了Google的回复: [Gmail Sending Limits `

Thank you for your message.

    I understand you have a query regarding the Google Apps for Business sending limits. As 
mentioned     in our Help Center article at http://support.google.com/a/bin/answer.py?hl=en&
answer=166852,     the daily limitation is 2000 messages in a 24-hour period not day. In general, our 
servers can tolerate one message per second until sending limits are hit. We really don't 
have an hourly or minute limitation for sending. If you send messages too quickly you may     
get rate-limited but the account should not lock out.

By rate-limt, since in general one message per second, if you try to send too many messages per second 
you may get a message telling you that the message cannot be send or you must wait before sending a 
message.

`

如果您需要,我很乐意写一个符合这些限制的课程。请让我知道,不应该花太长时间。

建议:使用其他电子邮件主机/中继

答案 2 :(得分:2)

发送电子邮件通常是一项缓慢的活动。无论出于何种原因(网络流量,流量优先级,邮件程序守护程序实现等),都需要花费很多时间。处理电子邮件流量的一种方法是不根据您生成的响应发送它。更好的解决方案是异步执行。上面的一个建议(使用工作队列并使用cron作业清空工作队列)非常棒。唯一的警告(取决于流量)是发送工作队列中所有电子邮件的时间可能大于cron任务之间的时间间隔。

另一个选项(这是我的首选选项)是使用像Rabbit MQ这样的消息传递层(可能是关于该主题的更好的书籍/帖子)或Zero MQ(如果你是一个更稳定的程序员)。在这种情况下,您创建一个事件“send-email”并将其推送到队列。有多个队列侦听器。一旦您的PHP脚本将电子邮件发送到队列,它就会完成并继续前进。其中一个队列侦听器接收消息并发送电子邮件。

这可以让您在构建解决方案时获得极大的灵活性。由于大多数时间发送电子邮件似乎是等待时间,因此您可以运行10个消费者程序来发送电子邮件,因为他们知道大多数时间个人发件人都会闲置。 (我发送电子邮件的经验是等待时间很长但CPU负载不高)。通过运行固定数量的消费者(您的PHP脚本是生产者),您可以限制发送邮件/投入系统资源以发送邮件的速率。

我已经实现了这种方法的变体,而另一方面是可以使用相同的模式处理其他需要缓慢发生的事情(比如调整图像大小)。随着您的成长,您可以通过在这些计算机上启动使用者来将部分工作卸载到其他计算机上。

答案 3 :(得分:1)

在托管PHPMailer的服务器上,尝试:

telnet smtp.gmail.com 465

您将看到在服务器和smtp.gmail.com

之间建立连接所需的时间

答案 4 :(得分:0)

删除从客户端到服务器的等待的解决方案之一是将电子邮件发送到crontab。因此,当客户点击发送时,php会将电子邮件和消息添加到队列中,然后每分钟都会通过cron发送排队的消息。

此外,您可以通过在脚本顶部放置$start = microtime(true);并在每一行回显echo "Line ".__LINE__.":"round(microtime(true) - $start, 3)."sec<br>";来将调试信息添加到脚本中。

答案 5 :(得分:0)

从您的描述中我猜它看起来可能是DNS缓存问题。您可能希望更详细地调查用于解析DNS记录的时间

  • 使用 curl_getinfo 获取有关SMTP google连接所花费时间的详细信息,例如:名称查找时间,解析等...请参阅http://www.php.net/manual/en/function.curl-getinfo.php。这将帮助您确定哪个部分的查找存在问题。
  • 排除DNS问题,您可能需要将DNS IP服务器设置为 Google的公共DNS服务器8.8.8.8或8.8.4.4 - 请参阅https://developers.google.com/speed/public-dns/。如果问题仍然存在,您可能错误配置了网络 - 然后尝试从另一台计算机或托管服务器连接到SMTP gmail以检查延迟时间。

从应用程序的角度来看,建议您异步发送电子邮件而不是同步发送电子邮件,这意味着通过后台进行操作,例如CRON工作。如果您每小时发送超过10封电子邮件,这是适合的解决方案。确保完全控制电子邮件堆栈队列,跟踪错误,没有延迟或前端用户的页面崩溃。