0

I’m using PHPMailer for single emails successfully for a long time.

Now I’m trying to upgrade my back-office reservation system so it will send each day to our suppliers the next day reservations. We have approximately 150-300 reservations per day while each reservation requires its own separate email.

My script receives an array of reservation Id’s, loops them and for each one retrieves its details, set the html and send it with PHPMailer using the following script:

$mail = new PHPMailer();
$mail->IsSMTP();
$mail->SMTPAuth = true;
$mail->SMTPAutoTLS = false;
$mail->Host = '11.222.33.444';
$mail->Port = 25;
$mail->Username = 'user@domain.com';
$mail->Password = '1234';
$mail->isHTML(true);
$mail->SetFrom('admin@client.com', 'admin');
$mail->Subject = $subject;
$mail->Body = $body;
$mail->CharSet = 'UTF-8';
$mail->AddAddress($service->supplier_email);
$mail->addCC('user@domain.com'); 
$strat_time = microtime(true);
$mail->Send();
echo microtime(true) - $strat_time . "<br>";

The problem is its taking long long time (approximately 5 second just execute to the $mail->Send() function, it means that in production the script needs to run about 25-35 minutes to send all reservations).

I’m not sure for how long to extend the ‘max_execution_time’ or if its smart to let the script to run for so long.

I have tried to switch the IsSMTP() to IsMail(), the script runs much faster but it seems no emails are received.

I would highly appreciate any kind of advice or direction about the most efficient way to perform the above task

******* Added after comments *******

@Synchro I have tried the approach you referred to, but i get minor improve in the execution time (about 20%), certainly not 250 messages per second. This is my test code:

$mail = new PHPMailer();
$mail->IsSMTP();
$mail->SMTPAuth = true;
$mail->SMTPKeepAlive = true;
$mail->SMTPAutoTLS = false;
$mail->Host = '******';
$mail->Port = 25;
$mail->Username = '*****';
$mail->Password = '****';
$mail->isHTML(true);
$mail->SetFrom('******', '*****');
$mail->CharSet = 'UTF-8';
foreach ($array as $value) {
    $mail->Subject = $value->subject;
    $mail->Body = $value->body;
    $mail->AddAddress($value->mail);
    $mail->Send();
    $mail->clearAddresses();
}

Can you recognize what I'm doing wrong?

Kots
  • 1
  • 2
  • 1
    I would advise to use either queue or set cron job for every 5-10 minutes and will get the reservation data in chunks of 50 and send them at one cron job execution. And with next cron, take next 50 reservations. – Himanshu Upadhyay Dec 05 '17 at 10:52
  • The thing is that the system doesn't do the action by itself. The user select the date he want to order and select the reservations in that day that he want to send. – Kots Dec 05 '17 at 10:58
  • So in that case, queue will be your solution. – Himanshu Upadhyay Dec 05 '17 at 11:02
  • Read [the PHPMailer docs on how to send to lists efficiently](https://github.com/PHPMailer/PHPMailer/wiki/Sending-to-lists). I have no problem sending ~250 messages per second using this approach, but it is dependent on having a decent mail server to send through. – Synchro Dec 05 '17 at 11:12
  • Bear in mind that a local mail server *is* a queueing system; you don't need to invent a whole new queue layer on the client (sending) side. – Synchro Dec 05 '17 at 11:14
  • @Synchro I have tried without sufficient success what you suggested. I add the code to the original question. – Kots Dec 05 '17 at 14:48
  • If you set `SMTPDebug = 2` you'll see the SMTP conversation as it happens with timestamps for each command, so you will be able to see exactly what is taking the time. BTW it's unusual to support auth on port 25 without encryption. Is your mail server nearby, e.g. on localhost, or at least on your local network? – Synchro Dec 05 '17 at 14:52
  • Kinda ugly solution, but you could use `popen` https://stackoverflow.com/a/4350418/1214800 – brandonscript Dec 05 '17 at 15:19
  • @brandonscript I do not know how to pass arguments or parameters to the script using popen – Kots Dec 06 '17 at 11:07
  • @Synchro I used the SMTPDebug = 2, the delay is always at same point: 2017-12-06 14:03:36 CLIENT -> SERVER: RCPT TO: 2017-12-06 14:03:40 I'm not sure what does it mean. – Kots Dec 06 '17 at 14:07
  • Are you saying there is a big time difference before or after this command? The command before this is `MAIL FROM`, and that will cause the server to check that this is a valid source address for relaying, that it passes SPF checks (which implies DNS lookup overhead). If it's the `RCPT TO` that's taking the time, there may be other lookups required by the mail server. – Synchro Dec 06 '17 at 14:13
  • @Synchro after, is the RCPT TO that's taking the time. What can I do? – Kots Dec 06 '17 at 14:22
  • Is forking like brandonscript suggested is a good idea? – Kots Dec 06 '17 at 14:23
  • It sounds like the bottleneck is in your mail server, so there's not much you can do from your script. You could run a local mail server to submit to (which will be very fast), and have that relay through your other server. Alternatively investigate what your mail server is doing that takes a long time. – Synchro Dec 06 '17 at 15:12

0 Answers0