You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony Mailer循环发件时如何重置收件人及附件?

问题描述

在Symfony 6.x项目中,我需要通过命令批量发送邮件,因此编写了一个主命令循环调用发送邮件的子命令,但出现了邮件内容累积的问题。

主命令代码:

protected function execute(InputInterface $input, OutputInterface $output): int
{
    ...

    foreach($params as $param) {
        $cmdParams = ['command' => 'my:first:command', 'arg1' => $param['arg1'], 'arg2' => $param['arg2']];
        $cmdInput = new ArrayInput($cmdParams);
        $this->getApplication()->doRun($cmdInput, $output);
    }

    ...
}

发送邮件的子命令代码:

public function __construct(readonly MailerInterface $mailer)
{
    ...
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
    ...

    $email = (new Email())
    ->from(...)
    ->replyTo(...)
    ->addTo([...])
    ->addCc([...])
    ->addPart(...)
    ;

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

具体问题:每次循环发送的邮件会累积之前的收件人、抄送地址及附件:

  • 第一封邮件
    • to: to-1@domain.tld
    • cc: cc-1@domain.tld
    • attachment: file-1.ext
  • 第二封邮件
    • to: to-1@domain.tld, to-2@domain.tld
    • cc: cc-1@domain.tld, cc-2@domain.tld
    • attachment: file-1.ext, file-2.ext
  • 第n封邮件
    • to: to-1@domain.tld, to-2@domain.tld, ..., to-nth@domain.tld
    • cc: cc-1@domain.tld, cc-2@domain.tld, ..., cc-nth@domain.tld
    • attachment: file-1.ext, file-2.ext, ..., file-nth.ext

请问该如何重置收件人、抄送地址及附件?

解决方案

问题根源是Symfony命令循环调用时,服务容器会复用子命令实例,若Email对象或相关数据未重新生成,就会导致内容累积。以下是两种解决方法:

方法一:子命令内每次创建全新Email实例

确保子命令的execute方法中,每次执行都新建Email对象,所有收件人、抄送、附件都从当前参数获取,不复用任何类属性或外部缓存数据:

protected function execute(InputInterface $input, OutputInterface $output): int
{
    ...

    // 每次执行都创建全新的Email实例
    $email = (new Email())
        ->from('your-sender@domain.tld')
        ->replyTo('reply-to@domain.tld')
        ->addTo($input->getArgument('arg1')) // 从当前命令参数获取收件人
        ->addCc($input->getArgument('arg2')) // 从当前命令参数获取抄送地址
        ->addPart('邮件正文内容', 'text/plain')
        ->attachFromPath($this->getCurrentAttachmentPath($input)); // 动态获取当前邮件的附件路径
    
    $this->mailer->send($email);
    
    ...
}

方法二:主命令中使用CommandRunner确保子命令重新初始化

避免直接调用$this->getApplication()->doRun(),改用CommandRunner每次循环都重新加载子命令实例:

use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Runner\CommandRunner;

protected function execute(InputInterface $input, OutputInterface $output): int
{
    ...

    $commandLoader = $this->getContainer()->get(CommandLoaderInterface::class);
    
    foreach($params as $param) {
        $cmdParams = ['command' => 'my:first:command', 'arg1' => $param['arg1'], 'arg2' => $param['arg2']];
        $cmdInput = new ArrayInput($cmdParams);
        
        // 每次循环新建CommandRunner,保证子命令重新初始化
        $runner = new CommandRunner($commandLoader);
        $runner->run($cmdInput, $output);
    }

    ...
}

额外注意点

  • 不要在子命令的类属性中存储Email对象、收件人列表或附件路径,所有邮件相关数据都应在execute方法内动态生成。
  • 若子命令依赖其他服务(如模板引擎),需确保这些服务不会缓存之前的请求数据,必要时在execute方法末尾清理状态。

内容的提问来源于stack exchange,提问作者Nadim Bundhoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:44:54