Aller au contenu principal

Envoi d'emails

Prérequis​

Requis à la création​

  • Au moins un Folder créé pour organiser vos campagnes.
  • Au moins un Email créé pour être utilisé dans la campagne.

Requis avant l'envoi​

  • Au moins une List créée contenant les Contacts à qui vous voulez envoyer l'email.

Étapes pour créer une EmailCampaign​

1 - Créer une ressource Folder (si nécessaire)​

Si vous n'avez pas encore de Folder, créez-en un d'abord avec une requête POST sur l'endpoint /v1/folder/.

POST /v1/folder/ HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"name": "<folder_name>",
"description": "<folder_description>"
}
réponse
{
"_id": "<folder_id>", //<--- utilisez cet ID dans les prochaines étapes
"name": "<folder_name>",
"description": "<folder_description>"
// ...
}

2 - Créer votre ressource Email​

Avant de créer une EmailCampaign, vous devez créer au moins une ressource Email contenant le design de l'email, avec une requête POST sur l'endpoint /v1/email/.

POST /v1/email/ HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"name": "Nom de l'email",
"description": "Description de l'email",

"subject": "Sujet de l'email",
"preheader": "Texte de preheader affiché après le sujet",
"fromemail": "[email protected]",
"fromname": "Nom de l'expéditeur",
"unsubscribetext": "Cliquez ici pour vous désabonner",

"editor": "bee",
"body": "<bee_html>",
"json": "<bee_json>"
}
réponse
{
"_id": "<email_id>", //<--- utilisez cet ID dans les prochaines étapes
"name": "Nom de l'email",
// ...
}

HTML & JSON​

Nous recommandons d'utiliser notre éditeur visuel pour créer le design de la ressource Email ; il génère à la fois le body HTML et l'attribut json. Cela dit, un contenu statique est rarement ce que l'on veut en passant par l'API. Pour créer un design d'email dynamique, nous recommandons les options suivantes :

Remplacements de texte simples
Pour les cas simples, créez un design de base avec notre éditeur visuel et utilisez-le comme template pour votre contenu dynamique. Ajoutez des placeholders facilement identifiables comme {{my_custom_text}} dans le contenu. Nous utilisons déjà la syntaxe « moustaches » {{...}} comme merge tags pour les propriétés de contact lors du rendu, et nous retirons tout tag inconnu avant l'envoi. C'est pratique pour des remplacements de texte simples.

Par exemple, vous créez une EmailCampaign & un Email via l'UI avec Bonjour {{firstname}}, voici votre offre spéciale : {{special_offer_code}} dans un bloc de texte. Vous utilisez cet Email comme template. Récupérez-le et remplacez uniquement le tag {{special_offer_code}} par votre propre code promo, dans le json & le body, que vous utilisez ensuite pour créer de nouvelles ressources EmailCampaign & Email via l'API. Vous avez laissé le tag {{firstname}} tel quel : il sera remplacé à l'envoi par le prénom réel du contact par notre moteur de rendu, comme prévu.

Cette approche est simple mais limitée aux remplacements de texte ; si vous avez besoin d'un contenu dynamique plus complexe en HTML, considérez l'option suivante.

Bloc HTML
Même approche que ci-dessus mais avec un bloc HTML plutôt qu'un bloc de texte. Ajoutez un tag placeholder comme {{dynamic_content}}. Dans votre code, récupérez la ressource Email et remplacez le tag {{dynamic_content}} dans le json & le body par votre propre contenu HTML généré. Vous pouvez générer du HTML complexe avec votre propre code ou vos propres templates.

attention

Prenez soin de générer du HTML valide pour les clients mail, qui n'est pas le même que le HTML web habituel.

3 - Créer votre ressource EmailCampaign​

Enfin, créez votre EmailCampaign avec une requête POST sur l'endpoint /v1/campaign/, en utilisant l'ID du Folder de l'étape 1 et le ou les IDs d'Email de l'étape 2.

POST /v1/campaign/ HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"name": "Nom de la campagne email",
"description": "Description de la campagne email",

"type": 2, /* EMAIL */
"status": "d", /* DRAFT */
"folder": "<folder_id>",
"start": "2026-01-01T00:00:00.000Z",
"batchConfiguration": { "type": "none" },

/* Variantes d'email (tests A/B) */
"emails": [
{ "email": "<email_id>", "weight": 100 }
],

/* Listes de contacts à qui envoyer */
"lists": [
{ "list": "<list_id>" }
],

/* Mailing List (si la fonctionnalité RGPD est activée) */
"mailinglist": {
"mailinglist": "<mailinglist_id>",
"statusFilter": 0, /* OPT_IN_ONLY: 0, UNDEFINED_ONLY: 1, OPT_IN_OR_UNDEFINED: 2 */
"language": null, /* "fr", "en" */
},
}
réponse
{
"_id": "<campaign_id>",
"name": "Nom de la campagne email",
// ...
}
attention

Notre système suppose toujours qu'un Email appartient à une seule EmailCampaign.

Ne partagez pas une entité Email entre plusieurs EmailCampaigns ; créez toujours des entités distinctes. Pour réutiliser le même design, dupliquez d'abord l'entité Email. Le plus simple est de faire une requête GET pour récupérer l'Email existant, d'en extraire les attributs json & body, puis de faire une requête POST pour en créer un nouveau avec ces données.

La liste spéciale « Tous les contacts »​

En mettant l'attribut list à null, vous utilisez la liste spéciale « Tous les contacts » pour envoyer l'EmailCampaign à tous les Contacts du Client :

PUT /v1/campaign/<campaign_id> HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json

{ "lists": [{ "list": null }] }
info

Nous avons volontairement rendu ce choix explicite pour éviter un envoi accidentel à tous les Contacts lorsqu'aucune List n'est spécifiée (campaign.lists vide).

Exclure des listes​

Vous pouvez exclure des Lists précises de votre campagne avec excluded: true. C'est utile pour cibler une large audience tout en excluant certains segments.

Exemple : inclure une liste, en exclure une autre

{
"lists": [
{ "list": "<include_list_id>" },
{ "list": "<exclude_list_id>", "excluded": true }
]
}

Exemple : envoyer à tous les contacts sauf une liste précise

{
"lists": [
{ "list": null },
{ "list": "<exclude_list_id>", "excluded": true }
]
}

Envoyer votre EmailCampaign​

Planification​

L'attribut start de l'EmailCampaign permet de planifier le début de l'envoi. Pour envoyer immédiatement, utilisez la date et l'heure actuelles (ou passées).

Contrôle du débit​

L'attribut batchConfiguration de l'EmailCampaign permet de configurer le contrôle du débit.

Pas de lots, tout est envoyé d'un coup aussi vite que possible.

{ "batchConfiguration": { "type": "none" } }

Envoi​

Lorsque vous êtes prêt, mettez simplement le status de l'EmailCampaign à a (ACTIVE).

PUT /v1/campaign/<campaign_id> HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"status": "a",
"start": "2024-06-01T12:00:00.000Z",
"batchConfiguration": { "type": "none" }
}

Récupérer les métriques d'une EmailCampaign​

Après l'envoi d'une EmailCampaign, vous pouvez récupérer ses métriques de performance pour analyser son efficacité.

Endpoint de métriques​

GET /v1/metric/<element_type>/<element_id>/email

Paramètres de path :

  • element_type :
    • campaign - Métriques d'une EmailCampaign (toutes les variantes)
    • target - Métriques d'une variante Email précise
    • owner - Métriques de toutes les EmailCampaigns du client
  • element_id : L'ID de l'élément (Campaign, Email, ou Client pour owner)

Paramètres de requête :

  • compile=true : Totaux agrégés sur toute la période
  • startdate + enddate : Métriques pour une plage de dates (format ISO 8601), groupées par jour par défaut
  • groupBy : day (défaut), week ou month — s'applique seulement avec startdate + enddate. Lorsqu'il est fourni, la plage startdate/enddate est limitée à 12 mois (400 au-delà) ; cette limite ne s'applique pas lorsque groupBy est omis.
  • breakdown : campaign, automation, folder ou target — valide seulement avec element_type=owner. Retourne une ventilation par élément en plus du total agrégé, plutôt qu'un seul agrégat. Une cinquième valeur, source, existe uniquement sur le subject session (ventilation par source de trafic, avec les sous-sources imbriquées dans children) et ne s'applique pas aux métriques email. La réponse contient aussi summary : les totaux du owner sur toute la plage (avec les taux), pour éviter d'additionner les buckets ou de faire un second appel.
  • timezone : Nom de fuseau horaire IANA (ex. America/Toronto). Interprète startdate/enddate comme des jours locaux de ce fuseau et groupe groupBy dans ce fuseau. UTC par défaut.

Définition des métriques :

MétriqueDescription
sentNombre total d'emails envoyés avec succès
openNombre total d'ouvertures (inclut les ouvertures multiples d'un même contact)
uniqueopenNombre de contacts uniques ayant ouvert l'email (compté une fois par contact)
clickNombre total de clics sur des liens (inclut les clics multiples d'un même contact)
uniqueclickNombre de contacts uniques ayant cliqué sur un lien (compté une fois par contact)
bounceNombre d'emails rebondis (hard et soft bounces)
unsubscribeNombre de contacts qui se sont désabonnés
spamNombre de plaintes pour spam
openRateuniqueopen / sent * 100, arrondi à 2 décimales, 0 lorsque sent vaut 0
clickRateuniqueclick / sent * 100, arrondi à 2 décimales, 0 lorsque sent vaut 0
unsubscribeRateunsubscribe / sent * 100, arrondi à 2 décimales, 0 lorsque sent vaut 0

Les champs de taux apparaissent sur la ligne compile=true, sur chaque bucket groupBy et sur chaque élément/summary de breakdown — toujours, que groupBy soit utilisé ou non.

Schémas de réponse​

Métriques totales (compile=true, startdate/enddate optionnels)​

[
{
"_id": <element_id>,
"sent": number,
"open": number,
"uniqueopen": number,
"click": number,
"uniqueclick": number,
"bounce": number,
"unsubscribe": number,
"spam": number,
"openRate": number,
"clickRate": number,
"unsubscribeRate": number
}
]

Métriques quotidiennes (startdate/enddate, groupBy=day)​

[
{
"_id": { "group": <element_id>, "year": number, "month": number, "day": number },
"date": string, // début du bucket, ISO 8601 UTC (minuit local dans `timezone`, sinon UTC)
"sent": number,
"open": number,
"uniqueopen": number,
"click": number,
"uniqueclick": number,
"bounce": number,
"unsubscribe": number,
"spam": number,
"openRate": number,
"clickRate": number,
"unsubscribeRate": number
}
]

Métriques hebdomadaires (startdate/enddate, groupBy=week)​

[
{
"_id": { "group": <element_id>, "isoYear": number, "isoWeek": number },
"date": string, // début du bucket : minuit local du lundi de la semaine ISO
"sent": number,
// ...mêmes métriques et taux que ci-dessus
}
]

Métriques mensuelles (startdate/enddate, groupBy=month)​

[
{
"_id": { "group": <element_id>, "year": number, "month": number },
"date": string, // début du bucket : minuit local du 1er
"sent": number,
// ...mêmes métriques et taux que ci-dessus
}
]

Lorsque groupBy est fourni, la réponse est complétée par des zéros : exactement une ligne par bucket de startdate à enddate inclusivement, en ordre croissant, avec toutes les métriques à 0 pour les buckets sans activité. Omettre groupBy conserve l'ancien comportement (buckets par jour, mais seulement pour les jours ayant des données, sans champ date ni champs de taux) pour les intégrations existantes.

Métriques ventilées (element_type=owner, breakdown=campaign|automation|folder|target)​

{
"total": [ /* même forme que ci-dessus, pour le groupBy demandé */ ],
"items": [
{
"id": <campaign_or_automation_or_folder_or_email_id>,
"name": string | null, // résolu depuis la collection de l'élément ; null pour breakdown=target ou un document manquant
"type": number | null, // type de campagne, breakdown=campaign seulement
"start": Date | null, // date d'envoi de la campagne, lorsque définie
"created": Date | null,
"deleted": boolean, // les éléments supprimés (soft delete) conservent leurs métriques et sont signalés ici
"totals": {
"sent": number,
"open": number,
"uniqueopen": number,
"click": number,
"uniqueclick": number,
"bounce": number,
"unsubscribe": number,
"spam": number,
"openRate": number,
"clickRate": number,
"unsubscribeRate": number
}
}
],
"summary": {
// même forme que les `totals` d'un élément - les totaux du owner sur toute la plage, avec les taux
}
}

items ne liste que les éléments ayant au moins une métrique non nulle dans la plage, triés par sent décroissant. Il n'y a pas de limite au nombre d'éléments retournés — un client avec 2 000 campagnes reçoit 2 000 éléments. Chaque élément porte ses champs d'affichage (name, type, start, created, deleted) résolus dans la même agrégation ; inutile de lister les campagnes ou les automatisations séparément pour les nommer.

Obtenir les métriques totales d'une campagne​

Pour récupérer les métriques totales agrégées d'une EmailCampaign, utilisez le paramètre compile=true :

GET /v1/metric/campaign/<campaign_id>/email?compile=true HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
réponse
{
"_id": "<campaign_id>",
"sent": 1000,
"open": 250,
// ...
}
info

Retourne les métriques agrégées de toutes les variantes Email de l'EmailCampaign.

Utilisez target plutôt que campaign dans le path pour récupérer les métriques d'une variante Email précise :
GET /v1/metric/target/<email_id>/email?compile=true

Obtenir les métriques quotidiennes d'une campagne​

Pour récupérer les métriques d'une EmailCampaign ventilées par jour, complétées par des zéros sur toute la plage :

GET /v1/metric/campaign/<campaign_id>/email?startdate=2025-01-01&enddate=2025-01-31&groupBy=day HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
réponse
[
{
"_id": { "group": "<campaign_id>", "year": 2025, "month": 1, "day": 1 },
"date": "2025-01-01T00:00:00.000Z",
"sent": 100,
"open": 25,
// ...
},
{
"_id": { "group": "<campaign_id>", "year": 2025, "month": 1, "day": 2 },
"date": "2025-01-02T00:00:00.000Z",
"sent": 0,
"open": 0,
// aucune activité ce jour-là, toutes les métriques sont à 0 - la ligne est tout de même présente
}
// ...une ligne par jour jusqu'au 2025-01-31
]
info

Utilisez target plutôt que campaign dans le path pour récupérer les métriques quotidiennes d'une variante Email précise :
GET /v1/metric/target/<email_id>/email?...

attention

Omettre groupBy conserve l'ancien comportement pour les intégrations existantes : des buckets par jour, mais seulement pour les jours ayant des données (pas de zéros, pas de champ date). Passez groupBy=day (ou week/month) pour obtenir la plage complète, complétée par des zéros, décrite ci-dessus.