简体   繁体   中英

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. I had to format my hard drive at one point and setup the server from scratch. Afterwards, PHP mail function became slow. While researching solutions for that, I found that most people recommended 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. Please find the relevant code below ($email1 and $email2 are arrays containing valid email addresses):

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
  • Sent each email using an object, that gave a 3-4 second delay for each email
  • Played around with optional configuration, comment out or set false, all with the same result

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. (eg Digital Ocean does not yet support IPv6 for SMTP traffic). So, use this:

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

gethostbyname() will return the IPv4 address.

For me, my PHPMailer script went from ~2 minutes execution time to <4 seconds

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.

An easy way to do this would be to implement a queue, and the message is sent via a non-blocking HTTP/SQL call. 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.

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). Why not create a $mail object only once and reuse it whenever you need to call sendemail()?

Also why not pass message1, subject1, etc. as one array and message2, subject2, etc. as a second array? 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. This would eliminate a lot of overhead as well.

Also, is relaying your messages through your own meial server an option? It'd elimiinate the delay.

Finally, I came across this response from 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.

`

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. 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.

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). In this case you create an event "send-email" and push it to a queue. There are multiple queue listeners. Once your PHP script pushes the e-mail to send to a queue, it's done and moves on. 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. (It's been my experience in sending e-mail is long wait time but not high CPU load). 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.

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:

telnet smtp.gmail.com 465

You'll see how long it took to establish connection between your server and smtp.gmail.com

One of solutions to remove waiting from client to server is to move sending emails to crontab. So when client clicks for sending, php adds email and message to queue, and then every minute you send queued messages by cron.

In addition you can add debug info into your script by having $start = microtime(true); at the top of the script and echoing 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. You may want to investigate in more details time being spent to resolve DNS record

  • 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 . 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/ . 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.

From application point of view, it might be advisable for you to send emails asynchronously rather than synchronously, meaning via background eg CRON job. This is solution suitable if you send say more than 10 emails per hour. Ensures full control over email stack queue, tracking errors, no latency or page crashes for frontend users.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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