phpswiftmailerbulk-email

Bulk Email with Swiftmailer


I am using SwiftMailer to send bulk emails. At the moment, I do it with the code

$transport = Swift_SmtpTransport::newInstance('*****', 25);
$transport->setUsername('***');
$transport->setPassword('***');

$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance();
$message->setSubject($derBetreff);

$bbc= array('1@web.de','2@web.de','3@web.de',...,'1000@web.de');

$message->setFrom(array('my@email.de' => 'My Name'));           
$message->setTo('my@email.de');
$message->setBcc($bcc);
$message->setBody('Hi this is my email');           
$message->attach(Swift_Attachment::fromPath('myFile.pdf'));     

// Send the message
$result = $mailer->send($message);
echo $result;

where I only send a single email to myself and add ~1000 people in the BCC.

It takes about 9 minutes to execute the code and send one single email and it returns a 'success' message. However, my max_execution_time in my php.ini file is only set to 30 seconds.

My first question is: Why does the max_execution_time not stop my SwiftMailer script?

Secondy, I found the AntiFlood Plugin for Swiftmailer which helps to send bulk emails. The script below sends each member a single email by sending 100 emails first and then pause for 30 seconds and continuing sending the next 100 emails and so on. I have read that this is good practice to circumvent being marked as spam.

My second question is: Does the AntiFlood Plugin need an extraordinary long execution time in order to work? For example, if I send 1000 emails with the script given below and only take the pausing into consideration, then the script runs already at least 4.5 minutes, right?

// Create the Mailer using any Transport
$mailer = Swift_Mailer::newInstance(
  Swift_SmtpTransport::newInstance('smtp.example.org', 25)
);

// Use AntiFlood to re-connect after 100 emails
$mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100));

// And specify a time in seconds to pause for (30 secs)
$mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100, 30));

// Continue sending as normal
for ($lotsOfRecipients as $recipient) {
  ...

  $mailer->send( ... );
}

Solution

  • First of all, the sending of the emails does not happen in the script itself. That is why the max_execution_time is not affected if your server runs on Linux, see the docs:

    The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system(), stream operations, database queries, etc. is not included when determining the maximum time that the script has been running. This is not true on Windows where the measured time is real.

    Thus using the Anti-Flood Plugin is a good idea when you send multiple mails at once.

    However, I think better practice is to store the emails in a database and let a cronjob send X mails from the DB every Y minutes. This way, you do not have a loading script that takes several minutes in front of you (included with the danger of resending if the page gets reloaded). If you use a framework like Laravel, then you could use the build-in mail-query feature which does exactly that.