Envoyer et suivre des e-mails
Envoyez, envoyez par lots, traduisez, programmez et annulez du courrier avec les commandes `emails`, puis suivez sa livraison, ses ouvertures et ses clics avec `tracking`.
Vue d'ensemble
L'espace de noms emails est l'API d'envoi sous forme de commandes, une pour chaque méthode de openemail.emails dans le SDK. Chacune appelle un point de terminaison et affiche ce qu'il renvoie. L'espace de noms tracking lit les ouvertures et les clics sur le courrier que vous avez envoyé. openemail email fonctionne à la place de openemail emails.
Chaque commande ici a besoin d'une connexion, par le navigateur ou par une clé API, et de l'un de deux scopes : emails:send pour envoyer, traduire, annuler et reprogrammer, et emails:read pour tout ce qui ne fait que lire.
Quel envoi utiliser
openemail send est la commande écrite à la main de la page Courrier, et elle envoie via emails send. Elle est faite pour une personne au terminal : elle choisit l'adresse d'envoi quand vous omettez --from, lit le corps depuis un fichier, stdin ou votre éditeur, joint des fichiers par leur chemin et affiche un récapitulatif à confirmer avant que quoi que ce soit ne parte. openemail emails send prend le corps de la requête en options, une pour chaque champ, et ne demande rien, ce qui convient à un script qui sait exactement ce qu'il envoie.
| send | emails send |
|---|---|
| --from <address> | Obligatoire, comme --to, sauf si --data le contient. send peut l'omettre et choisir une adresse pour vous |
| -f, --body-file <path> | Pas d'option de fichier pour le corps. Passez --html "$(cat body.html)", ou toute la requête dans --data @email.json |
| -a, --attach <path> | --attachments, un tableau JSON de fichiers, chacun avec un filename et un content en base64, ou avec le fileId d'un fichier déjà présent dans Fichiers |
| --at <when> | --scheduled-at <when>, un instant ISO 8601 ou une durée comme PT1H ou P2D. send accepte aussi des délais courts comme 10m, 2h et 1d |
| --undo <seconds> | --cancellable-for-seconds <n>, de 0 à 900 |
| --translate <language> | --translate '{"to":"de"}', qui accepte aussi from, includeOriginal et subject |
| --template <id> --props <json> | --template '{"id":"welcome","props":{"name":"Ada"}}', qui peut aussi fixer une version |
| --draft <id> | --draft-id <id> |
| --thread <id> | --thread-id <id> |
| --tag <key=value> | --tags <key=value>, répétée, ou un objet JSON |
Seule emails send a --tracking pour désactiver les ouvertures ou les clics sur un envoi, --signature, --headers pour des en-têtes personnalisés, --attachment-delivery pour choisir entre joindre les fichiers et les lier, et --data pour tout le corps en JSON, en ligne, depuis un fichier avec @path ou depuis stdin avec -.
Les deux se terminent différemment. send sort avec le code 1 quand l'e-mail revient failed. emails send sort avec le code 0 dès que l'API a répondu, vérifiez donc status dans ce qu'elle affiche.
Chaque commande emails
send, send-batch, translate, cancel et reschedule ont besoin de emails:send. list, get, list-events et get-tracking ont besoin de emails:read. Un identifiant d'e-mail est msg_ suivi de 24 caractères hexadécimaux, tel qu'un envoi le renvoie.
| Commande | Ce qu'il fait |
|---|---|
| openemail emails send --from <value> --to <a,b> | Envoyer un e-mail maintenant, le retenir pendant une fenêtre d'annulation avec --cancellable-for-seconds, ou le programmer avec --scheduled-at. Le corps est --html, --text ou les deux, un --template enregistré, ou un --draft-id enregistré |
| openemail emails send-batch <emails> | Envoyer jusqu'à 100 e-mails indépendants en une requête, depuis un tableau JSON dans un fichier, en ligne, ou sur stdin avec -. Chaque élément a la forme du corps de emails send et réussit ou échoue de son côté |
| openemail emails translate --to <value> | Prévisualiser ce qu'un envoi traduit livrerait, pour --subject, --html ou --text. Rien n'est enregistré ni envoyé, et cela consomme une action d'IA |
| openemail emails list | Une page d'e-mails envoyés, du plus récent au plus ancien, filtrée par --status, --from ou --broadcast-id |
| openemail emails get <id> | Un e-mail envoyé avec le statut, l'erreur et l'heure de livraison propres à chaque destinataire, et le rapport de suivi complet quand il a été suivi |
| openemail emails list-events <id> | La suite d'événements d'un envoi, du plus ancien au plus récent : accepté, programmé, envoyé, livré, rebondi, plainte, ouvert, cliqué et les autres |
| openemail emails get-tracking <id> | Le rapport d'engagement d'un envoi : ses totaux, une entrée par copie suivie, et chaque lien réécrit avec ses clics |
| openemail emails cancel <id> | Arrêter un e-mail en file d'attente ou programmé avant son départ. Demande confirmation |
| openemail emails reschedule <id> <scheduled-at> | Déplacer un e-mail en file d'attente ou programmé à un instant ISO 8601, ou d'une durée comme PT30M, d'une seconde à 365 jours dans le futur |
Chaque commande tracking
Les cinq ont besoin de emails:read. tracking get, list-opens et list-clicks acceptent l'un ou l'autre des identifiants d'un message : l'identifiant msg_ renvoyé par son envoi, ou l'identifiant de suivi tmsg_ que portent tracking list et les payloads de webhook.
| Commande | Ce qu'il fait |
|---|---|
| openemail tracking list | Une page de messages suivis envoyés sur une période, du plus récent au plus ancien, chacun avec son rapport complet. --opened et --clicked la filtrent, et --no-opened garde ceux que personne n'a ouverts. La période est de 30 jours sauf si --days ou --minutes indique autre chose |
| openemail tracking get-stats | Les chiffres derrière un panneau d'engagement : messages suivis, ouverts et cliqués, taux d'ouverture et de clic, une série temporelle par tranches --grain, et les principaux liens, clients mail et pays |
| openemail tracking get <id> | Le rapport d'engagement d'un message, le même document que renvoie emails get-tracking |
| openemail tracking list-opens <id> | Les ouvertures individuelles derrière le nombre d'ouvertures d'un message, de la plus récente à la plus ancienne, chacune marquée human, proxy ou machine. --include-machine ajoute les hits qui n'ont pas été comptés |
| openemail tracking list-clicks <id> | Les clics individuels sur les liens d'un message, du plus récent au plus ancien, chacun avec son url d'origine. --include-machine ajoute les scanners de liens et les répétitions regroupées |
tracking list et get-stats couvrent chaque message suivi envoyé par la boîte mail, y compris le courrier rédigé dans l'application web et celui envoyé par les outils MCP ou l'assistant, tandis que emails list contient les enregistrements d'envoi créés par l'API. Un rapport sans enregistrement d'envoi a sendId défini à null.
Exemples
Envoyer depuis un script avec votre propre clé d'idempotence. Le relancer avec la même --idempotency-key affiche le premier e-mail avec replayed: true au lieu d'en envoyer un second.
openemail emails send \ --from 'Acme Billing <[email protected]>' \ --to [email protected] \ --subject 'Your September invoice' \ --html '<p>The invoice is attached. Tell me if anything on it looks wrong.</p>' \ --attachments '[{"fileId":"file_6bb640f5b99e47deb758f1f5"}]' \ --tracking '{"opens":false}' \ --idempotency-key invoice:inv_2026_09_4192 \ --json | jq -r '.id + " " + .status'Faites relire une traduction par une personne avant son départ. Envoyez le texte approuvé comme simples --subject et --html, sans --translate, sinon il est traduit une seconde fois. Le html traduit contient déjà votre original en dessous, sauf si vous passez --no-include-original.
openemail emails translate --to de \ --subject 'Your September invoice' \ --html "$(cat invoice.html)" \ --json > preview.jsonjq -r .html preview.jsonopenemail emails send --from [email protected] --to [email protected] \ --subject "$(jq -r .subject preview.json)" \ --html "$(jq -r .html preview.json)"Envoyer un lot depuis un fichier. La commande sort avec le code 0 dès que le lot a été traité, même quand certains éléments ont échoué, lisez donc failed et le status de chaque élément. La relancer avec la même clé rejoue les éléments déjà partis et n'envoie que le reste, tant que le tableau garde son ordre.
[ { "from": "[email protected]", "to": "[email protected]", "subject": "Receipt 4192", "text": "Thanks for your order." }, { "from": "[email protected]", "to": "[email protected]", "subject": "Receipt 4193", "text": "Thanks for your order." }]openemail emails send-batch receipts.json --idempotency-key receipts:2026-09-27 --json > result.jsonjq '{ sent, failed }' result.jsonjq -r '.items[] | select(.status == "error") | "\(.index) \(.error.code)"' result.jsonProgrammer un e-mail, le déplacer, puis l'annuler. --yes répond à la confirmation que demande cancel, ce qu'un script ne peut pas faire.
ID=$(openemail send --from [email protected] --to [email protected] --subject "Standup notes" \ --body-file notes.md --at 2026-10-01T09:00:00Z --json | jq -r .id)openemail emails reschedule "$ID" 2026-10-01T13:00:00Zopenemail emails get "$ID" --json | jq -r '.status + " " + .scheduledAt'openemail emails cancel "$ID" --yesTrouver les envois qui ont échoué et lire ce qui est arrivé à l'un d'eux. Redirigé sans --json, --all affiche un objet JSON par ligne.
openemail emails list --status failed,partial --from [email protected] --all | jq -r .idopenemail emails get msg_3f9a1c07d2b84e6a9c5b1f20openemail emails list-events msg_3f9a1c07d2b84e6a9c5b1f20 --all --json | jq -r '.items[] | .createdAt + " " + .type'Lire une semaine d'engagement en jours qui basculent à minuit UTC+2, lister ce que personne n'a ouvert, et compter les clics sur chaque lien d'un message.
openemail tracking get-stats --days 7 --offset-minutes 120 --json | jq '{ tracked, openRate, clickRate }'openemail tracking list --no-opened --days 7 --all | jq -r .subjectopenemail tracking list-clicks msg_3f9a1c07d2b84e6a9c5b1f20 --all | jq -r .url | sort | uniq -cScopes, codes et confirmations
- Une connexion par navigateur demande des scopes sur la page d'approbation, et
openemail login --scopes emails:send,emails:readprésélectionne les deux. Une commande dont le scope manque s'arrête avec le code de sortie4etinsufficient_scope, et nomme le scope. send --attachavec plus de 5 Mo de fichiers les téléverse d'abord dans Fichiers, ce qui nécessite aussifiles:write.- Aucune de ces commandes ne demande de code de vérification, donc une connexion par navigateur les exécute comme le fait une clé API.
emails canceldemande avant d'annuler, et--yesrépond pour vous. Sans surveillance et sans--yes, elle s'arrête avecRefusing to run unattended. Pass --yes to confirm.et le code de sortie2.emails send,send-batchetreschedulene demandent jamais rien.sendaffiche un récapitulatif et ne demande que dans un terminal, et--yessaute cela aussi.--dry-runaffiche la requête qu'une commande enverrait, n'envoie rien et sort avec le code0. Suremails translate, cela ne consomme aucune action d'IA, et suremails cancel, rien n'est demandé.
Pages de résultats
emails list, emails list-events, tracking list, list-opens et list-clicks lisent une page. --limit fixe sa taille, de 1 à 100 avec 25 par défaut pour les deux listes emails, et de 1 à 200 avec 50 par défaut pour les trois listes tracking. --cursor reprend au curseur qu'une page a affiché.
--alllit chaque page et diffuse les éléments : un tableau dans un terminal, et un objet JSON par ligne quand la sortie est redirigée ou avec--ndjson.--max <n>s'arrête après autant d'éléments, et implique--all.--jsonaffiche un seul document{ items, hasMore, nextCursor },--allcompris.- La pagination se fait par curseur, pas par décalage, donc le courrier envoyé pendant que vous parcourez les pages ne décale ni ne répète jamais une ligne.
Bon à savoir
- Chaque exécution crée sa propre clé d'idempotence, qui couvre les nouvelles tentatives au sein de cette exécution. Lancer un envoi deux fois envoie deux fois, sauf si les deux exécutions passent la même
--idempotency-key. La même clé avec un corps différent est refusée avecidempotency_key_reuseet le code de sortie7. - Seul le courrier
queuedetscheduledpeut être annulé ou déplacé. Un envoi immédiat sans fenêtre d'annulation part au cours de la requête, donc quand vous avez son identifiant, il est en général trop tard, et l'appel se termine avecemail_not_cancellableet le code de sortie6. - Un e-mail annulé reste annulé. Reprogrammer ne change que l'heure, comptée pour une durée à partir de la réception de la requête par le serveur : pour changer le texte, annulez et envoyez à nouveau.
- Une traduction impossible à produire fait refuser tout l'envoi, et rien ne part sans traduction. Un lot traduit contient au plus 10 messages portant
translate. - Un quota d'envoi épuisé arrête un envoi avec
send_quota_exceededjusqu'au premier du mois, et un quota d'IA épuisé arrête une traduction avecai_quota_exceededjusqu'à minuit UTC, tous deux avec le code de sortie8. - Le courrier envoyé avec une clé
oe_test_n'est jamais livré. Il indiquesent, avectransportdéfini àtest, et n'est jamais suivi. emails get-trackingettracking getrépondent 404, code de sortie5, pour un message sans pixel ni lien réécrit, car non suivi n'est pas la même chose que non ouvert. Le suivi respecte le réglage avec lequel le message a été envoyé, donc l'activer plus tard n'atteint pas le courrier antérieur.- Chaque chiffre est un minimum. Un lecteur dont le client mail bloque les images ne compte jamais comme une ouverture, et un clic prouve davantage la lecture qu'une ouverture.
list-opensetlist-clicksrépondent 404 pour un identifiantmsg_sans rien de suivi, mais prennent un identifianttmsg_tel quel, donc un identifiant inconnu revient sous forme de liste vide.- Une clé limitée à certaines adresses ne voit que le courrier envoyé depuis ces adresses, et une clé qui couvre tout un domaine couvre chaque adresse de ce domaine.
Chaque option
Cette page nomme les options qui comptent le plus. openemail <command> --help liste chaque argument et option d'une commande, avec son type, le scope nécessaire, sa méthode et son chemin, ce qu'elle renvoie et les notes de la référence de l'API. Ajoutez --json pour obtenir la même aide sous forme d'un seul document JSON.
openemail emails --helpopenemail emails send --helpopenemail tracking list-opens --help --json