feat: send mailings over MailJet smtp in dedicated worker process
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Service\Teamer;
|
||||
|
||||
use App\Email\Mailer;
|
||||
use App\Entity\User;
|
||||
use App\Message\SendTeamerMailing;
|
||||
use App\Model\TeamerFilterDto;
|
||||
use App\Model\TeamerMailingDto;
|
||||
use App\Model\TeamerMailingRecipient;
|
||||
@@ -26,10 +27,20 @@ class TeamerMailingService
|
||||
private const TEMPLATE = 'email/teamer_mailing.html.twig';
|
||||
private const PREVIEW_SUBJECT_PREFIX = '[Vorschau] ';
|
||||
|
||||
/**
|
||||
* The mailer transport a mailing goes out over: Mailjet, rather than the webhoster's
|
||||
* relay that carries every other mail, which would risk the hosting account over a few
|
||||
* hundred recipients. Configured in mailer.yaml.
|
||||
*/
|
||||
private const TRANSPORT = 'mailing';
|
||||
|
||||
public function __construct(
|
||||
private readonly TeamerRepository $teamerRepository,
|
||||
private readonly Mailer $mailer,
|
||||
private readonly LoggerInterface $logger,
|
||||
// messenger transport, "mailing" in production and "sync" in dev and test,
|
||||
// see the parameter of the same name in services.yaml
|
||||
private readonly string $mailingBusTransport,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -68,32 +79,35 @@ class TeamerMailingService
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the mailing to everyone eligible and return how many mails went out.
|
||||
* Hand every recipient of a confirmed mailing to the mailer.
|
||||
*
|
||||
* This runs in the worker, not in the request that confirmed the mailing, so it
|
||||
* reports nothing back: each mail becomes a queued message of its own and whether it
|
||||
* reaches anyone is decided long after this method returns. A caller that wants to
|
||||
* know how many mails were actually delivered has to ask the mail provider.
|
||||
*/
|
||||
public function send(TeamerMailingDto $mailingDto, TeamerMailingRecipientsDto $recipients): int
|
||||
public function sendMailing(SendTeamerMailing $mailing): void
|
||||
{
|
||||
foreach ($recipients->getEligible() as $recipient) {
|
||||
// resolveRecipients() already guaranteed the address, this only narrows the type
|
||||
if (null === $email = $recipient->getEmail()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$values = $this->placeholderValuesFor($recipient);
|
||||
foreach ($mailing->getRecipients() as $recipient) {
|
||||
$values = $this->buildValues(
|
||||
$recipient['firstName'],
|
||||
$recipient['lastName'],
|
||||
$recipient['fullName']
|
||||
);
|
||||
|
||||
$this->sendTo(
|
||||
$email,
|
||||
$this->render($mailingDto->getSubject(), $values),
|
||||
$this->render($mailingDto->getMessage(), $values)
|
||||
$recipient['email'],
|
||||
$this->render($mailing->getSubject(), $values),
|
||||
$this->render($mailing->getMessage(), $values),
|
||||
self::TRANSPORT,
|
||||
$this->mailingBusTransport
|
||||
);
|
||||
}
|
||||
|
||||
$this->logger->info('Send teamer mailing', [
|
||||
'subject' => $mailingDto->getSubject(),
|
||||
'recipients' => $recipients->getEligibleCount(),
|
||||
'skipped' => $recipients->getSkippedCount(),
|
||||
'subject' => $mailing->getSubject(),
|
||||
'recipients' => $mailing->getRecipientCount(),
|
||||
]);
|
||||
|
||||
return $recipients->getEligibleCount();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,14 +187,26 @@ class TeamerMailingService
|
||||
];
|
||||
}
|
||||
|
||||
private function sendTo(string $email, string $subject, string $message): void
|
||||
{
|
||||
/**
|
||||
* The preview leaves the transports unset on purpose: it goes out over the same relay
|
||||
* and the same queue as the rest of the application, so it arrives while the admin is
|
||||
* still looking at the compose page.
|
||||
*/
|
||||
private function sendTo(
|
||||
string $email,
|
||||
string $subject,
|
||||
string $message,
|
||||
?string $transport = null,
|
||||
?string $busTransport = null,
|
||||
): void {
|
||||
$this->mailer->createAndSendEmail([
|
||||
'message' => $message,
|
||||
], [
|
||||
'to' => $email,
|
||||
'subject' => $subject,
|
||||
'template' => self::TEMPLATE,
|
||||
'transport' => $transport,
|
||||
'bus_transport' => $busTransport,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user