Skip to content
This repository was archived by the owner on Oct 15, 2025. It is now read-only.

Commit d3fdc56

Browse files
committed
feat(email): EmailCreatedSubscriber
1 parent b8765f5 commit d3fdc56

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

src/Entity/EmailKind.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace App\Entity;
66

7+
use Symfony\Component\Mime\Header\Headers;
78
use Symfony\Contracts\Translation\TranslatableInterface;
89
use Symfony\Contracts\Translation\TranslatorInterface;
910

@@ -21,4 +22,27 @@ public function trans(TranslatorInterface $translator, ?string $locale = null):
2122
self::Test => $translator->trans('email-kind.test', locale: $locale),
2223
};
2324
}
25+
26+
/**
27+
* @throws \InvalidArgumentException
28+
*/
29+
public static function fromEmailHeader(Headers $headers): self
30+
{
31+
$kind = $headers->getHeaderBody('X-Email-Kind');
32+
if (!\is_string($kind)) {
33+
throw new \InvalidArgumentException('The email kind header is missing or is invalid type.');
34+
}
35+
36+
return match ($kind) {
37+
'transactional' => self::Transactional,
38+
'marketing' => self::Marketing,
39+
'test' => self::Test,
40+
default => throw new \InvalidArgumentException("Invalid email kind: $kind"),
41+
};
42+
}
43+
44+
public function addToEmailHeader(Headers $headers): Headers
45+
{
46+
return $headers->addTextHeader('X-Email-Kind', $this->value);
47+
}
2448
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\EventSubscriber;
6+
7+
use App\Entity\Email as EmailEntity;
8+
use App\Entity\EmailDeliveryEvent;
9+
use App\Entity\EmailKind;
10+
use App\Repository\UserRepository;
11+
use Doctrine\ORM\EntityManagerInterface;
12+
use Psr\Log\LoggerInterface;
13+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
14+
use Symfony\Component\Mailer\Event\MessageEvent;
15+
use Symfony\Component\Mime\Address;
16+
use Symfony\Component\Mime\Email as EmailMessage;
17+
18+
final readonly class EmailCreatedSubscriber implements EventSubscriberInterface
19+
{
20+
public function __construct(
21+
private LoggerInterface $logger,
22+
private UserRepository $userRepository,
23+
private EntityManagerInterface $entityManager,
24+
) {
25+
}
26+
27+
public function onMessageEvent(MessageEvent $event): void
28+
{
29+
$message = $event->getMessage();
30+
if (!($message instanceof EmailMessage)) {
31+
$this->logger->warning('The message is not an instance of Email.', [
32+
'message' => $message,
33+
]);
34+
35+
return;
36+
}
37+
38+
$subject = $message->getSubject();
39+
if (!\is_string($subject)) {
40+
$this->logger->warning('The message does not have a valid subject.', [
41+
'message' => $message,
42+
'subject' => $subject,
43+
]);
44+
45+
return;
46+
}
47+
48+
$body = $message->getHtmlBody();
49+
if (!\is_string($body)) {
50+
$this->logger->warning('The message does not have an valid HTML body.', [
51+
'message' => $message,
52+
'body' => $body,
53+
]);
54+
55+
return;
56+
}
57+
58+
try {
59+
$kind = EmailKind::fromEmailHeader($message->getHeaders());
60+
} catch (\InvalidArgumentException $exception) {
61+
$this->logger->warning('The message does not have a valid email kind.', [
62+
'message' => $message,
63+
'exception' => $exception,
64+
]);
65+
66+
return;
67+
}
68+
69+
$email = (new EmailEntity())
70+
->setSubject($subject)
71+
->setContent($body)
72+
->setKind($kind);
73+
$this->entityManager->persist($email);
74+
75+
/**
76+
* @var list<Address> $recipients
77+
*/
78+
$recipients = [
79+
...$message->getTo(),
80+
...$message->getCc(),
81+
...$message->getBcc(),
82+
];
83+
84+
foreach ($recipients as $recipient) {
85+
$emailDeliveryEvent = (new EmailDeliveryEvent())
86+
->setToAddress($recipient->getAddress())
87+
->setEmail($email);
88+
89+
$user = $this->userRepository->findOneBy([
90+
'email' => $recipient->getAddress(),
91+
]);
92+
if (null !== $user) {
93+
$emailDeliveryEvent->setToUser($user);
94+
}
95+
96+
$this->entityManager->persist($emailDeliveryEvent);
97+
}
98+
99+
$this->entityManager->flush();
100+
}
101+
102+
public static function getSubscribedEvents(): array
103+
{
104+
return [
105+
MessageEvent::class => 'onMessageEvent',
106+
];
107+
}
108+
}

0 commit comments

Comments
 (0)