简体   繁体   English

Symfony 5.3:立即发送异步电子邮件

[英]Symfony 5.3: Async emails sent immediately

Edit: This question arose in the attempt to have both synchronous and synchronous emails in the same application.编辑:这个问题出现在试图在同一个应用程序中同时拥有同步和同步电子邮件的过程中。 That was not made clear.没有说清楚。 As of this writing it is not possible, at least not as simply as tried here.在撰写本文时,这是不可能的,至少不像这里尝试的那样简单。 See comments by @msg below.请参阅下面@msg 的评论。

An email service configured to send email asynchronously instead sends emails immediately.配置为异步发送 email 的 email 服务改为立即发送电子邮件。 This happens with either doctrine or amqp selected as MESSENGER_TRANSPORT_DSN .这发生在doctrineamqp选择为MESSENGER_TRANSPORT_DSN时。 doctrine transport successfully creates messenger_messages table, but with no contents. doctrine传输成功创建messenger_messages表,但没有内容。 This tells me the MESSENGER_TRANSPORT_DSN is observed.这告诉我观察到了MESSENGER_TRANSPORT_DSN Simple test of amqp using RabbitMQ 'Hello World' tutorial shows it is properly configured.使用 RabbitMQ 'Hello World' 教程对amqp的简单测试表明它已正确配置。

What have I missed in the code below?我在下面的代码中遗漏了什么?

Summary of sequence shown below: Opportunity added -> OppEmailService creates email contents -> gets TemplatedEmail() object from EmailerService (not shown) -> submits TemplatedEmail() object to LaterEmailService , which is configured to be async. Summary of sequence shown below: Opportunity added -> OppEmailService creates email contents -> gets TemplatedEmail() object from EmailerService (not shown) -> submits TemplatedEmail() object to LaterEmailService , which is configured to be async.

messenger.yaml:信使.yaml:

framework:
    messenger:
        transports:
            async: '%env(MESSENGER_TRANSPORT_DSN)%'
            sync: 'sync://'

        routing:
            'App\Services\NowEmailService': sync
            'App\Services\LaterEmailService': async

OpportunityController : OpportunityController

class OpportunityController extends AbstractController
{

    private $newOpp;
    private $templateSvc;

    public function __construct(OppEmailService $newOpp, TemplateService $templateSvc)
    {
        $this->newOpp = $newOpp;
        $this->templateSvc = $templateSvc;
    }
...
    public function addOpp(Request $request): Response
    {
...
        if ($form->isSubmitted() && $form->isValid()) {
...
            $volunteers = $em->getRepository(Person::class)->opportunityEmails($opportunity);
            $this->newOpp->oppEmail($volunteers, $opportunity);
...
    }

OppEmailService : OppEmailService

class OppEmailService
{

    private $em;
    private $makeMail;
    private $laterMail;

    public function __construct(
            EmailerService $makeMail,
            EntityManagerInterface $em,
            LaterEmailService $laterMail
    )
    {
        $this->makeMail = $makeMail;
        $this->em = $em;
        $this->laterMail = $laterMail;
    }
...
    public function oppEmail($volunteers, $opp): array
    {
...
            $mailParams = [
                'template' => 'Email/volunteer_opportunities.html.twig',
                'context' => ['fname' => $person->getFname(), 'opportunity' => $opp,],
                'recipient' => $person->getEmail(),
                'subject' => 'New volunteer opportunity',
            ];
            $toBeSent = $this->makeMail->assembleEmail($mailParams);
            $this->laterMail->send($toBeSent);
...
    }

}

LaterEmailService : LaterEmailService

namespace App\Services;

use Symfony\Component\Mailer\MailerInterface;

class LaterEmailService
{

    private $mailer;

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

    public function send($email)
    {
        $this->mailer->send($email);
    }

}

I ended up creating console commands to be run as daily cron jobs.我最终创建了作为日常cron作业运行的控制台命令。 Each command calls a services that create and send emails.每个命令都会调用一个创建和发送电子邮件的服务。 The use case is a low volume daily email to registered users informing them of actions that affect them.用例是每天向注册用户发送少量 email,通知他们影响他们的操作。 An example follows:一个例子如下:

Console command:控制台命令:

class NewOppsEmailCommand extends Command
{

    private $mailer;
    private $oppEmail;
    private $twig;

    public function __construct(OppEmailService $oppEmail, EmailerService $mailer, Environment $twig)
    {
        $this->mailer = $mailer;
        $this->oppEmail = $oppEmail;
        $this->twig = $twig;

        parent::__construct();
    }

    protected static $defaultName = 'app:send:newoppsemaiils';

    protected function configure()
    {
        $this->setDescription('Sends email re: new opps to registered');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $emails = $this->oppEmail->oppEmail();

        $output->writeln($emails . ' email(s) were sent');

        return COMMAND::SUCCESS;
    }

}

OppEmailService:欧普电子邮件服务:

class OppEmailService
{

    private $em;
    private $mailer;

    public function __construct(EmailerService $mailer, EntityManagerInterface $em)
    {
        $this->mailer = $mailer;
        $this->em = $em;
    }

    /**
     * Send new opportunity email to registered volunteers
     */
    public function oppEmail()
    {
        $unsentEmail = $this->em->getRepository(OppEmail::class)->findAll(['sent' => false], ['volunteer' => 'ASC']);
        if (empty($unsentEmail)) {
            return 0;
        }

        $email = 0;
        foreach ($unsentEmail as $recipient) {
            $mailParams = [
                'template' => 'Email/volunteer_opportunities.html.twig',
                'context' => [
                    'fname' => $recipient->getVolunteer()->getFname(),
                    'opps' => $recipient->getOpportunities(),
                ],
                'recipient' => $recipient->getVolunteer()->getEmail(),
                'subject' => 'New opportunities',
            ];
            $this->mailer->assembleEmail($mailParams);
            $recipient->setSent(true);
            $this->em->persist($recipient);
            $email++;
        }
        $this->em->flush();

        return $email;
    }

}

EmailerService:电子邮件服务:

class EmailerService
{

    private $em;
    private $mailer;

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

    public function assembleEmail($mailParams)
    {
        $sender = $this->em->getRepository(Person::class)->findOneBy(['mailer' => true]);
        $email = (new TemplatedEmail())
                ->to($mailParams['recipient'])
                ->from($sender->getEmail())
                ->subject($mailParams['subject'])
                ->htmlTemplate($mailParams['template'])
                ->context($mailParams['context'])
        ;

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

        return $email;
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM