Sur cette page
Documentation API
API de courriel
Du courriel transactionnel sur le même compte, la même clé et le même solde que vos SMS, avec des données stockées au Canada et les règles de la LCAP intégrées.
Démarrage rapide
Avec une clé de test, vous pouvez envoyer avant de configurer un domaine : envoyez depuis onboarding@test.honkio.ca vers l’une des adresses de test ci-dessous. Rien n’est livré et rien n’est facturé.
curl -X POST https://api.honkio.ca/v1/emails \
-H "Authorization: Bearer mk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <onboarding@test.honkio.ca>",
"to": "delivered@test.honkio.ca",
"subject": "Hello from HonkIO",
"html": "<p>It works.</p>"
}'
# Response 201: { "id": "cm...", "status": "queued", "scheduled_at": null }Le même envoi avec le SDK Node, @honkio/node. Chaque appel renvoie data ou error et ne lève jamais d’exception pour une erreur de l’API.
import { Honkio } from '@honkio/node'
const honkio = new Honkio(process.env.HONKIO_API_KEY)
const { data, error } = await honkio.emails.send({
from: 'Acme <onboarding@test.honkio.ca>',
to: 'delivered@test.honkio.ca',
subject: 'Hello from HonkIO',
html: '<p>It works.</p>',
})
if (error) console.error(error.name, error.message)
else console.log(data.id)Ou avec fetch :
const res = await fetch('https://api.honkio.ca/v1/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HONKIO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'Acme <onboarding@test.honkio.ca>',
to: 'delivered@test.honkio.ca',
subject: 'Hello from HonkIO',
html: '<p>It works.</p>',
}),
})
console.log(res.status, await res.json())Ajoutez ensuite votre propre domaine, passez à une clé réelle et envoyez depuis une adresse de ce domaine.
Domaines d’envoi
Ajoutez un domaine ou un sous-domaine que vous contrôlez, puis publiez chez votre hébergeur DNS les enregistrements que renvoie l’API. Rien n’est placé sur votre domaine principal : votre propre courrier et votre enregistrement SPF restent intacts.
| Enregistrement | Type | Nom (exemple) | Objet |
|---|---|---|---|
| DKIM | TXT | honkio1._domainkey.mail.acme.ca | Signe votre courrier. Obligatoire. |
| MX | MX | send.mail.acme.ca | Chemin de retour des rebonds, sur le sous-domaine send. Obligatoire. |
| SPF | TXT | send.mail.acme.ca | Autorise le chemin de retour, sur le sous-domaine send. Obligatoire. |
| DMARC | TXT | _dmarc.mail.acme.ca | Recommandé, non vérifié. Commencez par p=none. |
curl -X POST https://api.honkio.ca/v1/email-domains \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "domain": "mail.acme.ca" }'
# Publish the returned records at your DNS host, then check them:
curl -X POST https://api.honkio.ca/v1/email-domains/DOMAIN_ID/verify \
-H "Authorization: Bearer mk_live_YOUR_KEY"
# → { "status": "verified", "verified": true, "missing": [] }
# Tracking per domain (null = the platform default):
curl -X PATCH https://api.honkio.ca/v1/email-domains/DOMAIN_ID \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "open_tracking": false, "click_tracking": null }'Un domaine est en attente tant que ses enregistrements sont introuvables, en vérification pendant leur propagation, et vérifié quand DKIM, le MX, SPF et le fournisseur de courriel concordent. Il passe à échoué quand ses enregistrements sont encore manquants après 7 jours ou que le fournisseur de courriel rejette carrément le domaine, et à temporairement échoué après une défaillance passagère du fournisseur, ou quand un domaine déjà vérifié échoue à une nouvelle vérification ; appelez verify de nouveau une fois les enregistrements corrigés. La vérification est refaite chaque jour ; si un enregistrement disparaît, le domaine a 72 heures pour se rétablir avant de cesser d’envoyer.
Appelez verify à tout moment pour vérifier sur-le-champ. La réponse nomme tout enregistrement encore manquant.
Un domaine appartient à qui prouve qu’il contrôle son DNS. Le domaine vérifié d’un autre compte ne peut pas être ajouté ; une revendication non vérifiée bloque les autres pendant 72 heures, et la réponse 409 EMAIL_DOMAIN_IN_USE indique quand elle expire.
Le suivi des ouvertures et des clics est désactivé par défaut. Activez-le par domaine avec PATCH, ou par courriel avec le champ tracking ; null rétablit la valeur par défaut de la plateforme.
Une clé API peut être restreinte à certains domaines d’envoi dès sa création. Une clé restreinte ne peut envoyer que depuis ses propres domaines, et ne peut reprogrammer ou annuler qu’un courriel envoyé depuis l’un d’eux ; l’ajout, la vérification et la gestion des domaines eux-mêmes ne sont pas touchés et restent ouverts à toute clé disposant de la permission email_domains.
Envoyer un courriel
POST /v1/emails envoie un courriel. Les noms de champs sont ceux de Resend : la plupart des requêtes existantes fonctionnent telles quelles.
| Champ | Signification |
|---|---|
| from | Expéditeur, avec un nom au besoin. Son domaine doit être un domaine d’envoi vérifié de votre compte. |
| to, cc, bcc | Une chaîne ou un tableau ; au plus 50 destinataires entre to, cc et bcc. |
| reply_to | Une chaîne ou un tableau. |
| subject, html, text | Objet de 998 caractères au plus, et au moins html ou text. Omettez les trois pour envoyer un modèle. |
| variables | Valeurs à substituer dans subject, html et text. Ignoré quand template est présent ; les variables propres à un modèle vont dans template.variables. |
| template | Envoie un modèle enregistré par identifiant ou alias, avec ses variables. |
| attachments | filename et l’un de content (base64), content_base64 ou path (une URL HTTPS). content_id intègre le fichier dans le corps. 10 Mo au total. |
| tags | Jusqu’à 10 paires name et value, chaque partie de 1 à 256 lettres, chiffres, traits de soulignement ou traits d’union. Filtrez avec GET /v1/emails?tag=name:value. Les tags sont conservés aussi longtemps que le courriel, même après la purge de l’objet et du corps; n’y mettez aucun renseignement personnel. Le champ body_purged_at d’un courriel récupéré est nul tant que ce n’est pas fait. |
| headers | En-têtes de courriel supplémentaires, envoyés tels quels. |
| scheduled_at | Une date et heure ISO 8601, de 1 minute à 30 jours à l’avance. |
| is_commercial | False par défaut. True désigne un message commercial au sens de la LCAP ; voir plus bas. |
| tracking | Ouvertures et clics pour ce courriel, qui priment sur le réglage du domaine. |
curl -X POST https://api.honkio.ca/v1/emails \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Idempotency-Key: order-1042-receipt" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme Receipts <receipts@mail.acme.ca>",
"to": ["ada@example.com"],
"reply_to": "help@acme.ca",
"subject": "Your receipt for order 1042",
"html": "<img src=\"cid:logo\"><p>Thanks for your order.</p>",
"text": "Thanks for your order.",
"tags": [{ "name": "kind", "value": "receipt" }],
"attachments": [
{ "filename": "receipt.pdf", "path": "https://files.acme.ca/r/1042.pdf" },
{ "filename": "logo.png", "content": "iVBORw0KGgo...", "content_id": "logo" }
],
"scheduled_at": "2026-10-01T13:00:00-04:00"
}'
# Move it, or cancel it (refunded), while it is still scheduled:
curl -X PATCH https://api.honkio.ca/v1/emails/EMAIL_ID -H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" -d '{ "scheduled_at": "2026-10-02T09:00:00-04:00" }'
curl -X DELETE https://api.honkio.ca/v1/emails/EMAIL_ID -H "Authorization: Bearer mk_live_YOUR_KEY"Une pièce jointe path est récupérée une seule fois à l’envoi, en HTTPS seulement, depuis une adresse publique, en 10 secondes au plus. Si elle est inaccessible, l’envoi est refusé avec EMAIL_ATTACHMENT_FETCH_FAILED et rien n’est facturé. Les pièces jointes ne sont conservées que jusqu’à l’envoi du courriel.
Un courriel programmé peut être déplacé avec PATCH ou annulé avec DELETE tant qu’il est encore programmé ; l’annulation rembourse les frais. Les pièces jointes fonctionnent aussi pour les envois programmés.
Envoyez un en-tête Idempotency-Key pour tout ce qui peut être relancé. La même clé renvoie la réponse d’origine au lieu d’envoyer, et de facturer, deux fois.
Une relance qui arrive pendant que la première requête portant cette clé est encore en cours de facturation reçoit 409 EMAIL_IDEMPOTENCY_IN_PROGRESS. Réessayez la même clé sous peu plutôt que d’en changer.
Envois groupés
Envoyez un tableau JSON d’au plus 100 courriels indépendants. Chaque élément est vérifié avant tout envoi ; un élément invalide fait échouer tout l’appel, tandis qu’un refus de conformité, comme une adresse supprimée, ne rejette que cet élément et est listé avec son indice.
curl -X POST https://api.honkio.ca/v1/emails/batch \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '[
{ "from": "noreply@mail.acme.ca", "to": "ada@example.com", "subject": "Your code", "text": "123456" },
{ "from": "noreply@mail.acme.ca", "to": "lin@example.com", "template": { "id": "welcome", "variables": { "first_name": "Lin" } } }
]'
# → 200 { "data": [{ "id": "cm..." }, { "id": "cm..." }], "batch_id": "...", "rejected": [] }data ne liste que les courriels réellement envoyés ; il n’est donc pas aligné avec votre requête par position. Faites correspondre un rejet à son élément d’origine grâce au champ index de rejected.
Ou envoyez un même message à au plus 500 destinataires, sous forme d’objet avec une liste recipients, chacun avec ses propres variables. Les pièces jointes et la programmation par élément ne sont pas offertes en envoi groupé.
curl -X POST https://api.honkio.ca/v1/emails/batch \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "noreply@mail.acme.ca",
"template": { "id": "shipping-update" },
"recipients": [
{ "to": "ada@example.com", "variables": { "first_name": "Ada", "tracking": "1Z999" } },
{ "to": "lin@example.com", "variables": { "first_name": "Lin", "tracking": "1Z998" } }
]
}'Modèles
Les modèles utilisent des doubles accolades autour d’un nom de variable fait de lettres, de chiffres et de traits de soulignement. Les triples accolades sont acceptées et traitées de la même façon : les valeurs sont toujours échappées en HTML dans html. Il n’y a ni conditions ni boucles.
Subject: Your order has shipped, {{ first_name }}
<p>Hi {{ first_name }}, track it with {{ tracking }}.</p>
"variables": [
{ "key": "first_name", "fallback": "there" },
{ "key": "tracking" }
]Chaque variable qu’utilise un modèle doit être déclarée, avec une valeur de repli au besoin. Un envoi qui laisse une variable sans valeur ni repli est refusé et liste les clés manquantes.
Les modifications sont enregistrées dans un brouillon. La publication fait du brouillon la version numérotée suivante, que les envois utilisent ensuite ; un retour arrière republie une ancienne version comme nouvelle version. Les courriels programmés gardent leur version. Envoyez par identifiant ou alias ; un from ou reply_to dans la requête prime sur celui du modèle.
# Create a draft, publish it as version 1, send it by alias
curl -X POST https://api.honkio.ca/v1/email-templates -H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Shipping update", "alias": "shipping-update", "subject": "Shipped, {{ first_name }}",
"html": "<p>Track it with {{ tracking }}.</p>",
"variables": [{ "key": "first_name", "fallback": "there" }, { "key": "tracking" }] }'
curl -X POST https://api.honkio.ca/v1/email-templates/shipping-update/publish -H "Authorization: Bearer mk_live_YOUR_KEY"
curl -X POST https://api.honkio.ca/v1/emails -H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "from": "noreply@mail.acme.ca", "to": "ada@example.com",
"template": { "id": "shipping-update", "variables": { "tracking": "1Z999" } } }'
# Roll back: copies version 1 into the draft and publishes it as a new version
curl -X POST https://api.honkio.ca/v1/email-templates/shipping-update/rollback -H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" -d '{ "version": 1 }'Mode test
Les clés de test n’envoient rien et ne facturent rien, mais font les mêmes vérifications et déclenchent les mêmes webhooks qu’une clé réelle. Envoyez depuis onboarding@test.honkio.ca, sans domaine, vers ces adresses :
| Adresse | Résultat |
|---|---|
| delivered@test.honkio.ca | Livré. |
| bounced@test.honkio.ca | Rebond définitif ; l’adresse est ajoutée à vos suppressions. |
| complained@test.honkio.ca | Livré, puis une plainte pour pourriel ; l’adresse est ajoutée à vos suppressions et désabonnée. |
| delayed@test.honkio.ca | Un retard de livraison, puis livré. |
| *@test.honkio.ca | Toute autre adresse, et tout destinataire ordinaire avec une clé de test, est livré. |
L’issue spéciale est lue dans to seulement : la première adresse to qui correspond à l’un de ces noms locaux la détermine. cc et bcc ne sont jamais examinées, si bien que les destinataires qui s’y trouvent sont toujours livrés.
La suppression fonctionne comme en réel : un second envoi à bounced@test.honkio.ca est refusé avec EMAIL_SUPPRESSED. Ajoutez une étiquette, par exemple bounced+2@test.honkio.ca, pour obtenir une nouvelle adresse. Une clé réelle ne peut pas du tout envoyer à test.honkio.ca ; c’est refusé avec EMAIL_TEST_ADDRESS_LIVE_KEY.
Les courriels et les événements de webhook d’une clé de test portent livemode à false.
LCAP et courriel commercial
Le courriel est transactionnel par défaut : reçus, réinitialisations de mot de passe, alertes et avis de compte. Le courriel transactionnel n’exige aucun consentement enregistré.
Mettez is_commercial à true pour tout ce qui fait la promotion d’un produit ou d’un service. Un courriel commercial va à un seul destinataire, exige un consentement LCAP enregistré pour cette adresse, et porte un pied de page de désabonnement et un en-tête de désabonnement en un clic que les logiciels de courriel respectent. Enregistrez le consentement comme pour les SMS, avec email_address au lieu de phone_number.
Tout courriel de marketing doit définir is_commercial à true. Le champ vaut false par défaut, et un envoi transactionnel atteint aussi les personnes qui se sont désabonnées : un courriel promotionnel envoyé sans ce drapeau contournerait leur désabonnement et le consentement LCAP.
curl -X POST https://api.honkio.ca/v1/compliance/consents \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"email_address": "ada@example.com",
"consent_type": "express",
"source_description": "Newsletter checkbox on acme.ca/signup"
}'
# Then a commercial send to that one address:
curl -X POST https://api.honkio.ca/v1/emails -H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "from": "news@mail.acme.ca", "to": "ada@example.com", "subject": "Fall sale",
"html": "<p>20% off this week.</p>", "is_commercial": true }'DELETE /v1/compliance/consents/email/:address révoque les consentements actifs de cette adresse (exige compliance:m ou compliance:d) ; elle répond 404 NOT_FOUND si aucun n’est actif. Les désabonnements et les suppressions sont distincts et ne sont pas touchés.
Ceci décrit comment l’API applique la LCAP ; ce n’est pas un avis juridique sur vos propres messages.
Suppressions
Les rebonds définitifs et les plaintes pour pourriel ajoutent automatiquement l’adresse à votre liste de suppression, et plus aucun courriel ne lui est envoyé. Un désabonnement l’ajoute aussi, mais bloque seulement les courriels commerciaux : les reçus, les réinitialisations de mot de passe et les autres courriels transactionnels continuent d’arriver. Une adresse que vous bloquez vous-même ne reçoit plus aucun courriel. Vous pouvez lister les suppressions, ou en retirer une lorsque la personne demande à recevoir de vos nouvelles.
curl "https://api.honkio.ca/v1/email-suppressions?reason=hard_bounce" -H "Authorization: Bearer mk_live_YOUR_KEY"
curl -X POST https://api.honkio.ca/v1/email-suppressions -H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" -d '{ "email_address": "ada@example.com", "reason": "manual" }'
curl -X DELETE https://api.honkio.ca/v1/email-suppressions/ada%40example.com -H "Authorization: Bearer mk_live_YOUR_KEY"Webhooks de courriel
Abonnez-vous aux événements de courriel comme aux événements SMS. Les livraisons sont signées exactement comme décrit dans Vérifier les signatures.
Chaque évènement arrive sous forme d’un seul objet JSON avec les mêmes six champs de premier niveau. Seul data change d’un évènement à l’autre.
| Champ | Signification |
|---|---|
| id | L’identifiant de l’évènement, un UUID. Il est le même à chaque tentative et à chaque rejeu de cet évènement : conservez-le et ignorez tout id déjà traité. |
| type | Le nom de l’évènement, par exemple message.received. La même valeur est envoyée dans l’en-tête X-HonkIO-Event. |
| created | Le moment de l’évènement, en ISO 8601 UTC avec millisecondes. Une nouvelle tentative ou un rejeu garde la valeur d’origine. |
| account_id | Le compte HonkIO auquel appartient l’évènement. |
| livemode | true quand l’action d’une clé réelle a causé l’évènement, false pour une simulation avec une clé de test. Les évènements de compte et de numéro de téléphone valent toujours true. |
| data | Les champs propres à l’évènement, décrits sous chaque évènement ci-dessous. |
email.queued
Un courriel a été accepté et facturé, et il est en file, ou planifié si vous avez passé scheduled_at.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.queued",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
],
"subject": "Your receipt",
"tags": [
{
"name": "category",
"value": "receipt"
}
],
"status": "queued",
"is_commercial": false
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| email.subject | La ligne d’objet. |
| email.tags | Les étiquettes posées sur le courriel, sous forme de liste de paires name et value ; vide s’il n’y en a pas. |
| email.status | queued, ou scheduled quand le courriel attend scheduled_at. Absent pour les courriels envoyés en lot. |
| email.batch_id | Courriels envoyés avec POST /v1/emails/batch seulement : le lot auquel appartient le courriel. |
| email.is_commercial | Si vous avez marqué le courriel comme commercial (LCAP), ce qui décide du pied de page et de l’en-tête de désabonnement. |
email.sent
Le fournisseur de courriel a accepté le message pour livraison.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.sent",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
],
"subject": "Your receipt",
"tags": []
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| email.ses_message_id | L’identifiant du message chez le fournisseur de courriel, pour les demandes de soutien. Présent sur les évènements que le fournisseur signale. |
| email.subject | La ligne d’objet. |
| email.tags | Les étiquettes posées sur le courriel, sous forme de liste de paires name et value ; vide s’il n’y en a pas. |
email.delivered
Le serveur de courriel du destinataire a accepté le message.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.delivered",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"to": [
"ada@example.com"
],
"from": "receipts@mail.acme.ca",
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000",
"tags": [
{
"name": "category",
"value": "receipt"
}
]
},
"details": {
"delivered_at": "2026-10-01T17:00:03.512Z",
"smtp_response": "250 2.0.0 OK",
"processing_time_ms": 1204,
"recipients": [
"ada@example.com"
],
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| email.from | L’adresse d’expédition du courriel. |
| email.ses_message_id | L’identifiant du message chez le fournisseur de courriel, pour les demandes de soutien. Présent sur les évènements que le fournisseur signale. |
| email.tags | Les étiquettes posées sur le courriel, sous forme de liste de paires name et value ; vide s’il n’y en a pas. |
| details.delivered_at | Le moment où le serveur du destinataire a accepté le message, en ISO 8601 UTC. |
| details.smtp_response | La réponse SMTP du serveur du destinataire, telle quelle. |
| details.processing_time_ms | La durée de la livraison depuis l’acceptation, en millisecondes. |
| details.recipients | Les adresses de destinataires visées par ce rapport. |
| details.ses_message_id | Le même identifiant de fournisseur que email.ses_message_id. |
email.delivery_delayed
Le serveur du destinataire diffère le message ; la livraison est encore retentée. Plusieurs peuvent arriver pour un même courriel.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.delivery_delayed",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"to": [
"ada@example.com"
],
"from": "receipts@mail.acme.ca",
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000",
"tags": [
{
"name": "category",
"value": "receipt"
}
]
},
"details": {
"delay_type": "MailboxFull",
"expiration_time": "2026-10-02T17:00:00.000Z",
"recipients": [
{
"email_address": "ada@example.com",
"status": "4.2.2",
"diagnostic_code": "smtp; 452 4.2.2 Mailbox full"
}
],
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| email.from | L’adresse d’expédition du courriel. |
| email.ses_message_id | L’identifiant du message chez le fournisseur de courriel, pour les demandes de soutien. Présent sur les évènements que le fournisseur signale. |
| email.tags | Les étiquettes posées sur le courriel, sous forme de liste de paires name et value ; vide s’il n’y en a pas. |
| details.delay_type | Le type de retard signalé par le fournisseur, par exemple MailboxFull, SpamDetected ou TransientCommunicationFailure. |
| details.expiration_time | Le moment où le fournisseur cessera de réessayer et fera rebondir le message, en ISO 8601 UTC. |
| details.recipients | Les destinataires dont la livraison est retardée, un objet chacun. |
| details.recipients[].email_address | L’adresse d’un destinataire retardé. |
| details.recipients[].status | Le code de statut SMTP pour ce destinataire. |
| details.recipients[].diagnostic_code | L’explication du serveur du destinataire, quand il en donne une. |
| details.ses_message_id | Le même identifiant de fournisseur que email.ses_message_id. |
email.bounced
Le message a rebondi. Un rebond permanent supprime l’adresse ; un rebond temporaire, non.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.bounced",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"to": [
"ada@example.com"
],
"from": "receipts@mail.acme.ca",
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000",
"tags": [
{
"name": "category",
"value": "receipt"
}
]
},
"details": {
"bounce_type": "Permanent",
"bounce_subtype": "General",
"diagnostic_code": "smtp; 550 5.1.1 user unknown",
"suppressed": true,
"transient": false,
"recipients": [
"ada@example.com"
],
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| email.from | L’adresse d’expédition du courriel. |
| email.ses_message_id | L’identifiant du message chez le fournisseur de courriel, pour les demandes de soutien. Présent sur les évènements que le fournisseur signale. |
| email.tags | Les étiquettes posées sur le courriel, sous forme de liste de paires name et value ; vide s’il n’y en a pas. |
| details.bounce_type | Permanent, Transient ou Undetermined. |
| details.bounce_subtype | La classification plus fine du fournisseur, par exemple General, NoEmail ou MailboxFull. |
| details.diagnostic_code | L’explication du serveur du destinataire pour le premier destinataire rebondi, quand il en donne une. |
| details.suppressed | true quand l’adresse a été ajoutée à votre liste de suppression (tout rebond permanent). |
| details.transient | true pour un rebond temporaire, qui ne supprime pas l’adresse. |
| details.recipients | Les adresses de destinataires visées par ce rapport. |
| details.ses_message_id | Le même identifiant de fournisseur que email.ses_message_id. |
email.complained
Un destinataire a signalé le message comme pourriel. L’adresse est supprimée et enregistrée comme désabonnement.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.complained",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"to": [
"ada@example.com"
],
"from": "receipts@mail.acme.ca",
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000",
"tags": [
{
"name": "category",
"value": "receipt"
}
]
},
"details": {
"complained_at": "2026-10-01T18:12:00.000Z",
"recipients": [
"ada@example.com"
],
"ses_message_id": "0101019xxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-000000"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| email.from | L’adresse d’expédition du courriel. |
| email.ses_message_id | L’identifiant du message chez le fournisseur de courriel, pour les demandes de soutien. Présent sur les évènements que le fournisseur signale. |
| email.tags | Les étiquettes posées sur le courriel, sous forme de liste de paires name et value ; vide s’il n’y en a pas. |
| details.complained_at | Le moment de la plainte, en ISO 8601 UTC. |
| details.recipients | Les adresses de destinataires visées par ce rapport. |
| details.ses_message_id | Le même identifiant de fournisseur que email.ses_message_id. |
email.rejected
Le message a été refusé avant ou pendant l’envoi, par les vérifications de HonkIO ou par le fournisseur de courriel, et les frais sont remboursés. Un refus de nos vérifications porte failure_code et failure_message ; un refus signalé par le fournisseur porte reason.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.rejected",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
]
},
"details": {
"failure_code": "DOMAIN_NOT_VERIFIED",
"failure_message": "The sending domain is not verified."
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| details.failure_code | Le code HonkIO qui explique le refus ou l’échec du courriel. |
| details.failure_message | Une explication lisible de failure_code. |
| details.reason | Refus signalés par le fournisseur de courriel seulement (à la place de failure_code) : la raison du fournisseur. |
| email.ses_message_id | L’identifiant du message chez le fournisseur de courriel, pour les demandes de soutien. Présent sur les évènements que le fournisseur signale. |
email.failed
Le courriel n’a pas pu être envoyé pour une raison qui ne tient pas au destinataire, comme une erreur de facturation ou du fournisseur, et les frais sont remboursés.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.failed",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
]
},
"details": {
"failure_code": "SES_ERROR",
"failure_message": "The provider did not accept the message."
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| details.failure_code | Le code HonkIO qui explique le refus ou l’échec du courriel. |
| details.failure_message | Une explication lisible de failure_code. |
email.opened
La première ouverture du courriel : le pixel de suivi s’est chargé. Seulement quand le suivi des ouvertures est activé ; certains logiciels chargent les images automatiquement, une ouverture est donc un indice, pas une preuve. Les ouvertures suivantes ne déclenchent aucun webhook.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.opened",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
]
},
"details": {
"ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| details.ua | L’agent utilisateur qui a chargé le pixel ou suivi le lien, ou null. |
email.clicked
Le premier clic sur un lien suivi du courriel, quand le suivi des clics est activé. Les clics suivants ne déclenchent aucun webhook.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.clicked",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
]
},
"details": {
"url": "https://acme.ca/orders/1042",
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5)"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| details.url | Le lien suivi, tel qu’écrit dans votre courriel. |
| details.ua | L’agent utilisateur qui a chargé le pixel ou suivi le lien, ou null. |
email.unsubscribed
Un destinataire d’un courriel commercial s’est désabonné par son lien ou son en-tête, et il est maintenant supprimé pour ce domaine d’envoi.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.unsubscribed",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
]
},
"details": {
"recipient": "ada@example.com",
"from_domain": "mail.acme.ca"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| details.recipient | L’adresse qui s’est désabonnée. |
| details.from_domain | Le domaine d’envoi pour lequel l’adresse est maintenant supprimée. |
email.cancelled
Un courriel planifié a été annulé avant son envoi, et les frais ont été remboursés.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.cancelled",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
]
},
"details": {
"cancelled_at": "2026-10-01T16:58:00.000Z"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| details.cancelled_at | Le moment de l’annulation, en ISO 8601 UTC. |
email.rescheduled
Un courriel planifié a été déplacé à une nouvelle heure.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email.rescheduled",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"email": {
"id": "clxxxemailxxxxxxxxxxxxxxx",
"from": "receipts@mail.acme.ca",
"to": [
"ada@example.com"
],
"tags": []
},
"details": {
"previous_scheduled_at": "2026-10-02T13:00:00.000Z",
"scheduled_at": "2026-10-03T13:00:00.000Z"
}
}
}| Champ de data | Signification |
|---|---|
| email.id | L’identifiant HonkIO du courriel, tel que renvoyé par POST /v1/emails. |
| email.from | L’adresse d’expédition du courriel. |
| email.to | Les adresses des destinataires, sous forme de liste. |
| email.tags | Les étiquettes posées sur le courriel, sous forme de liste de paires name et value ; vide s’il n’y en a pas. |
| details.previous_scheduled_at | L’heure planifiée précédente, en ISO 8601 UTC. |
| details.scheduled_at | La nouvelle heure, en ISO 8601 UTC. |
email_domain.verified
Les enregistrements DNS d’un domaine d’envoi sont validés et il peut envoyer.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email_domain.verified",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"domain": {
"id": "clxxxdomainxxxxxxxxxxxxxx",
"domain": "mail.acme.ca",
"region": "ca-central-1"
}
}
}| Champ de data | Signification |
|---|---|
| domain.id | L’identifiant HonkIO du domaine de courriel. |
| domain.domain | Le nom de domaine. |
| domain.region | La région d’où le domaine envoie (ca-central-1). |
email_domain.verification_failed
Un domaine d’envoi a échoué la vérification, ou l’a perdue lors d’une vérification ultérieure de ses enregistrements.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "email_domain.verification_failed",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"domain": {
"id": "clxxxdomainxxxxxxxxxxxxxx",
"domain": "mail.acme.ca",
"status": "temporarily_failed"
},
"details": {
"failure_reason": "DKIM records not found",
"revalidation": true
}
}
}| Champ de data | Signification |
|---|---|
| domain.id | L’identifiant HonkIO du domaine de courriel. |
| domain.domain | Le nom de domaine. |
| domain.status | failed quand un autre compte a depuis vérifié le même domaine, temporarily_failed quand une nouvelle vérification d’un domaine déjà vérifié a échoué ; absent quand une première vérification a échoué. |
| details.failure_reason | Pourquoi la vérification a échoué, par exemple quels enregistrements sont introuvables. |
| details.revalidation | true quand il s’agissait d’une nouvelle vérification d’un domaine déjà vérifié. Absent sinon. |
Chaque événement porte livemode : true pour une clé réelle, false pour une clé de test.
Pause automatique
Tous les courriels partent sous une même réputation d’envoi : un compte dont les courriels réels récents rebondissent ou suscitent des plaintes à un taux élevé voit son envoi réel de courriels suspendu 24 heures. Aujourd’hui, c’est plus de 5 % de rebonds définitifs sur ses 200 derniers courriels réels (dès qu’il en a envoyé au moins 50), ou plus de 0,1 % de plaintes sur ses 1 000 derniers, avec au moins 2 plaintes : une seule plainte ne suspend jamais. Pendant la pause, les envois réels répondent 403 SENDING_PAUSED avec channel email, les courriels programmés attendent et partent après la pause, et les SMS et les clés de test ne sont pas touchés. Nous pouvons modifier ces seuils pour protéger la délivrabilité ; cette page indique les seuils en vigueur.
La pause émet account.sending_paused avec { channel: "email", paused_until, reason, bounce_rate_pct ou complaint_rate_pct }, et le titulaire du compte est avisé par courriel.
Erreurs de courriel
Les appels de courriel peuvent aussi répondre avec les codes généraux du tableau d’erreurs principal, comme VALIDATION_ERROR, INSUFFICIENT_BALANCE et NOT_FOUND.
| HTTP | Code | Signification |
|---|---|---|
| 403 | EMAIL_DOMAIN_NOT_ALLOWED | La clé API est restreinte à certains domaines d’envoi, et celui-ci n’en fait pas partie. |
| 409 | EMAIL_DOMAIN_ALREADY_EXISTS | Le domaine est déjà sur ce compte. |
| 409 | EMAIL_DOMAIN_IN_USE | Un autre compte détient ce domaine. details.retry_after indique quand une revendication non vérifiée expire ; un domaine vérifié reste à son propriétaire. |
| 409 | EMAIL_DOMAIN_HAS_INFLIGHT | Le domaine a encore des courriels en file, programmés ou en cours d’envoi. |
| 409 | EMAIL_IDEMPOTENCY_IN_PROGRESS | Une requête utilisant cette clé Idempotency-Key est encore en cours de traitement. Réessayez la même clé sous peu plutôt que d’en utiliser une nouvelle. |
| 409 | EMAIL_TEMPLATE_ALIAS_TAKEN | Un autre modèle de ce compte utilise déjà cet alias. |
| 409 | EMAIL_TEMPLATE_IN_USE | Un courriel programmé utilise ce modèle. Annulez-le, ou attendez qu’il soit envoyé, puis supprimez le modèle. |
| 413 | EMAIL_ATTACHMENT_TOO_LARGE | Les pièces jointes dépassent 10 Mo. |
| 422 | EMAIL_INVALID_ADDRESS | Une adresse n’est pas une adresse courriel valide. |
| 422 | EMAIL_DOMAIN_NOT_VERIFIED | Le domaine de l’expéditeur n’est pas un domaine d’envoi vérifié de ce compte. |
| 422 | EMAIL_DOMAIN_INVALID | Nom de domaine invalide. |
| 422 | EMAIL_TEST_ADDRESS_LIVE_KEY | Une clé réelle ne peut pas envoyer à une adresse sur test.honkio.ca ; ces adresses sont réservées aux clés de test. |
| 422 | EMAIL_HEADER_INVALID | L’adresse d’expéditeur ou un en-tête est mal formé, ou est un en-tête que honkio définit lui-même. |
| 422 | EMAIL_ATTACHMENT_FETCH_FAILED | Une pièce jointe fournie par path n’a pas pu être récupérée. details.reason indique pourquoi : blocked_address, http_status, timeout, too_large ou network. |
| 422 | EMAIL_RENDER_FAILED | Le contenu n’a pas pu être généré. |
| 422 | EMAIL_BATCH_TOO_LARGE | Trop de destinataires dans un seul appel. |
| 422 | EMAIL_COMMERCIAL_MULTI_RECIPIENT | Un courriel commercial va à un seul destinataire. Utilisez un envoi groupé pour en joindre plusieurs. |
| 422 | EMAIL_NOT_SCHEDULED | Seul un courriel programmé peut être déplacé ou annulé. |
| 422 | EMAIL_TEMPLATE_NOT_PUBLISHED | Le modèle n’a pas encore de version publiée. Publiez-le avant de l’utiliser pour un envoi. |
| 422 | EMAIL_TEMPLATE_VARIABLE_MISSING | Une variable du modèle n’a ni valeur ni valeur de repli. details.keys énumère celles qui manquent. |
| 422 | EMAIL_TEMPLATE_UNDECLARED_VARIABLE | Le corps du modèle utilise une variable qu’il ne déclare pas. Ajoutez-la à variables ; details.keys les énumère. |
| 422 | EMAIL_TEMPLATE_LIMIT_REACHED | Ce compte a atteint la limite de 200 modèles de courriel. Supprimez-en un pour en créer un autre. |
| 451 | EMAIL_SUPPRESSED | Le destinataire figure sur votre liste de suppression. |
| 451 | EMAIL_NO_CONSENT | Le courriel commercial exige un consentement LCAP enregistré pour le destinataire. |
| 451 | EMAIL_OPT_OUT_BLOCKED | Le destinataire s’est désabonné de cet expéditeur. |
| 503 | EMAIL_ATTACHMENTS_UNCONFIGURED | Le stockage des pièces jointes n’est pas configuré, donc les courriels avec pièces jointes ne peuvent pas être envoyés pour le moment. |
Codes d’échec de livraison
Ces codes ne sont jamais une réponse HTTP : l’appel a déjà répondu 201 avant que SES tente l’envoi. Si la livraison échoue quand même, l’un d’eux apparaît comme failure_code sur le webhook email.failed ou email.rejected, et les frais sont remboursés.
| Code | Signification |
|---|---|
| SES_THROTTLING | SES a limité le débit d’envoi ; le courriel a échoué et a été remboursé ; renvoyez-le. |
| SES_MESSAGE_REJECTED | SES a rejeté le message d’emblée, par exemple un contenu mal formé ; le courriel a échoué et a été remboursé ; corrigez le contenu et renvoyez-le. |
| SES_DOMAIN_NOT_VERIFIED | SES n’avait pas terminé de vérifier le domaine d’expéditeur, même si la vérification de honkio avait réussi ; le courriel a échoué et a été remboursé ; attendez la fin de la vérification, puis renvoyez-le. |
| SES_ERROR | Une erreur SES qui ne correspond à aucun autre code ; le courriel a échoué et a été remboursé ; renvoyez-le. |
| EMAIL_ATTACHMENTS_UNAVAILABLE | Les octets de la pièce jointe stockée n’ont pas pu être lus au moment de l’envoi ; le courriel a échoué et a été remboursé ; renvoyez-le. |
Migrer depuis Resend
Pour la plupart des intégrations, changez l’URL de base et la clé. Avec le SDK, importez Honkio depuis @honkio/node au lieu de Resend.
| Resend | HonkIO | Remarques |
|---|---|---|
| https://api.resend.com | https://api.honkio.ca/v1 | Les clés commencent par mk_live_ ou mk_test_. |
| from, to, cc, bcc, reply_to | identique | Au plus 50 destinataires par appel. |
| subject, html, text, headers | identique | |
| attachments[].content / path / filename / content_type / content_id | identique | content_base64 est accepté comme synonyme de content. |
| tags [{ name, value }] | identique | |
| scheduled_at | scheduled_at | ISO 8601 seulement. |
| template { id, variables } | identique | Les modèles sont stockés dans HonkIO ; les triples accolades sont échappées. |
| POST /emails/batch | POST /v1/emails/batch | Tableau d’au plus 100, ou l’objet modèle pour au plus 500. |
| Idempotency-Key | identique | |
| react | non offert | Générez d’abord votre courriel React en HTML. |
| audiences, broadcasts, inbound | non offert |
Différences connues
- scheduled_at prend une date et heure ISO 8601. Le langage naturel, comme in 1 hour, est refusé.
- Les variables à triples accolades sont échappées en HTML, comme les doubles.
- Le courriel commercial suit la LCAP : consentement enregistré, un seul destinataire, pied de page de désabonnement.
- Les réponses gardent les champs propres à HonkIO, comme status, livemode et cost_cents, en plus de l’id que lisent les clients Resend.
- Un envoi simple joint au plus 50 destinataires entre to, cc et bcc.
HonkIO