Documentation

Système d'emails

Templates DB-driven, fallbacks, éditeur admin et liste exhaustive des templates.

Les emails sont DB-driven : un template par défaut est défini dans le code, mais l'admin peut l'override en base. Édition via une UI dédiée, sans redéploiement.

Architecture

lib/email-templates.ts     // DEFAULT_TEMPLATES (fallback hard-codé)
lib/email.ts               // sendTemplated() + senders publics
prisma/schema.prisma       // model EmailTemplate
app/api/admin/emails       // CRUD admin
app/[locale]/(dashboard)/emails/  // éditeur UI

sendTemplated(key, locale, vars, to) :

  1. Cherche dans EmailTemplate (key + locale) — utilise si trouvé
  2. Sinon fallback sur DEFAULT_TEMPLATES[key][locale]
  3. Interpole les variables ({name}, {code}, etc.)
  4. Envoie via Resend

Liste des templates

KeyVariables clésQuand
welcome{name}, {appUrl}Inscription confirmée
magic-link{url}Login par lien
password-reset{url}Demande de reset
email-verification{code}Verif email (code 6 chiffres)
two-factor-code{code}Login 2FA
login-alert{device}, {os}, {browser}, {location}, {ip}, {when}Nouveau device détecté
subscription-trial-ending{planName}, {when}3 jours avant fin de trial
subscription-renewing{planName}, {priceLabel}, {when}7 jours avant renouvellement
subscription-canceled{planName}, {when}Cancel at period end
subscription-ended{planName}Fin effective
subscription-coupon-ending{couponDescription}, {when}Coupon expire bientôt
payment-failed{planName}, {priceLabel}Échec de paiement
payment-succeeded{planName}, {priceLabel}Paiement OK

Variables globales toujours dispo : {appName}, {appUrl}, {name}.

Senders publics

Wrappers typés dans lib/email.ts :

sendWelcomeEmail(to, name, locale)
sendMagicLinkEmail(to, url, locale)
sendPasswordResetEmail(to, url, locale)
sendVerificationCodeEmail(to, code, locale)
sendTwoFactorCodeEmail(to, code, locale)
sendLoginAlertEmail({ to, userName, browser, os, device, ip, country, city, locale })
sendTrialEndingEmail(...)
sendRenewingEmail(...)
// etc.

Éditeur admin

Route : /admin/emails. Pour chaque template :

  • Édition FR + EN côte à côte
  • VAR_CHIPS : boutons qui insèrent {name}, {code}, etc. au curseur
  • Preview live avec valeurs d'exemple
  • Bouton Reset to default par template/langue (delete row DB → fallback)

API : GET /api/admin/emails, PATCH /api/admin/emails/[key].

Ajouter un nouveau template

  1. Ajoute la clé dans le type EmailTemplateKey (lib/email-templates.ts).
  2. Ajoute les entrées FR + EN dans DEFAULT_TEMPLATES.
  3. Crée un sender wrapper dans lib/email.ts :
    export async function sendMyNewEmail(to: string, vars: MyVars, locale: SupportedLocale) {
      return sendTemplated("my-new-key", locale, vars, to);
    }
  4. L'éditeur admin le détecte automatiquement (il itère sur les clés).

EMAIL_FROM

EMAIL_FROM=noreply@toi.com

Doit être un domaine vérifié dans ton compte Resend. En dev, onboarding@resend.dev fonctionne mais n'envoie qu'à ton email de compte Resend.

Allez plus loin

On this page