import nodemailer from "nodemailer"; import type { ContactData } from "./validation"; import { getEnv } from "./env"; export interface Mailer { send(data: ContactData, meta: { ipHash: string }): Promise<{ delivered: boolean; id?: string }>; } function escapeHtml(s: string) { return s .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } export function renderContactEmail(data: ContactData) { const text = [ `Nouveau message depuis le site PHI Conseil`, ``, `Nom : ${data.name}`, `Courriel : ${data.email}`, `Organisation : ${data.organization || "—"}`, `Sujet : ${data.subject}`, ``, data.message, ].join("\n"); const html = `

Nouveau message depuis le site PHI Conseil

Nom${escapeHtml(data.name)}
Courriel${escapeHtml(data.email)}
Organisation${escapeHtml(data.organization || "—")}
Sujet${escapeHtml(data.subject)}

${escapeHtml(data.message)}

`; return { subject: `[Site PHI Conseil] ${data.subject}`, text, html }; } /** Transport « log » : n'envoie rien, journalise une empreinte. Jamais présenté comme une livraison. */ export const logMailer: Mailer = { async send(data, meta) { console.info( `[contact] CONTACT_TRANSPORT=log — courriel NON envoyé (sujet="${data.subject}", ip=${meta.ipHash})`, ); return { delivered: false }; }, }; export function createSmtpMailer(): Mailer { const env = getEnv(); const transporter = nodemailer.createTransport({ host: env.SMTP_HOST, port: env.SMTP_PORT, secure: env.SMTP_SECURE, auth: env.SMTP_USER ? { user: env.SMTP_USER, pass: env.SMTP_PASS } : undefined, }); return { async send(data) { const { subject, text, html } = renderContactEmail(data); const info = await transporter.sendMail({ from: env.CONTACT_FROM, to: env.CONTACT_TO, replyTo: data.email, subject, text, html, }); return { delivered: true, id: info.messageId }; }, }; } let instance: Mailer | null = null; export function getMailer(): Mailer { if (instance) return instance; instance = getEnv().CONTACT_TRANSPORT === "smtp" ? createSmtpMailer() : logMailer; return instance; } /** Pour les tests. */ export function setMailerForTests(m: Mailer | null) { instance = m; }