Массовая электронная почта с Swiftmailer
Я использую SwiftMailer для отправки массовых писем. На данный момент я делаю это с кодом
$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;
где я отправляю только одно электронное письмо самому себе и добавляю ~1000 человек в BCC.
Выполнение кода и отправка одного электронного письма занимает около 9 минут, и он возвращает сообщение "успешно". Тем не менее, мой max_execution_time в моем файле php.ini установлен только на 30 секунд.
Мой первый вопрос: почему max_execution_time не останавливает мой скрипт SwiftMailer?
Вскоре я обнаружил плагин AntiFlood для Swiftmailer, который помогает отправлять массовые электронные письма. Приведенный ниже сценарий отправляет каждому участнику по одному электронному письму, сначала отправив 100 писем, а затем приостановив их на 30 секунд и продолжив отправку следующих 100 писем и так далее. Я читал, что это хорошая практика, чтобы обойти пометку как спам.
Мой второй вопрос: нужно ли плагину AntiFlood необычайно долгое время выполнения для работы? Например, если я отправлю 1000 писем по приведенному ниже сценарию и приму только паузу, сценарий будет запущен уже не менее 4,5 минут, верно?
// 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( ... );
}
2 ответа
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:
Функция set_time_limit() и директива конфигурации max_execution_time влияют только на время выполнения самого скрипта. Любое время, потраченное на действия, которые происходят за пределами выполнения сценария, такие как системные вызовы с использованием system(), потоковые операции, запросы к базе данных и т. Д., Не учитывается при определении максимального времени выполнения сценария. Это не так в Windows, где измеренное время реально.
Таким образом, использование плагина Anti-Flood является хорошей идеей, когда вы отправляете несколько писем одновременно.
Тем не менее, я думаю, что лучше хранить электронные письма в базе данных, и пусть cronjob отправляет X писем из БД каждые Y минут. Таким образом, у вас нет загрузочного скрипта, который занимает несколько минут перед вами (включая опасность повторной отправки, если страница будет перезагружена). Если вы используете фреймворк, такой как Laravel, то вы можете использовать встроенную функцию почтового запроса, которая делает именно это.
Для отправки массовых писем Вам следует воспользоваться услугой брокера, такой как RabbitMQ. Вы должны создать 2 очереди, одну для объединения писем, а другую для отправки электронной почты с помощью Swiftmailer. Каждое письмо будет сообщением rabbitMq.