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
¿Puedo enviar? — la única llamada
GET /api/v1/me responde. Varias protecciones distintas pueden rechazar un envío, y hasta ahora lo rechazaban sin decir cuál: este bloque las nombra.
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"
}
}
}
}Códigos de bloqueo
Son estables y nunca se traducen: es una interfaz para máquinas. Construye tu remediación sobre ellos, no sobre un mensaje.| Código | Qué significa | Cómo resolverlo |
|---|---|---|
sending_disabled | El envío está desactivado en toda la aplicación | No puedes hacer nada desde la API |
organization_not_allowed | La organización no está en la lista de envío autorizada | Pide al operador que la autorice |
sending_paused | El proveedor de correo suspendió el envío para esta organización | Nada desde la API: consulta más abajo |
domain_not_verified | Hay un dominio declarado, pero su DKIM no está en SUCCESS | Publica los registros DNS y luego verify |
domain_ownership_unproven | DKIM está en SUCCESS, pero esta organización no ha probado que es la propietaria del dominio | Publica el TXT _agentmail-challenge y luego verify |
sender_not_on_verified_domain | Hay un dominio verificado, pero la dirección de remitente por defecto no está en él (ni en uno de sus subdominios) | Promueve o define una dirección en el dominio verificado |
no_sender_identity | La libreta de remitentes no tiene dirección por defecto; solo se indica junto a un bloqueo real | Añade una dirección (POST /api/v1/settings/identities) |
sending_paused no es algo que puedas reintentar. Aparece cuando el proveedor de correo suspende la organización, por reputación, normalmente por una tasa de rebotes o de quejas. Todo envío a tus contactos se rechaza mientras está presente: campañas, secuencias, confirmaciones de opt-in. El envío de prueba de una campaña sigue disponible, así que puedes seguir comprobando cómo se ve una campaña mientras resuelves la suspensión: sale con la dirección de la aplicación, no con la tuya. El bloqueo desaparece solo cuando el proveedor vuelve a habilitar el envío, y nunca desde la API. Corrige lo que lo causó —limpia tus listas, deja de importar contactos fríos— y habla con el operador.no_sender_identity por sí solo no es un bloqueo. Sin ninguna identidad de envío definida, los correos siguen saliendo con la dirección de la aplicación. Solo aparece cuando otra cosa ya está bloqueando, para decirte que la cuenta está vacía.sender_not_on_verified_domain es un bloqueo real, y te toca resolverlo a ti. Un dominio verificado solo te permite enviar desde ese dominio: con codemail.io verificado, hello@codemail.io y news@news.codemail.io salen, hello@example.org no. Sin esta comprobación, el proveedor aceptaría el lote y luego fallaría cada mensaje con "Email address is not verified", sin que nada en el producto te dijera por qué. Solo aparece una vez que hay al menos un dominio verificado: antes de eso, define la dirección de remitente libremente.Estado de la configuración
sending.setup es el mismo estado que el propietario de la cuenta lee en pantalla, como un solo código en lugar de una lista. Es puramente informativo: nunca entra en blockers y nunca cambia ready. Condiciona tus envíos a ready, y usa setup.status para decir en qué punto está la cuenta en una palabra.
status se deriva, gana la primera coincidencia, en este orden:
status | Cuándo | Qué hacer |
|---|---|---|
suspended | El proveedor de correo suspendió el envío para esta organización | Nada desde la API: consulta el aviso |
sending_disabled | El envío está desactivado en toda la aplicación | Esperar: no puedes hacer nada desde la API |
not_allowed | La organización no está en la lista de envío autorizada | Pide al operador que la autorice |
verification_failed | El envío está bloqueado por los dominios, y uno de ellos falló la verificación DKIM | Revisa los registros DNS y luego verify |
dns_pending | El envío está bloqueado por los dominios por cualquier otro motivo, incluido no haber declarado ninguno | Declara un dominio, publica el DNS, verify |
ownership_pending | DKIM tuvo éxito, pero la propiedad del dominio aún no está probada | Publica el TXT de desafío y luego verify |
sender_mismatch | Hay un dominio verificado, pero la dirección de remitente por defecto no está en él | PATCH /api/v1/settings/sending |
incomplete | Nada bloquea, pero el aislamiento de envío no está del todo en marcha | Nada: el operador lo reintenta |
active | Nada bloquea, y el aislamiento está en marcha | Envía |
provisioning es el estado bruto del aislamiento: none, provisioned o incomplete. none no es un fallo: simplemente significa que todavía no se ha intentado nada, y no impide un envío.
Una organización que no está autorizada a enviar nunca lee
active. Ese es todo el sentido del orden: una luz verde para un envío que el servicio rechazaría es peor que ninguna luz. Un dominio verificado no hace que una cuenta esté autorizada, y setup.status lo dice.blockers está vacío, ready es true y setup.status es active: la cuenta envía sin problema. verification_failed solo aparece cuando el fallo realmente bloquea.
Leerlo todo de una vez
GET /api/v1/settings devuelve todo el estado en una sola llamada.
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 es aquí exactamente el mismo objeto que GET /api/v1/me devuelve bajo sending, setup incluido: una pregunta, una respuesta, dos sitios donde leerla.
effectiveSender es lo que realmente saldrá, alternativa incluida: eso es lo que quieres comprobar, no la columna.
Identidad de envío
Una organización mantiene una libreta de remitentes: una dirección por dominio verificado, y exactamente una de ellas marcada por defecto. La dirección por defecto firma todo lo que no nombra su propia dirección: secuencias, confirmaciones de suscripción y todas las campañas que omitieronsendingIdentityId. Una campaña puede nombrar una de las otras direcciones —consulta POST /api/v1/campaigns— y entonces esa dirección la firma, sea cual sea la dirección por defecto después.
senderEmail y senderName en GET /api/v1/settings describen la dirección por defecto. El contrato no ha cambiado: léelos exactamente como antes. La libreta completa está en GET /api/v1/settings/identities.Leer y escribir la dirección por defecto — sin cambios
PATCH /api/v1/settings/sending: requiere el rol admin.
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 se borra y vuelve a la dirección de la aplicación. Sin esa distinción, definir solo el nombre visible borraría la dirección de remitente.
Este endpoint actúa sobre la dirección por defecto, y solo sobre ella:
| Cuerpo | Efecto |
|---|---|
senderEmail (no nulo) | Define la dirección por defecto; la identidad se crea si la libreta está vacía |
senderEmail: null | Quita la dirección por defecto de la libreta; el envío vuelve a la dirección de la aplicación |
senderName solo | Renombra la dirección por defecto. Se rechaza con 400 cuando no hay dirección por defecto: un nombre visible no tiene dónde vivir sin una dirección |
postalAddress | Se queda en la organización: una mención legal, no un atributo del remitente |
senderEmail: null se rechaza cuando la libreta contiene más de una dirección. Quitar la dirección por defecto mientras quedan alternativas dejaría la cuenta con una libreta llena y nada que firme. Promueve primero otra dirección, con PATCH /api/v1/settings/identities/{identityId}.La libreta de direcciones
| Endpoint | Rol | Qué hace |
|---|---|---|
GET /api/v1/settings/identities | member | Toda la libreta, la dirección por defecto primero |
POST /api/v1/settings/identities | admin | Añade una dirección: {senderEmail, senderName?, isDefault?} |
PATCH /api/v1/settings/identities/{identityId} | admin | Cambia la dirección o el nombre visible, o la promueve con {"isDefault": true} |
DELETE /api/v1/settings/identities/{identityId} | admin | Quita una dirección de la libreta |
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"
}
}La dirección por defecto no se puede eliminar mientras queden otras direcciones, y
{"isDefault": false} se rechaza. Ambos responden 400 nombrando la dirección. Promover en silencio a una superviviente cambiaría el remitente de cada campaña programada, cada secuencia en curso y cada confirmación de opt-in, sin que nadie lo haya pedido. Promueve primero otra dirección y luego elimina.Eliminar la última dirección está permitido: el envío vuelve entonces a la dirección de la aplicación, y no_sender_identity lo indica.Tampoco se puede eliminar una dirección nombrada por una campaña, sea cual sea el estado de esa campaña, borrador y ya enviada incluidos. El rechazo es un
400 que nombra las campañas. La alternativa sería un envío masivo programado que cambia de remitente en silencio, que es precisamente lo que este producto se niega a hacer. Apunta esas campañas a otra dirección, o de vuelta a la dirección por defecto con {"sendingIdentityId": null}, y luego elimina.Las secuencias y las confirmaciones de opt-in siempre usan la dirección por defecto. No hay remitente por secuencia: la elección solo existe en las campañas, mediante
sendingIdentityId.La dirección de remitente debe estar en un dominio verificado
Cada dirección de la libreta —no solo la dirección por defecto— debe estar en un dominio tuyo que esté verificado y probado. En cuanto la organización tiene al menos un dominio verificado,senderEmail debe estar en él, o en uno de sus subdominios. Cualquier otra cosa se rechaza con 400, nombrando ambos hechos:
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 sigue bloqueando los envíos hasta que un dominio esté verificado, y sender_not_on_verified_domain toma el relevo a partir de ahí.
Ajustes de suscripción
PATCH /api/v1/settings/optin: requiere el rol admin.
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"| Campo | Efecto |
|---|---|
required | Controla las suscripciones nuevas: true significa pending con confirmación; false significa subscribed sin confirmación. El campo heredado doubleOptIn de la API de contactos se ignora |
subject | Asunto del correo de confirmación |
content | Su HTML |
El contenido debe incluir
{{confirmationUrl}}. Sin él, el destinatario no tiene forma de confirmar, y el doble opt-in se rompe en silencio. Un contenido sin él se rechaza con 400, nombrando la variable que falta.{{confirmationUrl}} (obligatoria), {{firstName}}, {{lastName}}, {{email}}, {{postalAddress}}, {{currentYear}}. No hay variable de baja: el destinatario todavía no está suscrito.
Volver a enviar el contenido por defecto no es una personalización. Un contenido idéntico al predeterminado se guarda vacío, para que la organización siga heredando sus mejoras futuras. customized te dice en qué caso estás.
Probar el correo de confirmación
POST /api/v1/settings/optin/test-send: requiere el rol admin.
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 y el subject del cuerpo prevalecen sobre lo guardado: prueba antes de publicar. El enlace de confirmación de una prueba es falso: probar tres veces no debe poner en circulación tres tokens reales y válidos.
Una prueba es un envío real: pasa las mismas protecciones que cualquier otro. Responde {"status":"blocked"} (envío desactivado en toda la aplicación), {"status":"not_allowed"} (organización no autorizada, o dominio no verificado) o {"status":"send_refused"} (el proveedor rechazó el envío) en lugar de fallar, para que puedas distinguir un rechazo de un error, y distinguir los rechazos entre sí.