views:

1042

answers:

4

Hi,

I have recently implemented the Swiftmailer library, but the first time I used it, I got a php timeout error even though it only had to send out mails to around 300 people.. (I should mention that using the set_time_limit(0); workaround is not an option due to restrictions on the server)

The way I use it is like this:

 $transport = Swift_SmtpTransport::newInstance('smtp.mydomain.com',25);
 $mailer = Swift_Mailer::newInstance($transport);
 $message = Swift_Message::newInstance();
 $message->setSubject($_POST['subj']);
 $message->setFrom(array('email' => 'Mysite'));
 $message->setTo($recipients);
 $message->setBody(strip_tags($messagebody));
 $message->addPart($messagebody, 'text/html');
 $numSent = $mailer->batchSend($message);
 printf("Sent %d messages\n", $numSent);

where $recipients is a commaseparated array of emails (built with explode() from a mySQL query)..

I have no idea which part of the above code that generates the script-timeout, and since I use it for a newsletter function, it is rather difficult for me to test or debug it, so I would be really thankful for anyone coming up with a (near) bulletproof solution to this problem :)

Thanks in advance !

Lars

A: 

set_time_limit(0); before the code

EDIT: Okay, since you cannot use the set_time_limit() function, why not put the code that sends the emails inside a function and use register_shutdown_function()? That way, when the script times out it call the function again.

Alix Axel
Original poster specifically notes that this is not an option.
VoteyDisciple
I have to read the whole question next time.
Alix Axel
I never heard about that function - it might actually be a really good idea to wrap the whole thing in a function, and using register_shutdown_function()... I just figured that the issue might be something related more specifically to the Swiftmailer configuration..
How would you implement this? Would it just be a case of: register_shutdown_function(sendmail) at the top of the pageand then function sendmail() { # all the swiftmailer code here }
Yep, that would be it.
Alix Axel
+3  A: 

If you have access to cron, fill up a data base with what you need to send the newsletter, then pop the queue using a cron job that runs a script processing a low number of mails.

If you don't, write a system() statement at the end of the script so it call it self, passing the next newsletter as parameters, then dying. So you will execute the script as many time as you need to send a mail.

e-satis
I do have access to cron (though not for free) and this might actually be a good idea too.. How big "chunks" (how many mails at a time) do you think would be enough to not create a timeout?
I can't guess, but here is a easy way to know : run the code on a machine with no timeout and record the time it takes then divide by the number of mails... If you don't have the time, try little by little, I think 10 mails can't take 30 seconds to be sent.
e-satis
+1  A: 

[Update] well the data below is for me calling the smtp server from my dev box. So from Eastern Europe decent home ADSL to a US SMTP server (my project Staging server). When it all runs on the Staging - so localhost php+mysql+Postfix this baby barely takes 1 second to send 5 individual emails and a BCC to 30 recipients. Quite a sight...

Swiftmaieler actually behaves synchronously and waits for the SMTP server to send each email so that it gets the array with failed mail addys. So if u BCC to 100 recipients the total time is: time taken to talk to the server + time for the server to send 100 emails. Sending 100 individual emails would be 100*(talk time + send time). My Postfix takes 1 second per email and talk time is also 1 sec so it takes 2.5 sec to send an individual email. With the standard 30 sec timeout it would be 12 individual emails or 20 recipients in the BCC. It's all a guessing game actually :P

All these mailer seem to hve been designed with set_time_limit(0) as a must. For someone who has 30 sec timeout the smartest way would be to have a "batch sending" page that stays open and has an ifrme+refresh or Ajax mechanism that calls a "send mail packet" (a small one - 10) method every x seconds. With Ajax you could call again on script response.

cosmin
A: 

Limit recipients number per sending mail. Call script "n" times with offset value via curl or cron and it will not throw timeout. For example set $limit = 20. Then call script n times:

send.php?offset=0
send.php?offset=20

and so on... If your root script (which calls send.php script) will timeout, then you can continue sending mails from your last offset.

Pawka