GETRead every setting/api/v1/settingsPATCHUpdate sending preferences/api/v1/settings/sendingGETRead the address book/api/v1/settings/identitiesPOSTAdd a sender address/api/v1/settings/identitiesPATCHEdit or promote an address/api/v1/settings/identities/{identityId}DELETERemove an address/api/v1/settings/identities/{identityId}PATCHUpdate sign-up settings/api/v1/settings/optinPOSTTest the confirmation email/api/v1/settings/optin/test-send
Puis-je envoyer ? — l'appel unique
GET /api/v1/me y répond. Plusieurs garde-fous distincts peuvent refuser un envoi, et jusqu'ici ils refusaient sans dire lequel : ce bloc les nomme.
bash
curl -H "x-api-key: $AGENTMAIL_API_KEY" "https://www.agentsmail.io/api/v1/me"json
{
"success": true,
"data": {
"organization": {"id": "…", "name": "Atelier Nord", "slug": "atelier-nord"},
"organizationRole": "admin",
"keyId": "…",
"sending": {
"ready": false,
"blockers": ["domain_not_verified"],
"setup": {
"status": "dns_pending",
"provisioning": "provisioned"
}
}
}
}Codes de blocage
Ils sont stables et jamais traduits — c'est une interface machine. Construisez votre remédiation sur eux, pas sur un message.| Code | Ce que cela signifie | Comment le lever |
|---|---|---|
sending_disabled | L'envoi est coupé sur toute l'application | Rien de possible depuis l'API |
organization_not_allowed | L'organisation ne figure pas sur la liste des organisations autorisées à envoyer | Demandez à l'opérateur de l'autoriser |
sending_paused | Le fournisseur d'e-mail a suspendu l'envoi pour cette organisation | Rien depuis l'API — voir ci-dessous |
domain_not_verified | Un domaine est déclaré mais son DKIM n'est pas SUCCESS | Publiez les enregistrements DNS, puis verify |
domain_ownership_unproven | Le DKIM est SUCCESS, mais cette organisation n'a pas prouvé qu'elle possède le domaine | Publiez le TXT _agentmail-challenge, puis verify |
sender_not_on_verified_domain | Un domaine est vérifié, mais l'adresse d'expéditeur par défaut n'est pas dessus (ni sur l'un de ses sous-domaines) | Promouvez ou définissez une adresse sur le domaine vérifié |
no_sender_identity | Le carnet d'adresses d'expéditeur n'a pas d'adresse par défaut — signalé uniquement en présence d'un vrai blocage | Ajoutez une adresse (POST /api/v1/settings/identities) |
sending_paused n'est pas quelque chose que vous pouvez réessayer. Il apparaît quand le fournisseur d'e-mail suspend l'organisation — pour une question de réputation, en général un taux de rebonds ou de plaintes. Tout envoi à vos contacts est refusé tant qu'il est présent : campagnes, séquences, confirmations d'opt-in. L'envoi de test de campagne reste disponible, pour que vous puissiez toujours vérifier le rendu d'une campagne pendant que vous réglez la suspension — il part sous l'adresse de l'application, pas la vôtre. Le blocage se lève tout seul quand le fournisseur réactive l'envoi, et jamais depuis l'API. Corrigez ce qui l'a provoqué — nettoyez vos listes, arrêtez d'importer des contacts froids — et parlez-en à l'opérateur.no_sender_identity seul n'est pas un blocage. Sans identité d'expéditeur définie, les e-mails partent quand même sous l'adresse de l'application. Il n'apparaît que lorsque quelque chose d'autre bloque déjà, pour vous dire que le compte est nu.sender_not_on_verified_domain est un vrai blocage, et c'est à vous de le corriger. Un domaine vérifié ne vous permet d'envoyer que depuis ce domaine : avec codemail.io vérifié, hello@codemail.io et news@news.codemail.io partent, hello@example.org non. Sans cette vérification, le fournisseur accepte le lot puis fait échouer chaque message avec « Email address is not verified » — et rien dans le produit ne vous dirait pourquoi. Il n'apparaît qu'une fois au moins un domaine vérifié : avant cela, définissez librement l'adresse d'expéditeur.Statut de configuration
sending.setup est le même état que celui que le propriétaire du compte lit à l'écran, sous forme d'un code unique au lieu d'une liste. Il est purement informatif : il n'entre jamais dans blockers et ne change jamais ready. Conditionnez vos envois à ready, et servez-vous de setup.status pour dire où en est le compte en un mot.
status est déduit, la première correspondance l'emporte, dans cet ordre :
status | Quand | Que faire |
|---|---|---|
suspended | Le fournisseur d'e-mail a suspendu l'envoi pour cette organisation | Rien depuis l'API — voir l'encadré |
sending_disabled | L'envoi est coupé sur toute l'application | Attendre — rien de possible depuis l'API |
not_allowed | L'organisation ne figure pas sur la liste des organisations autorisées à envoyer | Demandez à l'opérateur de l'autoriser |
verification_failed | L'envoi est bloqué par les domaines, et l'un d'eux a échoué à la vérification DKIM | Revérifiez les enregistrements DNS, puis verify |
dns_pending | L'envoi est bloqué par les domaines pour toute autre raison, y compris aucun domaine déclaré | Déclarez un domaine, publiez le DNS, verify |
ownership_pending | Le DKIM a réussi, mais la propriété du domaine n'est pas encore prouvée | Publiez le TXT de preuve, puis verify |
sender_mismatch | Un domaine est vérifié, mais l'adresse d'expéditeur par défaut n'est pas dessus | PATCH /api/v1/settings/sending |
incomplete | Rien ne bloque, mais l'isolation d'envoi n'est pas entièrement en place | Rien — l'opérateur relance l'opération |
active | Rien ne bloque, et l'isolation est en place | Envoyez |
provisioning est l'état brut de l'isolation — none, provisioned ou incomplete. none n'est pas une anomalie : cela signifie simplement que rien n'a encore été tenté, et cela n'empêche pas un envoi.
Une organisation qui n'est pas autorisée à envoyer ne lit jamais
active. C'est tout l'intérêt de l'ordre : un feu vert pour un envoi que le service refuserait est pire que pas de feu du tout. Un domaine vérifié ne rend pas un compte autorisé, et setup.status le dit.blockers est vide, ready vaut true, et setup.status vaut active — le compte envoie sans problème. verification_failed n'apparaît que lorsque l'échec bloque réellement.
Tout lire d'un coup
GET /api/v1/settings renvoie l'état complet en un seul appel.
json
{
"success": true,
"data": {
"sending": {
"senderEmail": "bonjour@atelier-nord.fr",
"senderName": "Atelier Nord",
"postalAddress": "12 rue des Lilas\n59000 Lille",
"effectiveSender": "Atelier Nord <bonjour@atelier-nord.fr>"
},
"optin": {
"required": true,
"subject": "Confirme ton inscription",
"content": "<div>…</div>",
"customized": false
},
"readiness": {
"ready": true,
"blockers": [],
"setup": {"status": "active", "provisioning": "provisioned"}
}
}
}readiness est ici exactement le même objet que celui renvoyé par GET /api/v1/me sous sending, setup compris — une question, une réponse, deux endroits où la lire.
effectiveSender est ce qui partira réellement, repli compris — c'est ce que vous voulez vérifier, pas la colonne.
Identité d'expéditeur
Une organisation tient un carnet d'adresses d'expéditeur : une adresse par domaine vérifié, et exactement l'une d'elles marquée par défaut. L'adresse par défaut signe tout ce qui ne nomme pas sa propre adresse : les séquences, les confirmations d'inscription, et toute campagne qui a omissendingIdentityId. Une campagne peut nommer l'une des autres adresses — voir POST /api/v1/campaigns — et c'est alors cette adresse qui la signe, quelle que soit l'adresse par défaut par la suite.
senderEmail et senderName dans GET /api/v1/settings décrivent l'adresse par défaut. Le contrat n'a pas changé : lisez-les exactement comme avant. Le carnet complet se trouve à GET /api/v1/settings/identities.Lire et écrire l'adresse par défaut — inchangé
PATCH /api/v1/settings/sending — rôle admin requis.
bash
curl -X PATCH -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"senderName":"Atelier Nord"}' \
"https://www.agentsmail.io/api/v1/settings/sending"null est effacé et revient à l'adresse de l'application. Sans cette distinction, définir seulement le nom affiché effacerait l'adresse d'expéditeur.
Cet endpoint agit sur l'adresse par défaut, et sur elle seule :
| Corps | Effet |
|---|---|
senderEmail (non nul) | Définit l'adresse par défaut — l'identité est créée si le carnet est vide |
senderEmail: null | Retire l'adresse par défaut du carnet ; l'envoi revient à l'adresse de l'application |
senderName seul | Renomme l'adresse par défaut. Refusé avec 400 quand il n'y a pas d'adresse par défaut — un nom affiché n'a nulle part où vivre sans adresse |
postalAddress | Reste sur l'organisation : une mention légale, pas un attribut de l'expéditeur |
senderEmail: null est refusé quand le carnet contient plus d'une adresse. Retirer l'adresse par défaut alors que d'autres restent laisserait le compte avec un carnet plein et rien pour signer. Promouvez d'abord une autre adresse, avec PATCH /api/v1/settings/identities/{identityId}.Le carnet d'adresses
| Endpoint | Rôle | Ce qu'il fait |
|---|---|---|
GET /api/v1/settings/identities | member | Le carnet complet, l'adresse par défaut en premier |
POST /api/v1/settings/identities | admin | Ajoute une adresse — {senderEmail, senderName?, isDefault?} |
PATCH /api/v1/settings/identities/{identityId} | admin | Change l'adresse ou le nom affiché, ou la promeut avec {"isDefault": true} |
DELETE /api/v1/settings/identities/{identityId} | admin | Retire une adresse du carnet |
bash
curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"senderEmail":"news@atelier-nord.fr","senderName":"Atelier Nord"}' \
"https://www.agentsmail.io/api/v1/settings/identities"json
{
"success": true,
"data": {
"id": "…",
"senderEmail": "news@atelier-nord.fr",
"senderName": "Atelier Nord",
"isDefault": false,
"createdAt": "2026-08-17T09:00:00.000Z"
}
}L'adresse par défaut ne peut pas être supprimée tant que d'autres adresses restent, et
{"isDefault": false} est refusé. Les deux répondent 400 en nommant l'adresse. Promouvoir en silence une adresse restante changerait l'expéditeur de chaque campagne programmée, de chaque séquence en cours et de chaque confirmation d'opt-in — sans que personne ne l'ait demandé. Promouvez d'abord une autre adresse, puis supprimez.Supprimer la dernière adresse est autorisé : l'envoi revient alors à l'adresse de l'application, et no_sender_identity le signale.Une adresse nommée par une campagne ne peut pas non plus être supprimée — quel que soit le statut de cette campagne, brouillon et déjà envoyée comprises. Le refus est un
400 qui nomme les campagnes. L'alternative serait un envoi de masse programmé qui change d'expéditeur en silence, ce que ce produit refuse précisément de faire. Pointez ces campagnes vers une autre adresse, ou de nouveau vers l'adresse par défaut avec {"sendingIdentityId": null}, puis supprimez.Les séquences et les confirmations d'opt-in prennent toujours l'adresse par défaut. Il n'y a pas d'expéditeur par séquence : le choix n'existe que sur les campagnes, via
sendingIdentityId.L'adresse d'expéditeur doit être sur un domaine vérifié
Chaque adresse du carnet — pas seulement celle par défaut — doit vivre sur l'un de vos domaines vérifié et prouvé. Dès que l'organisation a au moins un domaine vérifié,senderEmail doit être sur ce domaine, ou sur l'un de ses sous-domaines. Tout le reste est refusé avec 400, en nommant les deux faits :
bash
curl -X PATCH -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"senderEmail":"hello@example.org"}' \
"https://www.agentsmail.io/api/v1/settings/sending"json
{
"error": "Erreur de validation : Votre domaine codemail.io est vérifié — mais hello@example.org n’est pas dessus. Utilisez une adresse sur ce domaine ou sur l’un de ses sous-domaines."
}domain_not_verified bloque tout de même les envois jusqu'à ce qu'un domaine soit vérifié, et sender_not_on_verified_domain prend le relais ensuite.
Réglages d'inscription
PATCH /api/v1/settings/optin — rôle admin requis.
bash
curl -X PATCH -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"required":true,"subject":"Confirm your sign-up","content":"<p><a href=\"{{confirmationUrl}}\">Confirm</a></p>"}' \
"https://www.agentsmail.io/api/v1/settings/optin"| Champ | Effet |
|---|---|
required | Décide des nouvelles inscriptions : true signifie pending avec confirmation ; false signifie subscribed sans confirmation. L'ancien champ doubleOptIn de l'API des contacts est ignoré |
subject | Objet de l'e-mail de confirmation |
content | Son HTML |
Le contenu doit contenir
{{confirmationUrl}}. Sans elle, le destinataire n'a aucun moyen de confirmer, et le double opt-in casse en silence. Un contenu qui ne la contient pas est refusé avec 400, en nommant la variable manquante.{{confirmationUrl}} (obligatoire), {{firstName}}, {{lastName}}, {{email}}, {{postalAddress}}, {{currentYear}}. Il n'y a pas de variable de désabonnement — le destinataire n'est pas encore abonné.
Renvoyer le contenu par défaut n'est pas une personnalisation. Un contenu identique à celui par défaut est stocké vide, pour que l'organisation continue d'hériter de ses améliorations futures. customized vous dit dans quel cas vous êtes.
Tester l'e-mail de confirmation
POST /api/v1/settings/optin/test-send — rôle admin requis.
bash
curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
-d '{"email":"you@example.com","content":"<p><a href=\"{{confirmationUrl}}\">Confirm</a></p>"}' \
"https://www.agentsmail.io/api/v1/settings/optin/test-send"content et le subject du corps l'emportent sur ce qui est stocké : essayez avant de publier. Le lien de confirmation d'un test est factice — tester trois fois ne doit pas mettre en circulation trois jetons réels et valides.
Un test est un envoi réel : il passe les mêmes garde-fous que n'importe quel autre. Il répond {"status":"blocked"} (envoi coupé sur toute l'application), {"status":"not_allowed"} (organisation non autorisée, ou domaine non vérifié) ou {"status":"send_refused"} (le fournisseur a refusé l'envoi) plutôt que d'échouer, pour que vous puissiez distinguer un refus d'une erreur — et distinguer les refus entre eux.