Подтвердить что ты не робот

Создание PHP mail() асинхронно

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

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

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

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

4b9b3361

Ответ 1

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("[email protected]", "lol", "Hi");

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

$post_processing = [];
/* your code */
$email = "[email protected]";
$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();
}

Работник фонового рабочего Hipster

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

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' => '[email protected]',
  'subject' => 'foo',
  'message' => 'bar'
]);

curl_exec($ch);
curl_close($ch);

echo "Expect an email in 10 seconds.";

Ответ 2

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

  • register_shutdown_function: вызывается функция выключения после отправки ответа. Это не очень асинхронно, но, по крайней мере, это не замедлит ваш запрос. Что касается реализации, см. Пример.
  • Swift pool: используя symfony, вы можете легко использовать катушку.
  • Очередь: зарегистрируйте почту, отправляемую в системе очередей (может быть выполнена с помощью RabbitMQ, MySQL, redis или что-то еще), затем запустите cron, который потребляет очередь. Может быть сделано так же просто, как таблица MySQL с такими полями, как from, to, message, sent (boolean устанавливается на 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', '[email protected]', 'Hello from the spool');


register_shutdown_function('MailSpool::send');

exit(); // You need to call this to send the response immediately

Ответ 3

Используйте 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; 

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

Ответ 4

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('[email protected]', '[email protected]',...);
foreach($mail_to_list as $mail_to) {
    $asynchMail = new AsynchMail($mail_to);
    $asynchMail->start();
}

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

Ответ 5

Я использую асинхронное выполнение 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)

Надеюсь, это поможет.

Ответ 6

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

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

// Example array with e-mailaddresses
$emailaddresses = ['[email protected]', '[email protected]', '[email protected]'];

// 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

Ответ 7

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

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

Ответ 8

Добро пожаловать в асинхронный PHP https://github.com/shuchkin/react-smtp-client

$loop = \React\EventLoop\Factory::create();

$smtp = new \Shuchkin\ReactSMTP\Client( $loop, 'tls://smtp.google.com:465', '[email protected]','password' );

$smtp->send('[email protected]', '[email protected]', 'Test ReactPHP mailer', 'Hello, Sergey!')->then(
    function() {
        echo 'Message sent via Google SMTP'.PHP_EOL;
    },
    function ( \Exception $ex ) {
        echo 'SMTP error '.$ex->getCode().' '.$ex->getMessage().PHP_EOL;
    }
);

$loop->run();