Email Lists
Une liste, c'est un conteneur d'abonnés avec ses propres réglages d'opt-in, son SMTP attaché, sa sequence par défaut, et son binding à des landings. Toute la machinerie (sends, events, suppression) s'organise autour de ce concept.

Concept
Une liste répond à trois besoins :
- Segmenter ta base. Différentes audiences (acheteurs sweepstakes vs nutra vs SaaS) n'ont pas besoin des mêmes drips. Une liste = un segment grossier ; les
custom_fieldsJSONB sur chaque subscriber permettent une segmentation fine au sein de la liste. - Isoler les réglages d'envoi. Une liste a sa propre adresse
from_email/from_name, sonreply_to, son SMTP, ses politiques opt-in. Tu peux router "Newsletter brand A" via Mailgun et "Transactional brand B" via Postmark, depuis la même instance. - Brancher l'enrôlement. Une landing pointe une liste via
landing_pages.email_list_id. Un conversion trigger pointe une liste viaemail_conversion_triggers.target_list_id. Une liste, c'est l'adresse stable vers laquelle tu redirigies des subscribers depuis n'importe quelle source.
Le modèle de données
Schema email_lists (extrait) :
| Colonne | Type | Note |
|---|---|---|
id |
SERIAL PK | |
name |
TEXT | label humain |
slug |
TEXT UNIQUE | utilisé dans les URLs de tracking |
smtp_server_id |
INTEGER FK | NULL = pas encore configuré — la liste accepte des subscribers mais refuse d'envoyer |
default_sequence_id |
INTEGER FK | sequence auto-déclenchée à l'enrollment (NULL = pas de drip auto) |
double_opt_in |
BOOLEAN | si true, le subscriber doit cliquer un lien de confirmation avant de recevoir la sequence |
track_opens |
BOOLEAN | injecte le pixel d'ouverture |
track_clicks |
BOOLEAN | réécrit les liens via un redirect signé |
unsubscribe_redirect_url |
TEXT | URL vers laquelle on redirige après un click sur unsubscribe (vide = page interne) |
custom_unsubscribe_message |
TEXT | message affiché sur la page d'unsubscribe (vide = défaut) |
confirmation_subject |
TEXT | subject de l'email de double opt-in |
confirmation_body_html |
TEXT | HTML du même |
from_name_override |
TEXT | si non-vide, écrase le from_name du SMTP server |
reply_to_override |
TEXT | idem pour reply-to |
sto_enabled |
BOOLEAN | active Send-Time Optimization (chaque send est snappé à l'heure préférée du subscriber) |
sto_default_hour |
SMALLINT 0-23 UTC | heure de fallback quand on n'a pas encore appris la préférence d'un subscriber |
is_active |
BOOLEAN | soft-disable : aucune envoi, mais la liste reste lisible |
subscriber_count |
INTEGER | dénormalisé, mis à jour par trigger |
deleted_at |
TIMESTAMPTZ | soft-delete : la liste disparaît de l'UI mais reste queryable pour l'archive |
Créer une liste
Via l'UI
Sidebar → Email Marketing → Lists → New list. Tu remplis les champs essentiels :
- Name + slug (auto-suggéré depuis le name)
- SMTP server — optionnel, tu peux laisser vide et brancher plus tard
- Double opt-in — coche si tu veux la confirmation par email avant d'envoyer la sequence
- Track opens / Track clicks — décoche pour les listes transactionnelles où le tracking serait inutile / mal vu
Via MCP
// Request
{
"name": "create_email_list",
"arguments": {
"name": "Sweepstakes Buyers FR",
"slug": "sweeps-buyers-fr",
"smtp_server_id": 1,
"double_opt_in": false,
"track_opens": true,
"track_clicks": true
}
}
// Response
{
"status": "ok",
"tool": "create_email_list",
"message": "Email list created",
"list": {
"id": 7,
"name": "Sweepstakes Buyers FR",
"slug": "sweeps-buyers-fr",
"smtp_server_id": 1,
"default_sequence_id": null,
"subscriber_count": 0,
"is_active": true,
"created_at": "2026-05-18T12:14:02.213Z"
}
}
Le tool est défini dans autopilot-email-tools.js. Scope requis : email:write.
Modes d'opt-in
| Mode | double_opt_in |
Comportement |
|---|---|---|
| Single opt-in | false |
Le subscriber est status='subscribed' immédiatement. La sequence démarre dès l'enrollment. |
| Double opt-in | true |
Le subscriber est status='pending_confirm'. Un email de confirmation est envoyé. Tant qu'il n'a pas cliqué le lien (confirm_token), aucun email de la sequence n'est envoyé. |
Quand choisir lequel ?
- Single opt-in : trafic affiliate, leads qualifiés par un formulaire prelander, conversions e-commerce. Le coût d'opportunité d'attendre un click de confirmation est trop élevé.
- Double opt-in : list-building pur (lead magnet, newsletter), audiences européennes où le GDPR pousse à documenter le consentement, listes que tu veux protéger contre le bot signup.
Champs GDPR / compliance
Trackily stocke pour chaque subscriber :
enrolled_at— quand le consentement a été donnéconfirmed_at— quand le lien double opt-in a été cliqué (si applicable)ip— IP au moment de l'enrollmentuser_agent— UA du browsersource— texte libre ("landing:foo-slug","manual:admin","trigger:postback-offer-42")country_code— auto-détecté via le tracking
Ces données t'aident à prouver le consentement en cas de demande GDPR. Pas de RGPD-magic automatique : à toi d'exposer une page d'export / suppression (et de propager l'unsubscribe vers email_suppression si la personne le demande).
Subscriber counts
email_lists.subscriber_count est dénormalisé pour éviter un COUNT(*) à chaque chargement de page. Il est recalculé :
- À chaque
enroll_email_subscriber/unsubscribe_email_subscriber - À chaque bounce / complaint reçu via webhook MTA
- Manuellement via un utilitaire admin si tu as bidouillé la DB en direct
Le compteur reflète les status='subscribed' uniquement — pending_confirm, unsubscribed, bounced, complained ne comptent pas.
Lister, inspecter, éditer
Lister toutes les listes
// Request
{ "name": "list_email_lists", "arguments": {} }
// Response (excerpt)
{
"status": "ok",
"lists": [
{
"id": 1,
"name": "Newsletter FR",
"slug": "newsletter-fr",
"subscriber_count": 8421,
"smtp_server_id": 1,
"default_sequence_id": 3,
"double_opt_in": false,
"is_active": true,
"bound_landings": 4,
"sequences": 2
}
]
}
Inspecter en profondeur
{
"name": "get_email_list_detail",
"arguments": { "id": 1 }
}
Retourne settings + histogramme des subscriber statuses + 10 plus récents subscribers + sequences attachées + landings bound. À utiliser AVANT toute opération de masse (rotation de sequence, soft-delete, changement de SMTP) pour t'éviter une surprise.
Patch incrémental
{
"name": "update_email_list",
"arguments": {
"id": 1,
"default_sequence_id": 5,
"from_name_override": "Marie de Brand FR"
}
}
Tu envoies seulement les champs à modifier. Les autres restent intacts.
Bind une liste à une landing
{
"name": "bind_landing_to_email_list",
"arguments": {
"landing_id": 42,
"list_id": 7
}
}
Toute soumission du formulaire de la landing enrôle désormais l'email dans la liste 7 et démarre sa default_sequence. Pour unbind, passe "list_id": null.
Détails sur les automations dans la page dédiée → Automations.
Soft-delete
Une liste se supprime de manière réversible. La table email_lists reçoit deleted_at = NOW(), mais les subscribers, sends, events, suppression sont conservés.
{
"name": "delete_email_list",
"arguments": { "id": 1 }
}
C'est un tool Tier-2 : la première call retourne une preview avec subscriber_count + nombre de landings bound. Tu rappelles avec confirm_token pour exécuter.
Erreurs courantes
- "column does not exist : from_name_override" — ta DB n'a pas appliqué la migration v41. Lance le startup une fois, le migrator y va.
- Sequence ne démarre pas — vérifie que
default_sequence_idest bien set sur la liste. Sans ça, l'enrollment se fait mais aucune drip ne tourne. - Subscribers en
pending_confirmqui ne reçoivent rien — double opt-in actif sans SMTP configuré → la confirmation email ne part jamais. Branche un SMTP ou désactive le double opt-in. - Compteur figé à 0 — tu as utilisé
INSERT INTO email_subscribersdirect au lieu de passer parenroll_email_subscriber(qui met à jour le compteur).
Voir aussi
- Sequences — l'autoresponder qui se déclenche à l'enrollment
- SMTP — relais à attacher
- Automations — binding landing/liste, conversion triggers, post-purchase
- Suppression — pourquoi un subscriber peut être bloqué
- MCP — tools reference — tous les tools email en un endroit