| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <?php
- declare(strict_types=1);
- namespace App\Service\Mailer;
- use App\Entity\Message\ReportEmail;
- use App\Enum\Core\EmailSendingTypeEnum;
- use App\Enum\Message\MessageStatusEnum;
- use App\Enum\Utils\EnvironnementVarEnum;
- use App\Service\Mailer\Model\MailerModelInterface;
- use App\Service\ServiceIterator\Mailer\BuilderIterator;
- use App\Service\Utils\Environnement;
- use App\Service\Utils\StringsUtils;
- use App\Enum\Message\ReportMessageStatusEnum;
- use App\Tests\Service\Mailer\MailerTest;
- use Doctrine\Common\Collections\ArrayCollection;
- use Doctrine\ORM\EntityManagerInterface;
- use Psr\Log\LoggerInterface;
- use Symfony\Bridge\Twig\Mime\TemplatedEmail;
- use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
- use Symfony\Component\Mailer\MailerInterface;
- use Symfony\Component\Mime\Address;
- use Symfony\Component\Mime\Email as SymfonyEmail;
- /**
- * Classe Mailer : Service assurant l'envoi d'un mail à un destinataire
- */
- class Mailer
- {
- public function __construct(
- private MailerInterface $symfonyMailer,
- private string $opentalentNoReplyEmailAddress,
- private BuilderIterator $builderIterator,
- private StringsUtils $stringsUtils,
- private EntityManagerInterface $entityManager,
- private Environnement $environnement,
- private LoggerInterface $logger
- )
- {}
- /**
- * Main fonction qui itère les différentes étapes nécessaires à l'envoi d'un email
- * - Le Build
- * - Le Send
- * - Le Reporting
- *
- * @param MailerModelInterface $mailerModel
- * @return ArrayCollection
- * @throws TransportExceptionInterface
- * @see MailerTest::testMain()
- */
- public function main(MailerModelInterface $mailerModel): ArrayCollection {
- // TODO: est-ce qu'on l'appellerait pas plutôt 'send' celle-ci? et est-ce qu'on ne passerait pas les autres en
- // private? j'ai peur qu'on se trompe parfois entre l'une et l'autre
- $builderService = $this->builderIterator->getBuilderFor($mailerModel);
- $emailsCollection = $builderService->build($mailerModel);
- $emailsCollection = $this->reduceEmailsCollectionInPreproduction($emailsCollection);
- /** @var Email $email */
- foreach ($emailsCollection as $email){
- //si l'email n'a pas de destinataire, on ne l'envoi pas...
- if($email->getEmailRecipients()->isEmpty()){
- $email->getEmailEntity()->setStatus(MessageStatusEnum::NO_RECIPIENT()->getValue());
- continue;
- }
- //Envoi du mail
- $this->send($email);
- //Persistance de l'entité Email
- $this->persistEmailEntity($email);
- }
- //Envoi du rapport
- $this->sendReport($emailsCollection);
- $this->entityManager->flush();
- return $emailsCollection;
- }
- /**
- * Fonction d'envoi
- *
- * @param EmailInterface $email
- *
- * @throws TransportExceptionInterface
- * @see MailerTest::testSend()
- */
- public function send(EmailInterface $email): void{
- //On créé le mail
- $symfonyMail = $this->createSymfonyEmail($email);
- $this->addRecipients($symfonyMail, $email);
- $this->setAntiSpam($email, $symfonyMail->getTo());
- $this->setSymfonyEmailContent($symfonyMail, $email);
- $this->addHeaders($symfonyMail, $email);
- // @todo
- //$this->addAttachments();
- //On tente d'envoyer
- try {
- $this->symfonyMailer->send($symfonyMail);
- $email->getEmailEntity()->setStatus(MessageStatusEnum::SEND()->getValue());
- $email->getEmailEntity()->setDateSent(new \DateTime('now'));
- } catch (\Exception $e) {
- $this->logger->error('Error while sending email');
- $this->logger->error($e);
- $email->getEmailEntity()->setStatus(MessageStatusEnum::FAILED()->getValue());
- }
- }
- /**
- * Envoi le rapport d'envoi
- * @param ArrayCollection $emails
- *
- * @see MailerTest::testSendReport()
- */
- public function sendReport(ArrayCollection $emails): void{
- $reportEmail = $this->createReportEmail($emails);
- try {
- $this->symfonyMailer->send($reportEmail);
- } catch (TransportExceptionInterface $e) {
- $this->logger->error('Error while sending report');
- $this->logger->error($e);
- }
- }
- /**
- * Création du Mail qui sera envoyé via le Mailer de Symfony
- * @param Email $email
- * @return SymfonyEmail
- *
- * @see MailerTest::testCreateSymfonyEmail()
- */
- public function createSymfonyEmail(Email $email): SymfonyEmail{
- $addressMailFrom = new Address($email->getFrom(), $email->geFromName());
- return (new SymfonyEmail())
- ->from($addressMailFrom)
- ->replyTo($addressMailFrom)
- ->returnPath(Address::create("mail.report@opentalent.fr"))
- ->subject($email->getEmailEntity()->getAbout())
- ;
- }
- /**
- * @param SymfonyEmail $symfonyEmail
- * @param Email $email
- *
- * @see MailerTest::testSetSymfonyEmailContent()
- */
- public function setSymfonyEmailContent(SymfonyEmail $symfonyEmail, Email $email): void
- {
- $symfonyEmail
- ->html($email->getContent())
- ->text($this->stringsUtils->convertHtmlToText($email->getContent()));
- }
- /**
- * Créé le Templated Email contenant le rapport d'envoi
- * @param ArrayCollection $emails
- * @return TemplatedEmail
- *
- * @see MailerTest::testCreateReportEmail()
- */
- public function createReportEmail(ArrayCollection $emails): TemplatedEmail
- {
- [$delivered, $unDelivered] = $this->getDeliveredAndUndelivered($emails);
- /** @var Email $email */
- $email = $emails->first();
- return (new TemplatedEmail())
- ->from($this->opentalentNoReplyEmailAddress)
- ->subject(sprintf('Rapport d\'envoi du message : %s', $email->getEmailEntity()->getAbout()))
- ->htmlTemplate('@templates/emails/report.html.twig')
- ->context(
- [
- 'email_example' => $email->getEmailEntity(),
- 'delivered' => $delivered,
- 'unDelivered' => $unDelivered
- ]
- )
- ->addTo(new Address($email->getFrom(), $email->geFromName()))
- ;
- }
- /**
- * Récupère les recipient delivered & undelivered de l'ensemble des emails
- * @param ArrayCollection $emails
- * @return array[]
- *
- * @see MailerTest::testGetDeliveredAndUndelivered()
- */
- function getDeliveredAndUndelivered(ArrayCollection $emails): array {
- $delivered = [];
- $unDelivered = [];
- foreach ($emails as $email){
- $emailRecipients = $email->getEmailRecipients();
- /** @var EmailRecipient $emailRecipient */
- foreach ($emailRecipients as $emailRecipient){
- if($emailRecipient->getSendStatus() === ReportMessageStatusEnum::MISSING()->getValue()){
- $unDelivered[] = $emailRecipient;
- }else if($emailRecipient->getSendStatus() === ReportMessageStatusEnum::DELIVERED()->getValue()){
- $delivered[] = $emailRecipient;
- }
- }
- }
- return [$delivered, $unDelivered];
- }
- /**
- * Persist l'Email
- * @param Email $email
- *
- * @see MailerTest::testPersistEmailEntity()
- */
- public function persistEmailEntity(Email $email): void
- {
- $emailEntity = $email->getEmailEntity();
- /** @var EmailRecipient $emailRecipient */
- foreach ($email->getEmailRecipients() as $emailRecipient){
- $emailEntity->addReport($this->createReport($emailRecipient));
- }
- $this->entityManager->persist($emailEntity);
- }
- /**
- * Création du rapport
- * @param EmailRecipient $emailRecipient
- *
- * @return ReportEmail
- * @see MailerTest::testCreateReport()
- */
- public function createReport(EmailRecipient $emailRecipient): ReportEmail{
- return (new ReportEmail())
- ->setAddressEmail($emailRecipient->getEmailAddress())
- ->setAccess($emailRecipient->getAccess())
- ->setOrganization($emailRecipient->getOrganization())
- ->setDateSend(new \DateTime('now'))
- ->setStatus($emailRecipient->getSendStatus())
- ;
- }
- /**
- * Reduit le nombre d'emails a envoyer si on ne se trouve pas en prod
- * @param ArrayCollection $emailsCollection
- *
- * @return ArrayCollection
- * @see MailerTest::testReduceEmailsCollectionInPreproduction()
- */
- public function reduceEmailsCollectionInPreproduction(ArrayCollection $emailsCollection): ArrayCollection {
- if($this->environnement->get(EnvironnementVarEnum::APP_ENV()->getValue()) !== 'prod' && $emailsCollection->count() > 20) {
- $startEmails = $emailsCollection->slice(0, 10);
- $endEmails = $emailsCollection->slice($emailsCollection->count() - 11, 10);
- return new ArrayCollection([...$startEmails, ...$endEmails]);
- }
- return $emailsCollection;
- }
- /**
- * @param SymfonyEmail $symfonyMail
- * @param Email $email
- *
- * @see MailerTest::testAddHeaders()
- */
- public function addHeaders(SymfonyEmail $symfonyMail, Email $email): void
- {
- $symfonyMail->getHeaders()->addTextHeader('List-Unsubscribe','mailto:'.$email->getFrom().'?subject=désabonnement');
- $symfonyMail->getHeaders()->addTextHeader('X-ID-OT', $email->getEmailEntity()->getUuid()->toString());
- }
- /**
- * On change le #__#ANTISPAM_PERSON_EMAIL#__# par la liste des emails afin d'éviter le spamming sur l'envoi en masse
- * @param Email $email
- * @param array $addresses
- * @see MailerTest::testSetAntiSpam()
- */
- public function setAntiSpam(Email $email, array $addresses): void
- {
- // map des Address pour ne conserver qu'un tableau d'email
- $to = array_map(function(Address $address){
- return $address->getAddress();
- }, $addresses);
- $email->setContent(str_replace('#__#ANTISPAM_PERSON_EMAIL#__#', implode(',', $to), $email->getContent()));
- }
- /**
- * On ajoute les destinataires suivant le type d'envoi souhaité
- *
- * @param SymfonyEmail $symfonyMail
- * @param Email $email
- * @see MailerTest::testAddRecipients()
- */
- public function addRecipients(SymfonyEmail $symfonyMail, Email $email): void{
- $allReadySend = [];
- foreach ($email->getEmailRecipients() as $emailRecipient){
- $addressMail = new Address($emailRecipient->getEmailAddress(), $emailRecipient->getName());
- //On envoi pas en double
- if(!in_array($addressMail, $allReadySend)){
- $allReadySend[] = $addressMail;
- switch($emailRecipient->getSendType()){
- case EmailSendingTypeEnum::TO()->getValue():
- $symfonyMail->addTo($addressMail);
- break;
- case EmailSendingTypeEnum::BBC()->getValue():
- $symfonyMail->addBcc($addressMail);
- break;
- case EmailSendingTypeEnum::CC()->getValue():
- $symfonyMail->addCc($addressMail);
- break;
- }
- }
- }
- }
- }
|