如何在 Symfony 5 中同时发送同步与异步邮件

admin 百科 13

如何在 Symfony 5 中同时发送同步与异步邮件

本教程详细介绍了如何在 symfony 5 应用中灵活地同时实现同步和异步邮件发送。通过创建自定义 messenger 消息和处理程序,并精确配置 messenger 路由,开发者可以区分处理不同场景下的邮件发送需求。文章涵盖了消息类、处理程序、messenger 配置以及在服务中调度邮件的完整实现,旨在提供一个结构清晰、易于理解的解决方案,避免了默认配置导致的所有邮件都被异步处理的问题。

如何在 Symfony 5 中同时发送同步与异步邮件-第2张图片-佛山资讯网

在现代 Web 应用中,邮件发送是常见的需求,而根据邮件的重要性和时效性,可能需要同步发送(即时响应)或异步发送(后台处理,不阻塞用户请求)。Symfony 框架通过其 Mailer 和 Messenger 组件提供了强大的邮件处理能力。然而,默认的 Messenger 配置可能导致所有通过 MailerInterface::send() 发送的邮件都被路由到异步队列。本教程将指导您如何配置 Symfony 5 应用,以实现对邮件发送模式的精细控制。

理解 Symfony Mailer 与 Messenger 的默认行为

当 Symfony 的 Messenger 组件与 Mailer 组件集成时,MailerInterface::send() 方法实际上会创建一个 Symfony\Component\Mailer\Messenger\SendEmailMessage 类型的消息,并将其调度到 Messenger 消息总线。如果在 framework.messenger.routing 配置中将此消息类型路由到异步传输,那么所有通过 MailerInterface::send() 发送的邮件都将变为异步处理。

为了实现同步和异步邮件的共存,我们需要避免将 Symfony\Component\Mailer\Messenger\SendEmailMessage 直接路由到异步传输。相反,我们将为异步邮件创建一个自定义的消息类型和处理程序,并只将这个自定义消息类型路由到异步传输。

实现异步邮件发送

要实现异步邮件发送,我们需要定义一个自定义的消息类来承载邮件数据,一个消息处理程序来实际发送邮件,并相应地配置 Messenger。

1. 创建异步邮件消息类

首先,创建一个 PHP 类来封装异步邮件所需的所有数据,例如主题、内容、收件人等。这个类将作为 Messenger 消息在总线中传输。

// src/Message/EmailAsync.php
namespace App\Message;

class EmailAsync
{
    private string $subject;
    private string $bodyHtmlTemplate;
    private ?string $bodyTextTemplate;
    private string $recipient;
    private array $context;
    private string $senderEmail; // 假设发件人是固定的或通过配置获取

    public function __construct(
        string $subject,
        string $bodyHtmlTemplate,
        ?string $bodyTextTemplate,
        string $recipient,
        array $context = [],
        string $senderEmail = 'noreply@example.com' // 示例发件人
    ) {
        $this->subject = $subject;
        $this->bodyHtmlTemplate = $bodyHtmlTemplate;
        $this->bodyTextTemplate = $bodyTextTemplate;
        $this->recipient = $recipient;
        $this->context = $context;
        $this->senderEmail = $senderEmail;
    }

    public function getSubject(): string
    {
        return $this->subject;
    }

    public function getBodyHtmlTemplate(): string
    {
        return $this->bodyHtmlTemplate;
    }

    public function getBodyTextTemplate(): ?string
    {
        return $this->bodyTextTemplate;
    }

    public function getRecipient(): string
    {
        return $this->recipient;
    }

    public function getContext(): array
    {
        return $this->context;
    }

    public function getSenderEmail(): string
    {
        return $this->senderEmail;
    }
}

登录后复制

2. 创建异步邮件处理程序

接下来,创建一个消息处理程序来处理 EmailAsync 消息。当 Messenger 收到一个 EmailAsync 消息时,它将调用这个处理程序,由处理程序构建 TemplatedEmail 并使用 MailerInterface 发送。

// src/MessageHandler/EmailAsyncHandler.php
namespace App\MessageHandler;

use App\Message\EmailAsync;
use Symfony\Component\Mime\Address;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;

class EmailAsyncHandler implements MessageHandlerInterface
{
    protected MailerInterface $mailer;

    public function __construct(MailerInterface $mailer)
    {
        $this->mailer = $mailer;
    }

    public function __invoke(EmailAsync $emailAsync): void
    {
        $emailToSend = (new TemplatedEmail())
            ->from(new Address($emailAsync->getSenderEmail()))
            ->to(new Address($emailAsync->getRecipient()))
            ->subject($emailAsync->getSubject())
            ->htmlTemplate($emailAsync->getBodyHtmlTemplate())
            ->textTemplate($emailAsync->getBodyTextTemplate())
            ->context($emailAsync->getContext());

        $this->mailer->send($emailToSend);
    }
}

登录后复制

3. 配置 Messenger 路由

在 config/packages/messenger.yaml 或 config/packages/prod/messenger.yaml 中配置 Messenger,将 App\Message\EmailAsync 消息路由到异步传输。请确保您已经配置了一个异步传输(例如使用 MESSENGER_TRANSPORT_DSN 环境变量)。

# config/packages/messenger.yaml
framework:
    messenger:
        # 配置异步传输,例如使用 RabbitMQ, Redis, 或 Doctrine
        transports:
            async: '%env(MESSENGER_TRANSPORT_DSN)%'

        routing:
            # 将自定义的 EmailAsync 消息路由到异步传输
            'App\Message\EmailAsync': async
            # 确保 Symfony\Component\Mailer\Messenger\SendEmailMessage 没有被路由到 async
            # 如果不在这里指定,它将默认走同步路径,这是我们希望的。
            # 如果你需要一个完全同步的 MailerInterface::send(),请不要在此处添加 SendEmailMessage 的路由。

登录后复制

重要提示: 确保 Symfony\Component\Mailer\Messenger\SendEmailMessage 没有被路由到 async。如果您的 Messenger 配置中没有关于 Symfony\Component\Mailer\Messenger\SendEmailMessage 的路由条目,那么通过 MailerInterface::send() 发送的邮件将默认以同步方式处理,这正是我们实现同步邮件所需要的。

标签: php redis html 编码 app ai 路由 环境变量 配置文件 red

发布评论 0条评论)

还木有评论哦,快来抢沙发吧~