Aller à la documentation
SDK

Suivi des ouvertures et des clics

`emails.getTracking` et toute la ressource `tracking`.

Un message

tracking.ts
const report = await openemail.emails.getTracking('msg_…') console.log(report.openCount, 'opens from', report.recipients.length, 'recipients')for (const link of report.links) console.log(link.url, link.clickCount)

Un message qui n'a jamais été suivi lève une OpenEmailApiError dont isNotFound vaut true, et non un rapport vide. « Nous n'avons rien enregistré » et « personne ne l'a ouvert » sont deux réponses différentes et ne doivent pas partager la même réponse.

Sur l'ensemble de la boîte

tracking-report.ts
await openemail.tracking.list({ opened: false, days: 7, limit: 100 })await openemail.tracking.getStats({ days: 30, offsetMinutes: -new Date().getTimezoneOffset() })await openemail.tracking.get('msg_…')await openemail.tracking.listOpens('msg_…', { includeMachine: true })await openemail.tracking.listClicks('msg_…')

list, listOpens et listClicks renvoient de simples arrays. get, listOpens et listClicks acceptent soit l'id d'envoi msg_…, soit le tmsg_… propre à l'enregistrement de suivi.

Une ressource à part entière plutôt que des champs sur emails, et la raison est la couverture : emails liste des enregistrements d'envoi, qui n'existent que pour le courrier traité par cette API. Le composer, les outils MCP et l'assistant envoient tous sans en créer : un rapport bâti sur emails serait donc un rapport sur votre trafic API plutôt que sur la boîte.

Lire les chiffres honnêtement

PaireCe que cela signifie
`opens` / `clicks`Ce qui a été APPLIQUÉ : si le message est parti avec un pixel ou des liens réécrits.
`opened` / `clicked`Ce qui s'est passé.
`openCount`Les hits comptabilisés. Scanners et proxys de confidentialité exclus.
`openCountRaw`Tous les hits. C'est en citant ce chiffre comme engagement qu'un taux d'ouverture dépasse 100 %.
`attributable`Si une lecture peut seulement être rattachée à un destinataire nommé.

Les taux renvoyés par tracking.getStats portent sur les messages SUIVIS, jamais sur tout ce qui a été envoyé. Sans quoi une boîte qui suit un message sur dix aurait l'air de s'être effondrée.

Paramètres : tracking.list

openedboolean
`true` sélectionne les messages ayant au moins une ouverture comptabilisée, `false` sélectionne les messages suivis qui n'en ont aucune. Aucune des deux valeurs n'est un défaut, et `false` ne désigne jamais le courrier non suivi, qui n'apparaît pas du tout dans cette liste.
clickedboolean
Le même filtre pour les clics comptabilisés, appliqué indépendamment d'`opened`. Les deux peuvent être fournis, et les messages doivent satisfaire les deux.
daysnumber
Sur combien de jours en arrière regarder à partir de maintenant, de 1 à 365, 30 par défaut ; hors de cette plage, c'est un 422. La fenêtre se mesure sur la date de création de l'enregistrement de suivi, et seuls les enregistrements dont l'envoi est réellement parti sont listés.
limitnumber
Au maximum ce nombre de messages, de 1 à 200, 50 par défaut, du plus récent au plus ancien. Il n'y a pas de cursor : c'est un rapport sur une fenêtre et non un flux, il est donc borné par `days` et `limit` et se lit d'un bloc.

Réponse : TrackingResource

object'tracking'
Toujours `'tracking'` sur un rapport récupéré pour lui-même, via `tracking.get`, `tracking.list` ou `emails.getTracking`. Le même rapport imbriqué sous `email.tracking` sur un message récupéré arrive sans cette clé, car il y fait partie de cet object au lieu d'avoir été récupéré.
idstring
L'id propre à l'enregistrement de suivi, `tmsg_…`. C'est sur lui que sont indexés les appels par hit `listOpens` et `listClicks` ; un `msg_…` qui leur est transmis est d'abord résolu vers celui-ci.
sendIdstring | null
L'envoi `msg_…` auquel cet enregistrement se rattache, et null quand aucun enregistrement d'envoi n'a été écrit. Le composer, le `sendEmail` de MCP et l'assistant envoient tous sans en créer. Le suivi couvre la boîte, pas seulement le trafic API.
threadIdstring | null
Renseigné après la transmission pour qu'une UI de lecture puisse retrouver le message, et null quand le driver n'en a rapporté aucun. Pas structurant : un enregistrement où il vaut null compte quand même.
messageIdstring | null
Le Message-ID RFC 5322, pas notre id. Également renseigné après la transmission, et null quand le transport n'a rien renvoyé pour le remplir.
subjectstring | null
L'objet tel qu'il était au moment de l'envoi. Null sur un message enregistré sans objet.
fromstring
L'adresse d'expédition, copiée sur l'enregistrement plutôt que jointe depuis l'envoi. Les rapports se lisent longtemps après coup, et une adresse corrigée ou supprimée depuis réécrirait sinon l'histoire.
sourceEmailSource | (string & {})
Quelle surface l'a envoyé : `composer`, `api`, `mcp`, `ai` ou `queue`. Typé ouvert pour qu'une surface que ce SDK ne nomme pas encore ne soit pas un changement cassant.
sentAtstring | null
Quand le message est parti, sous forme d'instant ISO-8601. Null sur un enregistrement dont l'envoi ne s'est jamais terminé. `tracking.list` les exclut, `get` non.
opensboolean
Indique si un pixel a été APPLIQUÉ à ce message. C'est ce qui a été fait, pas ce que dit aujourd'hui le réglage du compte.
clicksboolean
Indique si les liens de ce message ont été réécrits. False quand le corps ne portait aucun lien, car rien n'a alors été modifié et un enregistrement prétendant le contraire ne pourrait pas être réconcilié avec les octets.
openedboolean
Indique si une ouverture comptabilisée a été enregistrée sur l'ensemble des copies. À lire en regard d'`opens` : aucune donnée parce qu'aucune n'a été collectée est un fait différent de personne n'a lu le message.
clickedboolean
Indique si un clic comptabilisé a été enregistré. Preuve plus solide qu'une ouverture, car les images sont bloquées bien plus souvent que les liens ne restent inexplorés.
attributableboolean
Indique si chaque lecture rapportée ici peut être rattachée à un destinataire nommé. False dès qu'une copie non attribuée présente une activité comptabilisée, c'est-à-dire le cas multi-destinataires où un seul corps part vers toute la liste sous un même token : vérifiez-le avant d'écrire « Bob n'a pas ouvert ce message ».
openCountnumber
Les ouvertures jugées causées par une personne, additionnées sur les copies. Les hits machine sont exclus et les répétitions dans les trente secondes fusionnent en une seule : c'est donc le chiffre à mettre sous les yeux d'un lecteur.
clickCountnumber
Les clics comptabilisés, additionnés sur les copies. Dédupliqués par lien et non par message : deux liens différents suivis à quelques secondes d'intervalle comptent donc pour deux clics.
openCountRawnumber
Tous les chargements du pixel, scanners et proxys de confidentialité compris. `openCountRaw - openCount` donne le nombre que le classifieur a écarté, et c'est la seule preuve disponible que le filtrage a bien eu lieu.
clickCountRawnumber
Toutes les visites sur un lien réécrit, hits machine et répétitions compris.
firstOpenAtstring | null
La première ouverture comptabilisée parmi les copies, et null tant qu'il n'y en a aucune. Les hits machine ne la déplacent jamais.
lastOpenAtstring | null
La dernière ouverture comptabilisée parmi les copies, null tant qu'il n'y en a aucune.
firstClickAtstring | null
Le premier clic comptabilisé parmi les copies, null tant qu'il n'y en a aucun.
lastClickAtstring | null
Le dernier clic comptabilisé parmi les copies, null tant qu'il n'y en a aucun.
recipientsTrackingRecipientResource[]
Une entrée par copie suivie : une par destinataire quand le transport permet aux octets de différer d'une personne à l'autre, et une seule entrée partagée quand il ne le permet pas. L'entrée partagée est écartée sauf si quelque chose y a réellement atterri : une ligne « quelqu'un » restée intacte ne côtoie donc jamais de vrais noms.
recipients[].emailstring | null
À qui cette copie est allée, en minuscules et telle qu'elle était au moment de l'envoi. Null exactement quand `attributed` vaut false.
recipients[].kind'to' | 'cc' | 'bcc' | null
Sur quel en-tête l'adresse figurait, pour qu'un rapport se lise comme se lisait le message. Null sur la copie partagée, qui n'appartient à aucune adresse.
recipients[].attributedboolean
Indique si cette ligne nomme une personne. À lire avant `email` : false désigne la copie partagée, listée dès qu'un hit y atterrit, et mettre un nom sur ce hit, même sur un message à destinataire unique, inventerait le seul fait que le mécanisme ne peut pas fournir.
recipients[].openCountnumber
Les ouvertures comptabilisées sur cette seule copie, sous les mêmes exclusions que le total du message : hits machine écartés, et répétitions dans les trente secondes fusionnées en une seule.
recipients[].clickCountnumber
Les clics comptabilisés sur cette seule copie, dédupliqués par lien et non par copie.
recipients[].firstOpenAtstring | null
La première ouverture comptabilisée sur cette copie, null tant qu'il n'y en a aucune.
recipients[].lastOpenAtstring | null
La dernière ouverture comptabilisée sur cette copie, null tant qu'il n'y en a aucune.
recipients[].firstClickAtstring | null
Le premier clic comptabilisé sur cette copie, null tant qu'il n'y en a aucun.
recipients[].lastClickAtstring | null
Le dernier clic comptabilisé sur cette copie, null tant qu'il n'y en a aucun.
linksTrackingLinkResource[]
Tous les liens réécrits dans ce message, ordonnés selon leur position dans le corps. Vide quand il n'y en a eu aucun : un message envoyé avec `clicks` désactivé, ou un message dont le corps ne portait aucun lien.
links[].idstring
L'id propre au lien, `lnk_…`. C'est la valeur que désigne le `linkId` d'une ligne de clic, ce qui permet de rattacher un hit issu de `listClicks` à l'entrée correspondante ici.
links[].urlstring
Où mène réellement le lien, tel qu'il figurait dans le message avant réécriture. Le redirecteur résout un id vers cette valeur et envoie le visiteur plus loin.
links[].labelstring | null
Le texte du lien tel qu'il apparaissait dans le message, ou null quand le lien n'en avait pas, par exemple une image ou une URL nue. Il est là pour qu'un rapport puisse dire « le lien tarifs » au lieu de citer une URL portant trois paramètres de suivi, et il ne remplace jamais `url`.
links[].clickCountnumber
Les visites comptabilisées sur ce lien, additionnées sur les copies. La même fenêtre de trente secondes par lien que `clickCount` sur le message.
links[].clickCountRawnumber
Toutes les visites sur ce lien, hits machine et répétitions compris.