symfony/mailerの非同期送信処理

symfonyでは少なくとも5.4以降では、symfiny/mailerでもメール送信の非同期処理がデフォルトで有効になっている。

以下はSending Emails with MailerSending Messages Asyncの翻訳。

Sending Messages Async

[$mailer->send($email)] を呼び出すと、電子メールはすぐにトランスポートに送信されます。パフォーマンスを向上させるために、Messengerを利用して、後でMessengerトランスポート経由でメッセージを送信できます。

Messenger のドキュメントに従って、トランスポートを構成することから始めます。すべての設定が完了したら、[$mailer->send()] を呼び出すと、SendEmailMessage メッセージがデフォルトのメッセージ バス ([messenger.default_bus]) を介してディスパッチされます。 [async] というトランスポートがあると仮定すると、そこにメッセージをルーティングできます。

# config/packages/messenger.yaml
framework:
    messenger:
        transports:
            async: "%env(MESSENGER_TRANSPORT_DSN)%"

        routing:
            'Symfony\Component\Mailer\Messenger\SendEmailMessage': async

これにより、メッセージはすぐに配信されるのではなく、後で処理されるようにトランスポートに送信されます (Messenger: Sync & Queued Message Handling を参照してください)。メールの「レンダリング」(計算されたヘッダー、本文のレンダリングなど) も延期され、Messenger ハンドラーによってメールが送信される直前にのみ行われることに注意してください。

非同期の無効化

[message_bus] オプションを使用して、メッセージのディスパッチに使用するバスを構成できます。これを [false] に設定して、Mailer トランスポートを直接呼び出し、非同期配信を無効にすることもできます。

# config/packages/mailer.yaml
framework:
    mailer:
        message_bus: app.another_bus #falseにすると同期的に直接実行される。
TemplatedEmailによる事前レンダリング(6.2以降)

[$mailer->send($email)] を呼び出す前に電子メールをレンダリングする次の例は、Symfony 6.2 で機能します。

電子メールを非同期で送信する場合、そのインスタンスはシリアライズ可能である必要があります。これは Email インスタンスの場合は常に当てはまりますが、TemplatedEmail を送信するときは、[context] がシリアライズ可能であることを確認する必要があります。 Doctrine エンティティのようにシリアル化できない変数がある場合は、それらをより具体的な変数に置き換えるか、[$mailer->send($email)] を呼び出す前にメールをレンダリングします。

use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\BodyRendererInterface;

public function action(MailerInterface $mailer, BodyRendererInterface $bodyRenderer)
{
    $email = (new TemplatedEmail())
        ->htmlTemplate($template)
        ->context($context)
    ;
    $bodyRenderer->render($email);

    $mailer->send($email);
}

以上がsymfony/mailerの翻訳の内容。この非同期実行がデフォルトで有効なせいで、なぜ送信されないのか悩みまくった。