Retour aux projetsProjet personnel

EmailGen - Générateur de templates email IA

Un éditeur de templates email assisté par Claude. Décrivez votre email en langage naturel, affinez les textes depuis le panneau latéral ou via le chat, et obtenez un composant React Email compilé en temps réel. Sous le capot : un agent IA opérant sur un système de fichiers virtuel, un pipeline esbuild-wasm exécuté entièrement dans le navigateur, et une extraction automatique des champs éditables depuis le JSX généré.

Back-end

Next.js 16TypeScript strictVercel AI SDK v6Anthropic ClaudeMongoDBMongoose 9better-auth v1.6ResendAES-256-GCMZod

Front-end

React 19CSS Modulesesbuild-wasm@react-email/components@react-email/renderreact-hook-formGoogle Fonts API

Un agent IA qui opère sur du vrai code - pas sur du texte

Claude ne génère pas du code dans une zone de texte. Il utilise des outils structurés pour modifier précisément les fichiers d'un système de fichiers virtuel, comme un développeur qui appliquerait des diffs.

Le contexte

Créer un template email implique deux contraintes techniques fortes : les clients mail n'acceptent que du HTML inline, et la moindre modification de texte ou de couleur nécessite de retoucher du code. L'objectif était de rendre ce processus conversationnel, tout en garantissant un aperçu fidèle au rendu réel - pas une approximation.

L'approche

Le template vit dans un Virtual File System (VFS) en mémoire - une map de chemins vers du contenu, jamais écrite sur disque. Email.tsx est compilé à la demande par esbuild-wasm directement dans le navigateur, puis rendu en HTML par @react-email/render et injecté dans un iframe. Aucun code utilisateur n'est jamais exécuté côté serveur - l'aperçu est un vrai rendu React Email, pas une approximation, et le pipeline reste isolé dans l'onglet de l'utilisateur.

Côté IA, Claude dispose de quatre outils structurés : str_replace pour modifier précisément une portion de code (ciblage old → new, pas de réécriture complète), file_manager pour créer ou supprimer des fichiers dans le VFS, extract_fields pour scanner le JSX compilé à la recherche des attributs data-field-id et synchroniser le panneau d'édition, et set_template_name appelé une seule fois à la génération initiale.

Les champs éditables - extraction automatique depuis le code

Chaque zone de texte dans le template porte un attribut data-field-id kebab-case (ex. data-field-id="hero-title"). Après chaque génération ou modification, Claude appelle extract_fields, qui compile le VFS, parse le HTML résultant et construit dynamiquement la liste des champs dans le panneau latéral. Les champs ne sont jamais hardcodés : ils émergent du code généré lui-même.

Précision

str_replace cible une portion exacte du fichier. Une modification d'une couleur ne retouche pas le reste du template - le diff est chirurgical.

Rendu fidèle

L'aperçu passe par le même pipeline @react-email/render qu'un envoi réel. Ce que vous voyez est exactement ce que recevra le destinataire.

Champs dynamiques

Les data-field-id sont extraits du JSX généré à chaque tour. Ajouter un champ dans le code le fait apparaître automatiquement dans l'UI.

État persistant

VFS, historique de chat et valeurs des champs sont sauvegardés en MongoDB après chaque échange. Reprendre un template là où on l'a laissé est natif.

Architecture

Pipeline de compilation

Tout se passe côté client : VirtualFileSystem (in-memory) → esbuild-wasm (bundle en mémoire dans le navigateur, résolution des imports @react-email/components) → @react-email/render → HTML injecté dans un iframe. Aucune écriture disque, aucun appel serveur pour l'aperçu, latence minimale.

TemplateContext

Un contexte React unique partage le VFS, les messages du chat, les champs et leurs valeurs entre ChatPanel, Workspace et FieldEditorSidebar. Les mutations passent toutes par ce contexte, qui déclenche la recompilation à la demande.

Model router

Un routeur inspecte chaque message avant de l'envoyer à Claude et sélectionne automatiquement le modèle adapté à la complexité de la demande - génération initiale, édition ciblée, ou simple réponse textuelle.

Streaming AI

Les réponses de Claude sont streamées via createUIMessageStream (Vercel AI SDK v6). Les appels d'outils (tool-invocation) apparaissent en temps réel dans le chat sous forme de badges, dédupliqués par nom d'outil.

Sécurité et gestion des clés

Pas d'exécution de code utilisateur côté serveur. La compilation esbuild et le rendu React Email se font exclusivement dans le navigateur de l'utilisateur via esbuild-wasm et un iframe - éliminant par construction toute possibilité d'exécution de code arbitraire (RCE) dans le processus Node. L'endpoint d'envoi de test ne reçoit que du HTML déjà rendu, validé via Zod et plafonné à 500 KB, et le destinataire est forcé à l'adresse de l'utilisateur authentifié - pas de relais ouvert possible. Un rate-limit quotidien par utilisateur empêche tout abus de la clé Resend.

Les utilisateurs peuvent brancher leur propre clé Anthropic pour un usage illimité. La clé est chiffrée en AES-256-GCM avant stockage MongoDB avec le champ marqué select: false - elle n'est jamais retournée dans les requêtes, jamais loggée, et déchiffrée uniquement dans le scope de la requête de génération. Sans clé personnelle, un quota de 5 requêtes gratuites sur la clé serveur est appliqué via un compteur $inc atomique avant chaque stream (429 si dépassé). Les sessions sont gérées par better-auth avec cookie HttpOnly.

Évolutions envisagées

Export multi-format

Exporter le template compilé en HTML standalone ou en MJML pour l'intégrer directement dans un ESP (Mailchimp, Brevo, Sendgrid) sans passer par Resend.

Envoi de campagne

Brancher Resend Broadcasts pour envoyer le template à une liste d'abonnés depuis l'éditeur, avec personnalisation des champs par destinataire.