/** * Email Adapter * * Implements EmailPort using nodemailer. Le contenu et la mise en page des * emails vivent dans `templates/` : l'adaptateur ne fait que les assembler * (destinataire, expediteur, sujet) et les envoyer. */ import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import * as nodemailer from 'nodemailer'; import * as https from 'https'; import { BankTransferToValidateEmail, ContactMessageEmail, EmailPort, EmailOptions, } from '@domain/ports/out/email.port'; import { EmailTemplates } from './templates/email-templates'; /** * Noms d'expéditeur affichés (un nom lisible est moins souvent classé en spam). * * L'ADRESSE, elle, est toujours SMTP_FROM. Chaque type d'email partait d'une * adresse codée en dur (team@, bookings@, security@, carriers@xpeditis.com) : * un relais SMTP comme Brevo refuse tout expéditeur non validé chez lui. Seuls * les emails envoyés depuis SMTP_FROM (test SMTP, alerte virement aux admins) * partaient donc — invitations et demandes aux transporteurs étaient rejetées. */ const SENDER_NAMES = { SECURITY: 'Xpeditis Sécurité', BOOKINGS: 'Xpeditis Bookings', TEAM: 'Équipe Xpeditis', CARRIERS: 'Xpeditis Transporteurs', NOREPLY: 'Xpeditis', } as const; type SenderKind = keyof typeof SENDER_NAMES; const DEFAULT_FROM_ADDRESS = 'noreply@xpeditis.com'; /** * Version texte générée à partir du HTML (les emails sans version texte sont * pénalisés par les filtres anti-spam, et elle sert aux clients texte). * * Le HTML compilé par MJML contient un
chargé de styles, des * commentaires conditionnels Outlook et un preheader masqué : ils sont retirés * avant d'extraire le texte, sinon la version texte commençait par du CSS. */ function htmlToPlainText(html: string): string { return html .replace(//gi, '') .replace(//g, '') .replace(/