0

0

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

花韻仙語

花韻仙語

发布时间:2025-12-14 09:47:02

|

120人浏览过

|

来源于php中文网

原创

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

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

在现代 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() 发送的邮件将默认以同步方式处理,这正是我们实现同步邮件所需要的。

BlackBox AI
BlackBox AI

AI编程助手,智能对话问答助手

下载

4. 在服务中调度异步邮件

现在,您可以在任何服务中注入 MessageBusInterface 并调度 EmailAsync 消息来发送异步邮件。

// src/Service/MailManagerAsync.php
namespace App\Service;

use App\Message\EmailAsync;
use Symfony\Component\Messenger\MessageBusInterface;

class MailManagerAsync
{
    protected MessageBusInterface $bus;
    private string $defaultSenderEmail; // 可以通过构造函数注入或配置获取

    public function __construct(MessageBusInterface $bus, string $defaultSenderEmail = 'noreply@example.com')
    {
        $this->bus = $bus;
        $this->defaultSenderEmail = $defaultSenderEmail;
    }

    public function sendAsyncMessage(
        string $subject,
        string $htmlTemplate,
        ?string $textTemplate,
        string $to,
        array $context = []
    ): void {
        $emailAsync = new EmailAsync(
            $subject,
            $htmlTemplate,
            $textTemplate,
            $to,
            $context,
            $this->defaultSenderEmail
        );
        $this->bus->dispatch($emailAsync);
    }
}

现在,当您调用 MailManagerAsync::sendAsyncMessage() 时,邮件将被封装成 EmailAsync 消息并发送到 Messenger 总线,然后由异步传输处理。

实现同步邮件发送

对于同步邮件发送,您可以继续使用 Symfony 提供的 MailerInterface 服务,直接调用其 send() 方法。由于我们没有将 Symfony\Component\Mailer\Messenger\SendEmailMessage 路由到异步传输,因此这些邮件将立即发送,不会进入消息队列。

// src/Service/MailManagerSync.php
namespace App\Service;

use Symfony\Component\Mime\Address;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;

class MailManagerSync
{
    protected MailerInterface $mailer;
    private string $defaultSenderEmail; // 可以通过构造函数注入或配置获取

    public function __construct(MailerInterface $mailer, string $defaultSenderEmail = 'noreply@example.com')
    {
        $this->mailer = $mailer;
        $this->defaultSenderEmail = $defaultSenderEmail;
    }

    public function sendSyncMessage(
        string $subject,
        string $htmlTemplate,
        ?string $textTemplate,
        string $to,
        array $context = []
    ): void {
        $email = (new TemplatedEmail())
            ->from(new Address($this->defaultSenderEmail))
            ->to(new Address($to))
            ->subject($subject)
            ->htmlTemplate($htmlTemplate)
            ->textTemplate($textTemplate)
            ->context($context);

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

当您调用 MailManagerSync::sendSyncMessage() 时,邮件将立即发送,而不会经过 Messenger 队列。

总结与注意事项

通过上述步骤,您已经在 Symfony 5 应用中成功实现了同步和异步邮件的并行发送:

  • 异步邮件: 通过自定义 EmailAsync 消息和 EmailAsyncHandler 处理程序,并将其路由到 Messenger 的异步传输。在服务中,您需要注入 MessageBusInterface 来调度这些消息。
  • 同步邮件: 直接使用 MailerInterface 服务发送 TemplatedEmail。由于 Symfony\Component\Mailer\Messenger\SendEmailMessage 没有被路由到异步传输,这些邮件将直接发送。

注意事项:

  1. Messenger 传输配置: 确保您的 async 传输已正确配置并能够正常工作(例如,RabbitMQ 服务器正在运行,或者 Doctrine 传输的数据库连接正常)。
  2. 错误处理: 对于异步邮件,处理程序中的错误不会立即反馈给用户。您需要为 Messenger 配置失败策略(如重试、死信队列)来处理邮件发送失败的情况。
  3. 发件人地址: 示例代码中发件人地址是硬编码的,实际应用中应通过配置文件或环境变量注入。
  4. 模板路径: htmlTemplate 和 textTemplate 应指向实际的 Twig 模板文件路径。
  5. 代码可维护性: 将同步和异步邮件发送逻辑封装在不同的服务中,有助于提高代码的可读性和可维护性。

遵循本教程的方法,您将能够更灵活地管理 Symfony 应用中的邮件发送流程,根据业务需求选择最合适的发送模式。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
PHP Symfony框架
PHP Symfony框架

本专题专注于PHP主流框架Symfony的学习与应用,系统讲解路由与控制器、依赖注入、ORM数据操作、模板引擎、表单与验证、安全认证及API开发等核心内容。通过企业管理系统、内容管理平台与电商后台等实战案例,帮助学员全面掌握Symfony在企业级应用开发中的实践技能。

78

2025.09.11

rabbitmq和kafka有什么区别
rabbitmq和kafka有什么区别

rabbitmq和kafka的区别:1、语言与平台;2、消息传递模型;3、可靠性;4、性能与吞吐量;5、集群与负载均衡;6、消费模型;7、用途与场景;8、社区与生态系统;9、监控与管理;10、其他特性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

202

2024.02.23

Java 消息队列与异步架构实战
Java 消息队列与异步架构实战

本专题系统讲解 Java 在消息队列与异步系统架构中的核心应用,涵盖消息队列基本原理、Kafka 与 RabbitMQ 的使用场景对比、生产者与消费者模型、消息可靠性与顺序性保障、重复消费与幂等处理,以及在高并发系统中的异步解耦设计。通过实战案例,帮助学习者掌握 使用 Java 构建高吞吐、高可靠异步消息系统的完整思路。

10

2026.01.28

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

358

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2082

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

349

2023.08.31

MySQL恢复数据库
MySQL恢复数据库

MySQL恢复数据库的方法有使用物理备份恢复、使用逻辑备份恢复、使用二进制日志恢复和使用数据库复制进行恢复等。本专题为大家提供MySQL数据库相关的文章、下载、课程内容,供大家免费下载体验。

256

2023.09.05

vb中怎么连接access数据库
vb中怎么连接access数据库

vb中连接access数据库的步骤包括引用必要的命名空间、创建连接字符串、创建连接对象、打开连接、执行SQL语句和关闭连接。本专题为大家提供连接access数据库相关的文章、下载、课程内容,供大家免费下载体验。

326

2023.10.09

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

2

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 10万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.2万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号