phpemailamazon-web-servicesasynchronousamazon-ses

Making PHP's mail() asynchronous


I have PHP's mail() using ssmtp which doesn't have a queue/spool, and is synchronous with AWS SES.

I heard I could use SwiftMail to provide a spool, but I couldn't work out a simple recipe to use it like I do currently with mail().

I want the least amount of code to provide asynchronous mail. I don't care if the email fails to send, but it would be nice to have a log.

Any simple tips or tricks? Short of running a full blown mail server? I was thinking a sendmail wrapper might be the answer but I couldn't work out nohup.


Solution

  • php-fpm

    You must run php-fpm for fastcgi_finish_request to be available.

    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");
    

    It's pretty easy queuing up any arbitrary code to processed after finishing the request to the user:

    $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();
    }
    

    Hipster background worker

    Instantly time-out a curl and let the new request deal with it. I was doing this on shared hosts before it was cool. (it's never cool)

    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.";