From db3c1e8ddd0325d9cc692362dd5c2692b8eca321 Mon Sep 17 00:00:00 2001 From: Thomas Hanke Date: Wed, 30 Nov 2022 16:47:42 +0100 Subject: [PATCH 1/3] add reject to MessageEvent to stop sending mail --- src/Symfony/Component/Mailer/CHANGELOG.md | 5 +++++ src/Symfony/Component/Mailer/Event/MessageEvent.php | 13 ++++++++++++- .../Mailer/Transport/AbstractTransport.php | 4 ++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mailer/CHANGELOG.md b/src/Symfony/Component/Mailer/CHANGELOG.md index 772f50717334..90fdf5d47811 100644 --- a/src/Symfony/Component/Mailer/CHANGELOG.md +++ b/src/Symfony/Component/Mailer/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.3 +--- + + * Add `reject()` in `MessageEvent` to reject sending mail + 6.2 --- diff --git a/src/Symfony/Component/Mailer/Event/MessageEvent.php b/src/Symfony/Component/Mailer/Event/MessageEvent.php index 083b8f8435b5..906d4459fabd 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,20 @@ public function isQueued(): bool return $this->queued; } + public function isRejected(): bool + { + return $this->rejected; + } + + public function reject(): void + { + $this->rejected = true; + } + 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/Transport/AbstractTransport.php b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php index a6710d007da0..f3ee80f890c8 100644 --- a/src/Symfony/Component/Mailer/Transport/AbstractTransport.php +++ b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php @@ -82,6 +82,10 @@ public function send(RawMessage $message, Envelope $envelope = null): ?SentMessa $sentMessage = new SentMessage($message, $envelope); + if ($event->isRejected()) { + return $sentMessage; + } + try { $this->doSend($sentMessage); } catch (\Throwable $error) { From ee020be06bd5c0c0aca60ff873c316d68f5109f8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 31 Dec 2022 11:24:53 +0100 Subject: [PATCH 2/3] [Mailer] Add the possibility to reject a message --- src/Symfony/Component/Mailer/CHANGELOG.md | 2 +- src/Symfony/Component/Mailer/Mailer.php | 4 +++ .../Component/Mailer/Tests/MailerTest.php | 34 +++++++++++++++++++ .../Tests/Transport/AbstractTransportTest.php | 31 +++++++++++++++++ .../Mailer/Transport/AbstractTransport.php | 8 ++--- 5 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Mailer/CHANGELOG.md b/src/Symfony/Component/Mailer/CHANGELOG.md index 90fdf5d47811..877872ca8ed7 100644 --- a/src/Symfony/Component/Mailer/CHANGELOG.md +++ b/src/Symfony/Component/Mailer/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 6.3 --- - * Add `reject()` in `MessageEvent` to reject sending mail + * Add `MessageEvent::reject()` to allow rejecting an email before sending it 6.2 --- diff --git a/src/Symfony/Component/Mailer/Mailer.php b/src/Symfony/Component/Mailer/Mailer.php index c9f8b15aa85c..cd305a65c492 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 a369216e23cb..3167a8270ea0 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,33 @@ 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()); + + $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 42c23fcd735e..7f64429002c2 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,31 @@ 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()); + + $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 f3ee80f890c8..6598dccfcc09 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(); @@ -82,10 +86,6 @@ public function send(RawMessage $message, Envelope $envelope = null): ?SentMessa $sentMessage = new SentMessage($message, $envelope); - if ($event->isRejected()) { - return $sentMessage; - } - try { $this->doSend($sentMessage); } catch (\Throwable $error) { From 5733cf767760999139dcf82a70e316a5f31687c1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 31 Dec 2022 12:54:12 +0100 Subject: [PATCH 3/3] [Mailer] Stop propagation when an email is rejected --- src/Symfony/Component/Mailer/Event/MessageEvent.php | 1 + src/Symfony/Component/Mailer/Tests/MailerTest.php | 3 ++- .../Component/Mailer/Tests/Transport/AbstractTransportTest.php | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mailer/Event/MessageEvent.php b/src/Symfony/Component/Mailer/Event/MessageEvent.php index 906d4459fabd..f00fdd52ca24 100644 --- a/src/Symfony/Component/Mailer/Event/MessageEvent.php +++ b/src/Symfony/Component/Mailer/Event/MessageEvent.php @@ -79,6 +79,7 @@ public function isRejected(): bool public function reject(): void { $this->rejected = true; + $this->stopPropagation(); } public function addStamp(StampInterface $stamp): void diff --git a/src/Symfony/Component/Mailer/Tests/MailerTest.php b/src/Symfony/Component/Mailer/Tests/MailerTest.php index 3167a8270ea0..95ab9d9391c7 100644 --- a/src/Symfony/Component/Mailer/Tests/MailerTest.php +++ b/src/Symfony/Component/Mailer/Tests/MailerTest.php @@ -87,7 +87,8 @@ public function dispatch($message, array $stamps = []): Envelope public function testRejectMessage() { $dispatcher = new EventDispatcher(); - $dispatcher->addListener(MessageEvent::class, fn (MessageEvent $event) => $event->reject()); + $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) diff --git a/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php index 7f64429002c2..19d574f73607 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php @@ -86,7 +86,8 @@ public function testRenderedTemplatedEmail() public function testRejectMessage() { $dispatcher = new EventDispatcher(); - $dispatcher->addListener(MessageEvent::class, fn (MessageEvent $event) => $event->reject()); + $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)