Vincent GUFFON vor 3 Jahren
Ursprung
Commit
a9f6cb060a

+ 1 - 0
composer.json

@@ -53,6 +53,7 @@
         "symfony/serializer": "5.4.*",
         "symfony/translation": "5.4.*",
         "symfony/twig-bundle": "^5.4",
+        "symfony/uid": "5.4.*",
         "symfony/validator": "5.4.*",
         "symfony/yaml": "5.4.*",
         "twig/cssinliner-extra": "^3.4",

+ 157 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "e403ff9a6e83cf9bb6571a11e3837da7",
+    "content-hash": "3fa7de50c31eceda9118ecc6a3101b7d",
     "packages": [
         {
             "name": "api-platform/core",
@@ -7408,6 +7408,88 @@
             ],
             "time": "2022-05-24T11:49:31+00:00"
         },
+        {
+            "name": "symfony/polyfill-uuid",
+            "version": "v1.26.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-uuid.git",
+                "reference": "a41886c1c81dc075a09c71fe6db5b9d68c79de23"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/a41886c1c81dc075a09c71fe6db5b9d68c79de23",
+                "reference": "a41886c1c81dc075a09c71fe6db5b9d68c79de23",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "provide": {
+                "ext-uuid": "*"
+            },
+            "suggest": {
+                "ext-uuid": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Uuid\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Grégoire Pineau",
+                    "email": "lyrixx@lyrixx.info"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for uuid functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "uuid"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-uuid/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-24T11:49:31+00:00"
+        },
         {
             "name": "symfony/process",
             "version": "v5.4.8",
@@ -8937,6 +9019,80 @@
             ],
             "time": "2022-04-03T13:03:10+00:00"
         },
+        {
+            "name": "symfony/uid",
+            "version": "v5.4.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/uid.git",
+                "reference": "2b52d90f0a913a1f770e0b09be3e9baf298b4872"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/uid/zipball/2b52d90f0a913a1f770e0b09be3e9baf298b4872",
+                "reference": "2b52d90f0a913a1f770e0b09be3e9baf298b4872",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-uuid": "^1.15"
+            },
+            "require-dev": {
+                "symfony/console": "^4.4|^5.0|^6.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Uid\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Grégoire Pineau",
+                    "email": "lyrixx@lyrixx.info"
+                },
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides an object-oriented API to generate and represent UIDs",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "UID",
+                "ulid",
+                "uuid"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/uid/tree/v5.4.3"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T09:53:40+00:00"
+        },
         {
             "name": "symfony/validator",
             "version": "v5.4.10",

+ 2 - 2
config/packages/twig.yaml

@@ -1,5 +1,5 @@
 twig:
     paths:
         '%kernel.project_dir%/templates': templates
-        '%kernel.project_dir%/assets/images': images
-        '%kernel.project_dir%/assets/styles': styles
+        '%kernel.project_dir%/templates/assets/images': images
+        '%kernel.project_dir%/templates/assets/styles': styles

+ 8 - 2
src/Controller/MailerController.php

@@ -32,8 +32,14 @@ class MailerController extends AbstractController
 //
 //
 //
-        $mailerModel = new TestModel(15, 498);
-        $mailerModel->setSenderId(15);
+
+
+
+
+        $mailerModel = (new TestModel())
+            ->setAccessId(15)
+            ->setOrganizationId(498)
+            ->setSenderId(15);
 
         $messageBus->dispatch(
             new MailerCommand($mailerModel)

+ 6 - 10
src/Entity/Message/AbstractMessage.php

@@ -7,6 +7,7 @@ use App\Annotation\OrganizationDefaultValue;
 use App\Entity\Organization\Organization;
 use App\Enum\Message\MessageStatusEnum;
 use Doctrine\ORM\Mapping as ORM;
+use Ramsey\Uuid\UuidInterface;
 use Symfony\Component\Validator\Constraints as Assert;
 
 /**
@@ -21,8 +22,8 @@ abstract class AbstractMessage
     #[ORM\GeneratedValue]
     protected ?int $id = null;
 
-    #[ORM\Column]
-    protected ?string $uniqueSendId = null;
+    #[ORM\Column(type: 'string', unique: true)]
+    protected $uuid = null;
 
     #[ORM\ManyToOne]
     #[ORM\JoinColumn(nullable: true)]
@@ -32,6 +33,7 @@ abstract class AbstractMessage
     #[Assert\Choice(callback: [MessageStatusEnum::class, 'toArray'], message: 'invalid-departure-cause')]
     protected string $status;
 
+    // @todo remplacer par le nom sendingDate
     #[ORM\Column(type: 'datetime', nullable: true)]
     protected ?\DateTimeInterface $dateSent = null;
 
@@ -46,15 +48,9 @@ abstract class AbstractMessage
         return $this->id;
     }
 
-    public function setUniqueSendId(string $uniqueSendId): self
-    {
-        $this->uniqueSendId = $uniqueSendId;
-        return $this;
-    }
-
-    public function getUniqueSendId(): string
+    public function getUuid(): ?UuidInterface
     {
-        return $this->uniqueSendId;
+        return $this->uuid;
     }
 
     public function setOrganization(Organization $organization): self

+ 2 - 2
src/Entity/Message/AbstractReport.php

@@ -5,7 +5,7 @@ namespace App\Entity\Message;
 
 use App\Entity\Access\Access;
 use App\Entity\Organization\Organization;
-use App\Enum\Message\ReportMessageSatusEnum;
+use App\Enum\Message\ReportMessageStatusEnum;
 use Symfony\Component\Validator\Constraints as Assert;
 use Doctrine\ORM\Mapping as ORM;
 
@@ -19,7 +19,7 @@ class AbstractReport
     protected ?\DatetimeInterface $dateSend;
 
     #[ORM\Column(length: 255)]
-    #[Assert\Choice(callback: [ReportMessageSatusEnum::class, 'toArray'], message: 'invalid-report-type')]
+    #[Assert\Choice(callback: [ReportMessageStatusEnum::class, 'toArray'], message: 'invalid-report-type')]
     protected string $status;
 
     #[ORM\ManyToOne(inversedBy: 'report')]

+ 2 - 0
src/Entity/Message/Email.php

@@ -10,6 +10,7 @@ use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
+use Ramsey\Uuid\Uuid;
 
 /**
  * @todo : A la suite de la migration, il faut supprimer le nom de la table pour avoir une table Email, et supprimer l'attribut discr.
@@ -53,6 +54,7 @@ class Email extends AbstractMessage
 
     public function __construct()
     {
+        $this->uuid = Uuid::uuid4();
         $this->report = new ArrayCollection();
         $this->files = new ArrayCollection();
         $this->tags = new ArrayCollection();

+ 2 - 0
src/Entity/Message/Mail.php

@@ -10,6 +10,7 @@ use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
+use Ramsey\Uuid\Uuid;
 
 /**
  * @todo : A la suite de la migration, il faut supprimer le nom de la table pour avoir une table Mail, et supprimer l'attribut discr.
@@ -43,6 +44,7 @@ class Mail extends AbstractMessage
 
     public function __construct()
     {
+        $this->uuid = Uuid::uuid4();
         $this->files = new ArrayCollection();
         $this->tags = new ArrayCollection();
     }

+ 0 - 12
src/Entity/Message/ReportEmail.php

@@ -26,18 +26,6 @@ class ReportEmail extends AbstractReport
     #[ORM\Column(length: 255)]
     private string $addressEmail;
 
-    public function getDiscr(): ?string
-    {
-        return $this->discr;
-    }
-
-    public function setDiscr(string $discr): self
-    {
-        $this->discr = $discr;
-
-        return $this;
-    }
-
     public function getId(): ?int
     {
         return $this->id;

+ 1 - 16
src/Entity/Message/ReportSms.php

@@ -5,7 +5,6 @@ namespace App\Entity\Message;
 
 use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
 use Doctrine\ORM\Mapping as ORM;
-use Symfony\Component\Serializer\Annotation\Groups;
 
 /**
  * Classe ... qui ...
@@ -27,23 +26,9 @@ class ReportSms extends AbstractReport
     #[ORM\Column(length: 255)]
     private string $mobile;
 
-    #[ORM\Column(type: 'string', nullable: true)]
-    #[Assert\Type(type: 'string')]
-    #[Groups(['reportmessage', 'report'])]
+    #[ORM\Column(nullable: true)]
     private $smsId;
 
-    public function getDiscr(): ?string
-    {
-        return $this->discr;
-    }
-
-    public function setDiscr(string $discr): self
-    {
-        $this->discr = $discr;
-
-        return $this;
-    }
-
     public function getId(): ?int
     {
         return $this->id;

+ 2 - 0
src/Entity/Message/Sms.php

@@ -9,6 +9,7 @@ use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
+use Ramsey\Uuid\Uuid;
 
 /**
  * @todo : A la suite de la migration, il faut supprimer le nom de la table pour avoir une table Sms, et supprimer l'attribut discr.
@@ -39,6 +40,7 @@ class Sms extends AbstractMessage
 
     public function __construct()
     {
+        $this->uuid = Uuid::uuid4();
         $this->report = new ArrayCollection();
         $this->tags = new ArrayCollection();
     }

+ 1 - 0
src/Enum/Message/MessageStatusEnum.php

@@ -17,4 +17,5 @@ class MessageStatusEnum extends Enum
     private const PRINTED = 'PRINTED';
     private const SENDING_IN_PROGRESS = 'SENDING_IN_PROGRESS';
     private const FAILED = 'FAILED';
+    private const NO_RECIPIENT = 'NO_RECIPIENT';
 }

+ 1 - 1
src/Enum/Message/ReportMessageSatusEnum.php → src/Enum/Message/ReportMessageStatusEnum.php

@@ -9,7 +9,7 @@ use MyCLabs\Enum\Enum;
  * Report Mail status.
  *
  */
-class ReportMessageSatusEnum extends Enum
+class ReportMessageStatusEnum extends Enum
 {
   private const DELIVERED = 'DELIVERED';
   private const PRINTED = 'PRINTED';

+ 1 - 1
src/Message/Command/MailerCommand.php

@@ -21,7 +21,7 @@ class MailerCommand
         return $this->model;
     }
 
-    public function setEmails(MailerModelInterface $model): void
+    public function setMailerModel(MailerModelInterface $model): void
     {
         $this->model = $model;
     }

+ 4 - 4
src/Message/Handler/MailerHandler.php

@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace App\Message\Handler;
 
+use App\Entity\Message\Email;
 use App\Message\Command\MailerCommand;
 use App\Repository\Access\AccessRepository;
-use App\Service\Mailer\Email;
 use App\Service\Mailer\Mailer;
 use App\Service\Notifier;
 use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
@@ -27,12 +27,12 @@ class MailerHandler implements MessageHandlerInterface
         $emails = $this->mailer->main($mailerModel);
 
         if ($mailerModel->getNotify()) {
-            /** @var Email $email */
-            $email = $emails->first();
+            /** @var Email */
+            $email = $emails->first()->getEmailEntity();
 
             $this->notifier->notifyMessage(
                 $this->accessRepository->find($mailerCommand->getMailerModel()->getSenderId()),
-                ['about' => $email->getEmailEntity()->getAbout()]
+                ['about' => $email->getAbout()]
             );
         }
     }

+ 5 - 6
src/Service/Mailer/Builder/AbstractBuilder.php

@@ -6,7 +6,7 @@ namespace App\Service\Mailer\Builder;
 use App\Entity\Access\Access;
 use App\Entity\Core\ContactPoint;
 use App\Entity\Organization\Organization;
-use App\Enum\Message\ReportMessageSatusEnum;
+use App\Enum\Message\ReportMessageStatusEnum;
 use App\Repository\Core\ContactPointRepository;
 use App\Service\Mailer\Email;
 use App\Entity\Message\Email as EmailEntity;
@@ -39,7 +39,6 @@ class AbstractBuilder implements AbstractBuilderInterface
      */
     public function buildEmailEntity(string $subject, Access $author, string $content): EmailEntity{
         return (new EmailEntity())
-            ->setUniqueSendId(uniqid())
             ->setAuthor($author)
             ->setAbout($subject)
             ->setIsSystem(true)
@@ -59,7 +58,7 @@ class AbstractBuilder implements AbstractBuilderInterface
      * @throws \Twig_Error_Runtime
      * @throws \Twig_Error_Syntax
      */
-    public function renderer(string $template, array $context)
+    public function render(string $template, array $context)
     {
         return $this->twig->render(sprintf('@templates/emails/%s.html.twig', $template), $context);
     }
@@ -83,7 +82,7 @@ class AbstractBuilder implements AbstractBuilderInterface
             $emailRecipient->setName($target->getName());
             $this->setMailToRecipient($this->contactPointRepository->getByTypeAndOrganization($contactPointType, $target), $emailRecipient);
         }else{
-            $emailRecipient->setSendStatus(ReportMessageSatusEnum::DELIVERED()->getValue());
+            $emailRecipient->setSendStatus(ReportMessageStatusEnum::DELIVERED()->getValue());
             $emailRecipient->setEmailAddress($target);
         }
 
@@ -96,10 +95,10 @@ class AbstractBuilder implements AbstractBuilderInterface
      */
     public function setMailToRecipient(array $contactPoints, EmailRecipient $recipient): void {
         if($contactPoint = $this->getFirstContactPointWithEmail($contactPoints)){
-            $recipient->setSendStatus(ReportMessageSatusEnum::DELIVERED()->getValue());
+            $recipient->setSendStatus(ReportMessageStatusEnum::DELIVERED()->getValue());
             $recipient->setEmailAddress($contactPoint->getEmail());
         }else{
-            $recipient->setSendStatus(ReportMessageSatusEnum::MISSING()->getValue());
+            $recipient->setSendStatus(ReportMessageStatusEnum::MISSING()->getValue());
         }
     }
 

+ 1 - 1
src/Service/Mailer/Builder/AbstractBuilderInterface.php

@@ -9,7 +9,7 @@ use App\Service\Mailer\Email;
 
 interface AbstractBuilderInterface {
 
-    public function renderer(string $template, array $context);
+    public function render(string $template, array $context);
 
     public function buildEmailEntity(string $subject, Access $author, string $content);
 

+ 1 - 1
src/Service/Mailer/Builder/TestBuilder.php

@@ -42,7 +42,7 @@ class TestBuilder extends AbstractBuilder implements BuilderInterface
         $emails = new ArrayCollection();
 
         $context = ['organization' => $organization];
-        $content = $this->renderer('test', $context);
+        $content = $this->render('test', $context);
 
         $email= (new Email())
             ->setEmailEntity($this->buildEmailEntity('Mon sujet', $access, $content))

+ 21 - 14
src/Service/Mailer/Mailer.php

@@ -11,9 +11,10 @@ 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\ReportMessageSatusEnum;
+use App\Enum\Message\ReportMessageStatusEnum;
 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;
@@ -31,7 +32,8 @@ class Mailer
         private BuilderIterator $builderIterator,
         private StringsUtils $stringsUtils,
         private EntityManagerInterface $entityManager,
-        private Environnement $environnement
+        private Environnement $environnement,
+        private LoggerInterface $logger
     )
     {
     }
@@ -55,7 +57,7 @@ class Mailer
         foreach ($emailsCollection as $email){
             //si l'email n'a pas de destinataire, on ne l'envoi pas...
             if(empty($email->getEmailRecipients())){
-                $email->getEmailEntity()->setStatus(MessageStatusEnum::FAILED()->getValue());
+                $email->getEmailEntity()->setStatus(MessageStatusEnum::NO_RECIPIENT()->getValue());
                 continue;
             }
 
@@ -64,6 +66,7 @@ class Mailer
 
             //Persistance de l'entité Email
             $this->persistEmailEntity($email);
+
         }
 
         //Envoi du rapport
@@ -98,6 +101,9 @@ class Mailer
             $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());
         }
     }
@@ -114,9 +120,9 @@ class Mailer
             $emailRecipients = $email->getEmailRecipients();
             /** @var EmailRecipient $emailRecipient */
             foreach ($emailRecipients as $emailRecipient){
-                if($emailRecipient->getSendStatus() === ReportMessageSatusEnum::MISSING()->getValue()){
+                if($emailRecipient->getSendStatus() === ReportMessageStatusEnum::MISSING()->getValue()){
                     $unDelivered[] = $emailRecipient;
-                }else if($emailRecipient->getSendStatus() === ReportMessageSatusEnum::DELIVERED()->getValue()){
+                }else if($emailRecipient->getSendStatus() === ReportMessageStatusEnum::DELIVERED()->getValue()){
                     $delivered[] = $emailRecipient;
                 }
             }
@@ -124,7 +130,7 @@ class Mailer
 
         $templatedMail = (new TemplatedEmail())
             ->from($this->opentalentNoReplyEmailAddress)
-            ->subject(sprintf('Rapport d\'envoie du message : %s', $emails->first()->getEmailEntity()->getAbout()))
+            ->subject(sprintf('Rapport d\'envoi du message : %s', $emails->first()->getEmailEntity()->getAbout()))
             ->htmlTemplate('@templates/emails/report.html.twig')
             ->context(
                 [
@@ -139,7 +145,8 @@ class Mailer
         try {
             $this->symfonyMailer->send($templatedMail);
         } catch (TransportExceptionInterface $e) {
-
+            $this->logger->error('Error while sending report');
+            $this->logger->error($e);
         }
     }
 
@@ -169,12 +176,12 @@ class Mailer
      * @param ArrayCollection $emailsCollection
      */
     public function reduceEmailsCollectionInPreproduction(ArrayCollection $emailsCollection): ArrayCollection {
-        if($this->environnement->get(EnvironnementVarEnum::APP_ENV()->getValue()) === 'prod') return $emailsCollection;
-
-        $startEmails = $emailsCollection->slice(0, 10);
-        $endEmails = $emailsCollection->slice($emailsCollection->count() - 11, 10);
-
-        return new ArrayCollection([...$startEmails, ...$endEmails]);
+        if($this->environnement->get(EnvironnementVarEnum::APP_ENV()->getValue()) !== 'prod') {
+            $startEmails = $emailsCollection->slice(0, 10);
+            $endEmails = $emailsCollection->slice($emailsCollection->count() - 11, 10);
+            return new ArrayCollection([...$startEmails, ...$endEmails]);
+        }
+        return $emailsCollection;
     }
 
     /**
@@ -183,7 +190,7 @@ class Mailer
      */
     public function addHeaders(SymfonyEmail $symfonyMail, Email $email){
         $symfonyMail->getHeaders()->addTextHeader('List-Unsubscribe','mailto:'.$email->getFrom().'?subject=désabonnement');
-        $symfonyMail->getHeaders()->addTextHeader('X-ID-OT', $email->getEmailEntity()->getUniqueSendId());
+        $symfonyMail->getHeaders()->addTextHeader('X-ID-OT', $email->getEmailEntity()->getUuid()->toString());
     }
 
     /**

+ 4 - 4
src/Service/Mailer/Model/TestModel.php

@@ -8,10 +8,10 @@ namespace App\Service\Mailer\Model;
  */
 class TestModel extends AbstractMailerModel implements MailerModelInterface
 {
-    public function __construct(
-        private int $accessId,
-        private int $organizationId
-    )
+    private int $accessId;
+    private int $organizationId;
+
+    public function __construct()
     {}
 
     public function setAccessId(int $accessId) : self{

+ 1 - 1
src/Service/Utils/Environnement.php

@@ -14,6 +14,6 @@ class Environnement
         if(in_array($name, EnvironnementVarEnum::toArray(), true)){
             return $_ENV[$name];
         }
-        throw new \RuntimeException('not supported', 500);
+        throw new \RuntimeException(sprintf('Undefined environment variable : %s', $name), 500);
     }
 }

+ 0 - 0
assets/styles/foundation-emails.css → templates/assets/styles/foundation-emails.css