简体   繁体   English

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

[英]PHPMailer using Gmail SMTP slow when sending emails

I found few older threads that have a similar issue but most of them didn't have answers or if they had, the suggestions weren't relevant in my case. 我发现很少有较旧的线程有类似的问题,但大多数没有答案,或者如果有的话,这些建议与我的情况无关。

I had a complete setup at one point with PHP mail function and it worked great. 我在一个点上完成了PHP邮件功能的设置,效果很好。 I had to format my hard drive at one point and setup the server from scratch. 我不得不在一点上格式化硬盘并从头开始设置服务器。 Afterwards, PHP mail function became slow. 之后,PHP邮件功能变得缓慢。 While researching solutions for that, I found that most people recommended PHPMailer. 在研究解决方案时,我发现大多数人都推荐使用PHPMailer。 I switched to that but the problem still persisted. 我改用了,但问题仍然存在。

Most of the time, I am sending at least two emails per page with different bodies but using the same object. 大多数情况下,我每页至少发送两封电子邮件,但是使用相同的对象。 There is about 3-4 second delay. 大约有3-4秒的延迟。 Please find the relevant code below ($email1 and $email2 are arrays containing valid email addresses): 请在下面找到相关代码($ 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();
}

I don't see any error through debug and messages, it just takes longer than usual to send the email. 我没有通过调试和消息看到任何错误,发送电子邮件只需要比平时更长的时间。

What I've tried: 我尝试过的:

  • I turned off the Firewall just to test it, and it's the same. 我关闭防火墙只是为了测试它,它是一样的。
  • Switched to 'tls', that made it even slower 切换到'tls',这使它更慢
  • Sent each email using an object, that gave a 3-4 second delay for each email 使用对象发送每封电子邮件,每封电子邮件延迟3-4秒
  • Played around with optional configuration, comment out or set false, all with the same result 使用可选配置,注释掉或设置为false,都具有相同的结果

Is there anything else missing in the mailer setup or is there some behind-the-scenes configuration that I should check? 邮件程序设置中是否还有其他内容,或者我应该检查一些幕后配置? Thanks 谢谢

The slowness (or failure due to timeouts) is because Google supports IPv6 addressing but your network does not. 缓慢(或由于超时导致的失败)是因为Google支持IPv6寻址,但您的网络却不支持。 (eg Digital Ocean does not yet support IPv6 for SMTP traffic). (例如Digital Ocean尚不支持IPv6用于SMTP流量)。 So, use this: 所以,使用这个:

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

gethostbyname() will return the IPv4 address. gethostbyname()将返回IPv4地址。

For me, my PHPMailer script went from ~2 minutes execution time to <4 seconds 对我来说,我的PHPMailer脚本从大约2分钟的执行时间变为<4秒

If the delay between sending the emails is really a critical issue, have you considered implementing a form of multithreading? 如果发送电子邮件之间的延迟确实是一个关键问题,您是否考虑过实施多线程? The delay per message may be the same, but it would essentially be cut in half if you send two enails at a time. 每条消息的延迟可能是相同的,但如果你一次发送两个enails,它基本上会减少一半。

An easy way to do this would be to implement a queue, and the message is sent via a non-blocking HTTP/SQL call. 一种简单的方法是实现队列,并通过非阻塞HTTP / SQL调用发送消息。 In this way you could send as many as you like with a minimal delay. 通过这种方式,您可以以最小的延迟发送任意数量的内容。

I also suggest, if possible, find the gmail server with the lowest latency and add it to your hosts file to elimiinate DNS lookups. 我还建议,如果可能的话,找到延迟最低的gmail服务器并将其添加到您的hosts文件中以消除DNS查找。

Also some performance hints: You only need to require_once() for the include file, but you're requiring it on every call (as an aside, include_once() is faster). 还有一些性能提示:你只需要require_once()作为包含文件,但是你需要在每次调用时都需要它(顺便说一句,include_once()更快)。 Why not create a $mail object only once and reuse it whenever you need to call sendemail()? 为什么不只创建一个$ mail对象并在需要调用sendemail()时重用它?

Also why not pass message1, subject1, etc. as one array and message2, subject2, etc. as a second array? 另外为什么不将message1,subject1等作为一个数组传递,将message2,subject2等作为第二个数组传递? Passing fewing parameters during procedure calls in general (at least in classical programming) tends to speed things up. 通常在过程调用期间传递几个参数(至少在经典编程中)往往会加快速度。

As an aside -- no idea if this is possible -- Perhaps there is a way to maintain a constant connection to smtp.gmail.com. 暂时不说 - 不知道这是否可行 - 也许有一种方法可以保持与smtp.gmail.com的持续连接。 This would eliminate a lot of overhead as well. 这也将消除大量开销。

Also, is relaying your messages through your own meial server an option? 此外,通过您自己的meial服务器中继您的消息选项? It'd elimiinate the delay. 它会消除延迟。

Finally, I came across this response from Google: [ Gmail Sending Limits ` 最后,我遇到了Google的回复:[ Gmail发送限制 `

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.

`

I'd be happy to write a class that conforms to these limits if you need one. 如果你需要,我会很乐意写一个符合这些限制的课程。 Please let me know, shouldn't take too long. 请让我知道,不应该花太长时间。

Recommendation: Use another email host/relay 建议:使用其他电子邮件主机/中继

Sending e-mails is generally a slow activity. 发送电子邮件通常是一项缓慢的活动。 For whatever reason (network traffic, traffic priority, mailer daemon implementation, etc) it takes a lot of time. 无论出于何种原因(网络流量,流量优先级,邮件程序守护程序实现等),都需要花费很多时间。 One way to handle e-mail traffic is to not send it in line with the response you're generating. 处理电子邮件流量的一种方法是不根据您生成的响应发送它。 A better solution is to do it asynchronously. 更好的解决方案是异步执行。 One suggestion above (to use a work queue and empty the work queue using a cron job) is great. 上面的一个建议(使用工作队列并使用cron作业清空工作队列)非常棒。 The only caveat (depending on the volume of traffic) is that the time to send all the e-mails in the work queue may be greater than the time interval between cron tasks. 唯一的警告(取决于流量)是发送工作队列中所有电子邮件的时间可能大于cron任务之间的时间间隔。

Another option (and this is my preferred option) is to use a messaging layer like Rabbit MQ (probably more good books/posts on the topic) or Zero MQ (if you're a more solid programmer). 另一个选项(这是我的首选选项)是使用像Rabbit MQ这样的消息传递层(可能是关于该主题的更好的书籍/帖子)或Zero MQ(如果你是一个更坚实的程序员)。 In this case you create an event "send-email" and push it to a queue. 在这种情况下,您创建一个事件“send-email”并将其推送到队列。 There are multiple queue listeners. 有多个队列侦听器。 Once your PHP script pushes the e-mail to send to a queue, it's done and moves on. 一旦您的PHP脚本将电子邮件发送到队列,它就会完成并继续前进。 One of the queue listeners picks up the message and sends the e-mail. 其中一个队列侦听器接收消息并发送电子邮件。

This can allow you great flexibility in building a solution. 这可以让您在构建解决方案时具有极大的灵活性。 Since most of the time to send e-mails appears to be wait time, you could run 10 consumer programs to send e-mail, knowing that most of the time the individual senders will be idle. 由于大多数时间发送电子邮件似乎是等待时间,因此您可以运行10个消费者程序来发送电子邮件,因为他们知道大多数时间个人发件人都会闲置。 (It's been my experience in sending e-mail is long wait time but not high CPU load). (我发送电子邮件的经验是等待时间很长但CPU负载不高)。 By running a fixed number of consumers (your PHP script is the producer), you can throttle the rate at which you send mail/devote system resources to sending mail. 通过运行固定数量的使用者(您的PHP脚本是生产者),您可以限制发送邮件/投入系统资源以发送邮件的速率。

I have implemented variants of this approach and the up side is that other things that need to happen that are slow (like resizing images) can be handled using the same pattern. 我已经实现了这种方法的变体,而另一方面是需要发生的其他缓慢的事情(比如调整图像大小)可以使用相同的模式来处理。 As you grow you can off-load portions of the work to other machines simply by starting up consumers on those machines. 随着您的成长,您可以通过在这些计算机上启动使用者来将部分工作卸载到其他计算机上。

From server where you have the PHPMailer hosted, try: 从托管PHPMailer的服务器,尝试:

telnet smtp.gmail.com 465

You'll see how long it took to establish connection between your server and smtp.gmail.com 您将看到在服务器和smtp.gmail.com之间建立连接所需的时间

One of solutions to remove waiting from client to server is to move sending emails to crontab. 删除从客户端到服务器的等待的解决方案之一是将电子邮件发送到crontab。 So when client clicks for sending, php adds email and message to queue, and then every minute you send queued messages by cron. 因此,当客户端点击发送时,php会将电子邮件和消息添加到队列中,然后每分钟都会通过cron发送排队的消息。

In addition you can add debug info into your script by having $start = microtime(true); 此外,您可以通过$start = microtime(true);将调试信息添加到脚本中$start = microtime(true); at the top of the script and echoing echo "Line ".__LINE__.":"round(microtime(true) - $start, 3)."sec<br>"; 在脚本的顶部并回显echo "Line ".__LINE__.":"round(microtime(true) - $start, 3)."sec<br>"; at every line. 在每一行。

From your description I'd guess it looks like DNS caching issue perhaps. 根据您的描述,我猜它可能看起来像DNS缓存问题。 You may want to investigate in more details time being spent to resolve DNS record 您可能希望更详细地调查用于解析DNS记录的时间

  • use curl_getinfo for detailed info on time being spent on the connection fo SMTP google, eg name lookup time, resolving, etc... see http://www.php.net/manual/en/function.curl-getinfo.php . 使用curl_getinfo获取有关SMTP google连接时间的详细信息,例如名称查找时间,解析等...请参阅http://www.php.net/manual/en/function.curl-getinfo.php This will help you to isolate which part of lookup is problematic. 这将帮助您确定哪个部分的查找存在问题。
  • to exclude DNS issues you may want to set your DNS IP server to Google's public DNS server 8.8.8.8 or 8.8.4.4 - see https://developers.google.com/speed/public-dns/ . 要排除DNS问题,您可能需要将DNS IP服务器设置为Google的公共DNS服务器8.8.8.8或8.8.4.4 - 请参阅https://developers.google.com/speed/public-dns/ If problem still persists, you may have misconfigured your network - then try connecting to SMTP gmail from another computer or hosting to check latency time. 如果问题仍然存在,您可能错误配置了网络 - 然后尝试从另一台计算机或托管服务器连接到SMTP gmail以检查延迟时间。

From application point of view, it might be advisable for you to send emails asynchronously rather than synchronously, meaning via background eg CRON job. 从应用程序的角度来看,建议您异步发送电子邮件而不是同步发送电子邮件 ,这意味着通过后台例如CRON作业。 This is solution suitable if you send say more than 10 emails per hour. 如果您每小时发送超过10封电子邮件,这是适合的解决方案。 Ensures full control over email stack queue, tracking errors, no latency or page crashes for frontend users. 确保完全控制电子邮件堆栈队列,跟踪错误,没有延迟或前端用户的页面崩溃。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM