```
✨ feat(ansible/caddy): Ajoute le domaine signature.ludikevent.fr à la configuration Caddy. ✨ feat(src/Service/Mailer): Améliore l'envoi d'emails avec désinscription et Message-ID. ✨ feat(templates/mails): Met à jour le logo de l'email pour LudikEvent. ```
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
intranet.ludikevent.fr {
|
||||
intranet.ludikevent.fr, signature.ludikevent.fr {
|
||||
tls {
|
||||
dns cloudflare KL6pZ-Z_12_zbnM2TtFDIsKM8A-HLPhU5GJJbKTW
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Service\Mailer;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -7,10 +8,8 @@ use Exception;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||
use Symfony\Component\Mailer\MailerInterface;
|
||||
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
|
||||
use Symfony\Component\Mime\Address;
|
||||
use Symfony\Component\Mime\Email;
|
||||
use Symfony\Component\Mime\Header\IdentificationHeader;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
@@ -21,15 +20,19 @@ class Mailer
|
||||
private readonly MailerInterface $mailer;
|
||||
|
||||
public function __construct(
|
||||
MailerInterface $mailer,
|
||||
MailerInterface $mailer,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly UrlGeneratorInterface $urlGenerator,
|
||||
private readonly ?Profiler $profiler,
|
||||
private readonly Environment $environment,
|
||||
) {
|
||||
private readonly UrlGeneratorInterface $urlGenerator,
|
||||
private readonly ?Profiler $profiler,
|
||||
private readonly Environment $environment,
|
||||
)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit le contenu MJML en HTML via le binaire MJML installé sur le serveur.
|
||||
*/
|
||||
private function convertMjmlToHtml(string $mjmlContent): string
|
||||
{
|
||||
$process = new Process(['mjml', '--stdin']);
|
||||
@@ -44,57 +47,98 @@ class Mailer
|
||||
|
||||
return $process->getOutput();
|
||||
} catch (ProcessFailedException|Exception) {
|
||||
return ''; // Retourne vide en cas d'échec
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $address
|
||||
* @param string $addressName
|
||||
* @param string $subject
|
||||
* @param string $template
|
||||
* @param array<string, mixed> $data
|
||||
* @param array<\Symfony\Component\Mime\Part\DataPart> $files
|
||||
* Envoie un email avec headers de désinscription et Message-ID personnalisé.
|
||||
* * @param string $address Email du destinataire
|
||||
* @param string $addressName Nom du destinataire
|
||||
* @param string $subject Sujet de l'email
|
||||
* @param string $template Chemin du template Twig/MJML
|
||||
* @param array<string, mixed> $data Données à passer au template
|
||||
* @param array<\Symfony\Component\Mime\Part\DataPart> $files Pièces jointes
|
||||
*/
|
||||
public function send(
|
||||
string $address,
|
||||
string $addressName,
|
||||
string $subject,
|
||||
string $template,
|
||||
array $data,
|
||||
array $files = []
|
||||
): void {
|
||||
array $data,
|
||||
array $files = []
|
||||
): void
|
||||
{
|
||||
$domain = "ludikevent.fr";
|
||||
$dest = new Address($address, $addressName);
|
||||
$src = new Address("contact@e-page.fr", "E-PAGE");
|
||||
$src = new Address("contact@" . $domain, "Ludikevent");
|
||||
|
||||
// 1. Génération du Message-ID unique
|
||||
$messageId = sprintf('<%s.%s@%s>',
|
||||
bin2hex(random_bytes(12)),
|
||||
time(),
|
||||
$domain
|
||||
);
|
||||
|
||||
// 2. Préparation de l'URL de désinscription
|
||||
$unsubscribeUrl = "https://intranet.ludikevent.fr/unscribe/" . urlencode($address);
|
||||
|
||||
$mail = (new Email())
|
||||
->subject($subject)
|
||||
->to($dest)
|
||||
->from($src);
|
||||
|
||||
// 3. Configuration des Headers techniques
|
||||
$headers = $mail->getHeaders();
|
||||
|
||||
// Identification unique
|
||||
$headers->addIdHeader('Message-ID', $messageId);
|
||||
|
||||
// RFC 2369 & 8058 (Bouton désinscription dans le client mail)
|
||||
$headers->addTextHeader('List-Unsubscribe', sprintf('<mailto:unscribe@%s>, <%s>', $domain, $unsubscribeUrl));
|
||||
$headers->addTextHeader('List-Unsubscribe-Post', 'List-Unsubscribe=One-Click');
|
||||
|
||||
// 4. Génération du contenu via Twig et MJML
|
||||
$mjmlGenerator = $this->environment->render($template, [
|
||||
'system' => [
|
||||
'subject' => $subject,
|
||||
'path' => $_ENV['PATH_URL'],
|
||||
'path' => $_ENV['PATH_URL'] ?? 'https://intranet.ludikevent.fr',
|
||||
'unsubscribe_url' => $unsubscribeUrl,
|
||||
'message_id' => $messageId
|
||||
],
|
||||
'datas' => $data,
|
||||
]);
|
||||
|
||||
$htmlContent = $this->convertMjmlToHtml($mjmlGenerator);
|
||||
$txtContent = $this->environment->render('txt-'.$template,[
|
||||
'system' => [
|
||||
'subject' => $subject,
|
||||
'path' => $_ENV['PATH_URL'],
|
||||
],
|
||||
'datas' => $data,
|
||||
]);
|
||||
|
||||
// 5. Version Texte Brut (Fallback)
|
||||
try {
|
||||
$txtContent = $this->environment->render('txt-' . $template, [
|
||||
'system' => [
|
||||
'subject' => $subject,
|
||||
'path' => $_ENV['PATH_URL'] ?? 'https://ludikevent.fr',
|
||||
'unsubscribe_url' => $unsubscribeUrl
|
||||
],
|
||||
'datas' => $data,
|
||||
]);
|
||||
$mail->text($txtContent);
|
||||
} catch (Exception) {
|
||||
// Si le template TXT n'existe pas, on laisse le mailer gérer le fallback ou on ignore
|
||||
}
|
||||
|
||||
// 6. Ajout des pièces jointes
|
||||
foreach ($files as $file) {
|
||||
$mail->addPart($file);
|
||||
}
|
||||
$mail->html($htmlContent);
|
||||
$mail->text($txtContent);
|
||||
$this->mailer->send($mail);
|
||||
}
|
||||
|
||||
$mail->html($htmlContent);
|
||||
|
||||
// 7. Envoi final
|
||||
try {
|
||||
$this->mailer->send($mail);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
// Optionnel : Logger l'erreur ici
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
{# Section d'en-tête #}
|
||||
<mj-section background-color="#ffffff" padding-bottom="0px">
|
||||
<mj-column>
|
||||
{# Logo mis à jour pour SARL SITECONSEIL #}
|
||||
<mj-image src="{{ system.path }}{{ asset('assets/images/logo.png') }}" alt="Logo LudikEvent" align="center" width="150px" padding-bottom="20px"></mj-image>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
|
||||
Reference in New Issue
Block a user