Éditeur visuel d'e-mails
Compose un e-mail sans écrire de HTML : tu glisses des blocs (titre, texte, image, bouton, colonnes, séparateur, réseaux sociaux), tu les règles, tu vois le rendu — et Trackily en tire un HTML compatible avec les messageries (mise en page en tableaux, styles intégrés aux balises). Partout où tu écris un corps d'e-mail : les envois ponctuels (variante A et variantes B/C d'un test A/B) et les étapes de séquence.
Concept
L'éditeur, c'est GrapesJS — le même que pour les landings — avec son préréglage newsletter. Il ne se charge que quand tu l'ouvres.
Deux choses sont gardées sur chaque e-mail conçu dans l'éditeur :
| Champ | Ce que c'est | Qui s'en sert |
|---|---|---|
body_html |
le HTML exporté par l'éditeur, styles intégrés | le moteur d'envoi : c'est ce qui part, comme avant |
body_design |
le projet de l'éditeur (un objet JSON) | l'éditeur, pour rouvrir l'e-mail et le modifier |
Le moteur d'envoi ne change pas : il envoie body_html, ajoute le pied de désinscription et le suivi comme pour n'importe quel e-mail. Le serveur ne fait rien du projet à part le ranger : il ne l'interprète jamais, il ne l'exécute jamais.
Les règles qui te protègent
- Le HTML envoyé reste la vérité. Ce que tu vois dans l'aperçu (une
iframeisolée, sans script) est ce qui part. - Le projet et le HTML ne divergent jamais en silence. Si tu modifies le HTML à la main après coup (dans la zone HTML, ou par un agent MCP qui écrit
body_htmlsansbody_design), le projet est détaché : l'écran te prévient (« ça détache l'éditeur visuel »), puisbody_designest effacé. Rouvrir l'éditeur repartirait sinon de l'ancien projet et écraserait ta correction. - Les variables restent intactes.
{{first_name}},{{custom.X}},{{unsubscribe_url}}… s'insèrent depuis le menu « Insérer une variable » et ressortent telles quelles dans le HTML. Le pied de désinscription reste ajouté par le moteur : inutile de le mettre dans l'e-mail. - Des bornes. Le projet pèse 2 Mo au plus (sinon
413 projet_trop_gros) ; le HTML exporté qui l'accompagne, 1 Mo au plus (sinon413 corps_trop_gros). Rien n'est écrit quand c'est refusé. Pour rester dessous : héberge les images (l'outil d'images, ou une URL) au lieu de les intégrer. - Un projet ne peut rien exécuter. Un projet qui contient un attribut d'événement (
onerror,onclick…), une adressejavascript:,vbscript:oudata:(sauf les imagesdata:image/png,jpeg,gif,webp), une balise ou un composantscript,iframe,object,embed,base,meta,link, une propriétéscript, ousrcdocest refusé (400 projet_dangereux, qui nomme l'endroit fautif). L'écran passe le même filtre avant d'ouvrir un projet : l'éditeur tourne dans l'admin, avec ta session. - Le projet voyage avec son HTML. Un
body_designenvoyé sansbody_htmlnon vide dans la même écriture est refusé (400 projet_sans_html). - Les verrous ne changent pas. Un envoi ponctuel lancé ne se modifie plus (
409 envoi_verrouille), projet compris : duplique-le — la copie garde son projet et celui de ses variantes, et se rouvre dans l'éditeur.
Composer un e-mail
- Dans l'éditeur d'un envoi ponctuel (onglet A, B ou C) ou d'une étape de séquence, clique « Éditeur visuel », à côté de la zone HTML.
- L'e-mail est vide ? « Choisir un modèle » : pars d'un modèle de départ (ci-dessous) ou d'une page blanche.
- Glisse des blocs depuis la barre, règle-les dans le panneau de réglages ; bascule ordinateur / mobile pour vérifier les deux rendus.
- « Enregistrer » : le HTML exporté remplit la zone HTML, le projet est gardé, l'aperçu se met à jour. « Annuler » ferme sans rien changer.
Une ligne qui a un projet affiche « Conçu dans l'éditeur visuel ».
Le chargement de l'éditeur est impossible (pas de réseau vers le CDN) ? Un message le dit, et la zone HTML reste utilisable comme avant.
Les modèles de départ
Cinq modèles, sobres, en français, sans aucune image (rien d'obligatoire à héberger), en tableaux de 600 px avec les styles intégrés :
| Modèle | Pour quoi |
|---|---|
| Annonce simple | une nouvelle, un rendez-vous, un changement : un titre, deux paragraphes, un bouton |
| Promotion avec bouton | une remise mise en avant, un code promo encadré, un bouton d'achat |
| Lettre d'information deux colonnes | la lettre du mois : une introduction, deux sujets côte à côte, un conseil |
| Relance de panier | un panier laissé : le récapitulatif des produits, « Finaliser ma commande », les garanties |
| Bienvenue | le premier e-mail d'une séquence d'accueil : remercier, dire à quoi s'attendre, trois premiers pas |
Chacun porte {{first_name}} et un bouton. Le texte vouvoie le destinataire (c'est la voix de ta marque) : change-le si ta marque tutoie. Les liens pointent vers https://exemple.com : remplace-les avant d'envoyer, et remplace « Votre marque » par la tienne.
Via MCP
| Outil | Tier | Rôle |
|---|---|---|
list_email_visual_templates |
lecture | les modèles de départ : id, nom, description, apercu_html (le HTML exporté), design (le projet) ; { id } pour un seul |
create_email_broadcast, update_email_broadcast |
T1 | acceptent body_design (et ab.variantes[].body_design) |
add_email_sequence_step, update_email_sequence_step |
T1 | acceptent body_design |
get_email_broadcast |
lecture | rend body_design et a_un_design, sur A et sur chaque variante |
list_email_broadcasts, get_email_sequence_detail |
lecture | rendent a_un_design seulement — le projet ne voyage que dans le détail |
Un agent qui écrit du HTML directement (body_html sans body_design) détache le projet, comme l'écran. Un projet envoyé par un agent passe le même filtre (projet_dangereux, projet_sans_html). Pour partir d'un modèle, un agent adapte apercu_html et l'écrit en body_html seul ; il ne redonne design en body_design que s'il n'a pas touché au HTML (sinon le projet ne correspondrait plus à ce qui part).
// L'agent écrit un corps à la main : le projet est détaché.
{ "name": "update_email_broadcast", "arguments": { "id": 12, "body_html": "<p>Bonjour {{first_name}}, …</p>" } }
// → { "ok": true, "broadcast": { …, "body_design": null, "a_un_design": false } }
API (admin)
Toutes sous /admin/api, lecture landings:read, écriture landings:write :
GET /email/modeles-visuels→[{ id, nom, description, apercu_html, design }].POST /email/broadcasts,PUT /email/broadcasts/:id:body_design(objet, ounullpour détacher) à côté debody_html; dansab.variantes[], chaque variante porte le sien. Une variante est réécrite en entier à chaque écriture deab.variantes(règle du test A/B) : redonne sonbody_design, sinon il est détaché.POST /email/sequences/:id/steps,PUT /email/steps/:id:body_design, même règle.- La règle de détachement : un
body_htmlenvoyé sansbody_designsur une ligne qui avait un projet l'efface (body_design = null) ;body_design: nullaussi. Un autre champ seul (objet, délai…) ne touche pas au projet. - Les détails (
GET /email/broadcasts/:id,GET /email/steps/:id) et les réponses des écritures rendentbody_designeta_un_design; les listes (GET /email/broadcasts,GET /email/sequences/:id/steps) rendenta_un_designsans le projet. - Refus :
400 projet_invalide(pas un objet, imbriqué sur plus de 64 niveaux, caractère nul ou Unicode isolé),400 projet_dangereux(avecchemin, ex.pages[0].frames[0].component.components[2].attributes.onerror),400 projet_sans_html,413 projet_trop_gros,413 corps_trop_gros(avecchamp:body_design,variantes[0].body_design…),409 migration_absente(base sans la migration v146 : le HTML s'enregistre, le projet non).
Limites connues
- Le projet n'est pas relu par le serveur : un projet GrapesJS abîmé à la main (par un agent, par l'API) ne se rouvrira pas dans l'éditeur. Le HTML, lui, part normalement.
- Avant un retour arrière sous la v146 : un HTML modifié par l'ancien code ne détache pas le projet — voir
OPERATIONS.md.
Voir aussi
- Envois ponctuels — écrire, tester (A/B compris) et programmer un envoi
- Sequences — les étapes envoyées automatiquement, par abonné
- MCP — tools reference / email — toutes les opérations e-mail