Создание PHP-почты () асинхронно

У меня есть mail() PHP mail() использующая ssmtp, у которой нет очереди / очереди, и синхронно с AWS SES.

Я слышал, что могу использовать SwiftMail для создания катушки, но я не мог разработать простой рецепт, чтобы использовать его, как в настоящее время с mail() .

Я хочу, чтобы наименьшее количество кода предоставляло асинхронную почту. Мне все равно, если письмо не отправлено, но было бы неплохо иметь журнал.

Какие-нибудь простые советы или трюки? Не удалось запустить полномасштабный почтовый сервер? Я думал, что оболочка sendmail может быть ответом, но я не мог работать nohup .

PHP-FPM

Вы должны запустить php- fpm для fastcgi_finish_request, чтобы быть доступным.

 echo "I get output instantly"; fastcgi_finish_request(); // Close and flush the connection. sleep(10); // For illustrative purposes. Delete me. mail("test@example.org", "lol", "Hi"); 

Довольно легко выполнить любой произвольный код для обработки после завершения запроса пользователю:

 $post_processing = []; /* your code */ $email = "test@example.org"; $subject = "lol"; $message = "Hi"; $post_processing[] = function() use ($email, $subject, $message) { mail($email, $subject, $message); }; echo "Stuff is going to happen."; /* end */ fastcgi_finish_request(); foreach($post_processing as $function) { $function(); } 

Рабочий стол в Хипстер

Мгновенно тайм-аут завитка и пусть новый запрос справится с этим. Я делал это на общих хостах, пока это не было круто. (это никогда не круто)

 if(!empty($_POST)) { sleep(10); mail($_POST['email'], $_POST['subject'], $_POST['message']); exit(); // Stop so we don't self DDOS. } $ch = curl_init("http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); curl_setopt($ch, CURLOPT_TIMEOUT, 1); curl_setopt($ch, CURLOPT_NOSIGNAL, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, [ 'email' => 'noreply@example.org', 'subject' => 'foo', 'message' => 'bar' ]); curl_exec($ch); curl_close($ch); echo "Expect an email in 10 seconds."; 

У вас есть много способов сделать это, но обработка потока не обязательно является правильным выбором.

  • register_shutdown_function : вызывается функция выключения после отправки ответа. Это не очень асинхронно, но, по крайней мере, это не замедлит ваш запрос. Что касается реализации, см. Пример.
  • Swift pool : используя symfony, вы можете легко использовать катушку.
  • Очередь : зарегистрируйте почту, которая будет отправлена ​​в системе очередей (может быть выполнена с помощью RabbitMQ, MySQL, redis или что-то еще), затем запустите cron, который потребляет очередь. Может быть сделано с чем-то столь же простым, как таблица MySQL с такими полями, как from , to , message , sent (boolean set to true когда вы отправили электронное письмо).

Пример с register_shutdown_function

 <?php class MailSpool { public static $mails = []; public static function addMail($subject, $to, $message) { self::$mails[] = [ 'subject' => $subject, 'to' => $to, 'message' => $message ]; } public static function send() { foreach(self::$mails as $mail) { mail($mail['to'], $mail['subject'], $mail['message']); } } } //In your script you can call anywhere MailSpool::addMail('Hello', 'contact@example.com', 'Hello from the spool'); register_shutdown_function('MailSpool::send'); exit(); // You need to call this to send the response immediately 

Используйте AWS SES с PHPMailer .

Этот способ очень быстрый (сотни сообщений в секунду), и кода не требуется.

 $mail = new PHPMailer; $mail->isSMTP(); // Set mailer to use SMTP $mail->Host = 'ssl://email-smtp.us-west-2.amazonaws.com'; // Specify main and backup SMTP servers $mail->SMTPAuth = true; // Enable SMTP authentication $mail->Username = 'blah'; // SMTP username $mail->Password = 'blahblah'; // SMTP password $mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted $mail->Port = 443; 

Не уверен, правильно ли я правильно понял ваш вопрос, но я надеюсь, что это поможет.

Pthreads – ваш друг 🙂
Это пример того, как я сделал в своем производственном приложении

 class AsynchMail extends Thread{ private $_mail_from; private $_mail_to; private $_subject; public function __construct($subject, $mail_to, ...) { $this->_subject = $subject; $this->_mail_to = $mail_to; // ... } // ... // you must redefine run() method, and to execute it we must call start() method public function run() { // here put your mail() function mail($this->_mail_to, ...); } } 

ПРИМЕР ТЕСТИРОВАНИЯ SCRIPT

 $mail_to_list = array('Shigeru.Miyamoto@nintendo.com', 'Eikichi.Kawasaki@neogeo.com',...); foreach($mail_to_list as $mail_to) { $asynchMail = new AsynchMail($mail_to); $asynchMail->start(); } 

Дайте мне знать, если вам нужна дополнительная помощь для установки и использования потока в PHP
Для системы ведения журнала я настоятельно рекомендую вам использовать Log4PHP : мощный и простой в использовании и настроить
Для отправки писем я также настоятельно рекомендую вам использовать PHPMailer

Я использую асинхронное выполнение php с помощью beanstalkd .
Это простая очередь сообщений, очень легкая и легко интегрируемая.

Используя следующую php-оболочку для php https://github.com/pda/pheanstalk, вы можете сделать что-то следующим образом, чтобы внедрить почтового рабочего:

 use Beanstalk\Client; $msg="dest_email##email_subject##from_email##email_body"; $beanstalk = new Client(); $beanstalk->connect(); $beanstalk->useTube('flux'); // Begin to use tube `'flux'`. $beanstalk->put( 23, // Give the job a priority of 23. 0, // Do not wait to put job into the ready queue. 60, // Give the job 1 minute to run. $msg // job body ); $beanstalk->disconnect(); 

Затем задание будет выполнено в коде, помещенном в отдельный файл php.
Что-то вроде:

 use Beanstalk\Client; $do=true; try { $beanstalk = new Client(); $beanstalk->connect(); $beanstalk->watch('flux'); } catch (Exception $e ) { echo $e->getMessage(); echo $e->getTraceAsString(); $do = false; } while ($do) { $job = $beanstalk->reserve(); // Block until job is available. $emailParts = explode("##", $job['body'] ); // Use your SendMail function here if ($i_am_ok) { $beanstalk->delete($job['id']); } else { $beanstalk->bury($job['id'], 20); } } $beanstalk->disconnect(); 

Вы можете запустить этот файл php отдельно, как независимый процесс php. Предположим, вы сохранили его как sender.php , он будет запущен в Unix как:

php /path/to/sender/sender.php & && disown

Эта команда будет запускать файл и, кроме того, позволяет закрыть консоль или выйти из текущего пользователя без остановки процесса.
Убедитесь, что ваш веб-сервер использует тот же файл php.ini, что и ваш интерпретатор командной строки php. ( Можно решить, используя ссылку на ваш любимый php.ini )

Я надеюсь, что это помогает.

Ваш лучший выбор – с укладкой или наложением буфера. Это довольно просто и может быть описано в 2 этапа.

  • Сохраните свои электронные письма в таблице с отмеченным флагом в текущем потоке.
  • Используйте cron или ajax для повторного вызова файла php почты, который получит 10 или 20 неотправленных писем из вашей базы данных, помечает их как отправленные и отправляет их по вашему любимому методу рассылки.

Легкий способ сделать это – вызвать код, который обрабатывает ваши письма асинхронно.

Например, если у вас есть файл с именем email.php со следующим кодом:

 // Example array with e-mailaddresses $emailaddresses = ['example1@test.com', 'example2@example.com', 'example1@example.com']; // Call your mail function mailer::sendMail($emailaddresses); 

Затем вы можете вызвать это асинхронно в обычном запросе, например

 exec('nice -n 20 php email.php > /dev/null & echo $!'); 

И запрос завершится, не дожидаясь, когда email.php завершит отправку электронных писем. Регистрация также может быть добавлена ​​в файл, который отправляет сообщения электронной почты.

Переменные могут быть переданы в exec между вызываемым именем файла и > /dev/null как

 exec('nice -n 20 php email.php '.$var1.' '.$var2.' > /dev/null & echo $!'); 

Убедитесь, что эти переменные безопасны с помощью escapeshellarg () . В названном файле эти переменные могут использоваться с $ argv