diff --git a/src/Symfony/Component/Mailer/CHANGELOG.md b/src/Symfony/Component/Mailer/CHANGELOG.md index 772f50717334f..877872ca8ed7e 100644 --- a/src/Symfony/Component/Mailer/CHANGELOG.md +++ b/src/Symfony/Component/Mailer/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.3 +--- + + * Add `MessageEvent::reject()` to allow rejecting an email before sending it + 6.2 --- diff --git a/src/Symfony/Component/Mailer/Event/MessageEvent.php b/src/Symfony/Component/Mailer/Event/MessageEvent.php index 083b8f8435b56..f00fdd52ca24c 100644 --- a/src/Symfony/Component/Mailer/Event/MessageEvent.php +++ b/src/Symfony/Component/Mailer/Event/MessageEvent.php @@ -28,6 +28,7 @@ final class MessageEvent extends Event private Envelope $envelope; private string $transport; private bool $queued; + private bool $rejected = false; /** @var StampInterface[] */ private array $stamps = []; @@ -70,10 +71,21 @@ public function isQueued(): bool return $this->queued; } + public function isRejected(): bool + { + return $this->rejected; + } + + public function reject(): void + { + $this->rejected = true; + $this->stopPropagation(); + } + public function addStamp(StampInterface $stamp): void { if (!$this->queued) { - throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued', __METHOD__)); + throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); } $this->stamps[] = $stamp; diff --git a/src/Symfony/Component/Mailer/Mailer.php b/src/Symfony/Component/Mailer/Mailer.php index c9f8b15aa85c1..cd305a65c4926 100644 --- a/src/Symfony/Component/Mailer/Mailer.php +++ b/src/Symfony/Component/Mailer/Mailer.php @@ -56,6 +56,10 @@ public function send(RawMessage $message, Envelope $envelope = null): void $event = new MessageEvent($clonedMessage, $clonedEnvelope, (string) $this->transport, true); $this->dispatcher->dispatch($event); $stamps = $event->getStamps(); + + if ($event->isRejected()) { + return; + } } try { diff --git a/src/Symfony/Component/Mailer/Tests/MailerTest.php b/src/Symfony/Component/Mailer/Tests/MailerTest.php index a369216e23cbc..95ab9d9391c7b 100644 --- a/src/Symfony/Component/Mailer/Tests/MailerTest.php +++ b/src/Symfony/Component/Mailer/Tests/MailerTest.php @@ -13,14 +13,19 @@ use PHPUnit\Framework\TestCase; use Psr\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\Mailer\Envelope as MailerEnvelope; use Symfony\Component\Mailer\Event\MessageEvent; use Symfony\Component\Mailer\Exception\LogicException; use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\AbstractTransport; use Symfony\Component\Mailer\Transport\NullTransport; use Symfony\Component\Mailer\Transport\TransportInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Stamp\StampInterface; +use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; use Symfony\Component\Mime\RawMessage; @@ -78,4 +83,34 @@ public function dispatch($message, array $stamps = []): Envelope self::assertCount(1, $bus->stamps); self::assertSame([$stamp], $bus->stamps); } + + public function testRejectMessage() + { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener(MessageEvent::class, fn (MessageEvent $event) => $event->reject(), 255); + $dispatcher->addListener(MessageEvent::class, fn () => throw new \RuntimeException('Should never be called.')); + + $transport = new class($dispatcher, $this) extends AbstractTransport { + public function __construct(EventDispatcherInterface $dispatcher, private TestCase $test) + { + parent::__construct($dispatcher); + } + + protected function doSend(SentMessage $message): void + { + $this->test->fail('This should never be called as message is rejected.'); + } + + public function __toString(): string + { + return 'fake://'; + } + }; + $mailer = new Mailer($transport); + + $message = new RawMessage(''); + $envelope = new MailerEnvelope(new Address('fabien@example.com'), [new Address('helene@example.com')]); + $mailer->send($message, $envelope); + $this->assertTrue(true); + } } diff --git a/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php index 42c23fcd735e2..19d574f736079 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php @@ -15,9 +15,13 @@ use Symfony\Bridge\Twig\Mime\BodyRenderer; use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Event\MessageEvent; use Symfony\Component\Mailer\EventListener\MessageListener; use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\AbstractTransport; use Symfony\Component\Mailer\Transport\NullTransport; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\RawMessage; @@ -78,4 +82,32 @@ public function testRenderedTemplatedEmail() $sentMessage = $transport->send((new TemplatedEmail())->to('me@example.com')->from('me@example.com')->htmlTemplate('tpl')); $this->assertMatchesRegularExpression('/Some message/', $sentMessage->getMessage()->toString()); } + + public function testRejectMessage() + { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener(MessageEvent::class, fn (MessageEvent $event) => $event->reject(), 255); + $dispatcher->addListener(MessageEvent::class, fn () => throw new \RuntimeException('Should never be called.')); + + $transport = new class($dispatcher, $this) extends AbstractTransport { + public function __construct(EventDispatcherInterface $dispatcher, private TestCase $test) + { + parent::__construct($dispatcher); + } + + protected function doSend(SentMessage $message): void + { + $this->test->fail('This should never be called as message is rejected.'); + } + + public function __toString(): string + { + return 'fake://'; + } + }; + + $message = new RawMessage(''); + $envelope = new Envelope(new Address('fabien@example.com'), [new Address('helene@example.com')]); + $this->assertNull($transport->send($message, $envelope)); + } } diff --git a/src/Symfony/Component/Mailer/Transport/AbstractTransport.php b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php index a6710d007da02..6598dccfcc09e 100644 --- a/src/Symfony/Component/Mailer/Transport/AbstractTransport.php +++ b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php @@ -73,6 +73,10 @@ public function send(RawMessage $message, Envelope $envelope = null): ?SentMessa $event = new MessageEvent($message, $envelope, (string) $this); $this->dispatcher->dispatch($event); + if ($event->isRejected()) { + return null; + } + $envelope = $event->getEnvelope(); $message = $event->getMessage();