Dominios de envío

Enviar desde tu propio dominio cuesta siete registros DNS, publicados una sola vez. El ciclo de abajo está pensado para que lo conduzca un script.

Configurar un dominio, de principio a fin

Este es el ciclo que ejecuta un agente. Nada de esto necesita a una persona.
  1. Declara el dominio.
    bash
    curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
      -d '{"domain":"atelier-nord.fr"}' \
      "https://www.agentsmail.io/api/v1/domains"
  2. Lee los registros que publicar. GET /api/v1/domains los devuelve. Siete en la práctica: un TXT para el desafío de propiedad, tres CNAME DKIM, un MX y un TXT para el MAIL FROM personalizado, y un TXT para DMARC. El registro de desafío va primero, y es el que decide el uso. Su nombre es _agentmail-challenge.<domain> y su valor es el token propio de la organización. DKIM solo no basta: una identidad ya verificada en la cuenta del proveedor devuelve SUCCESS a quien la declare, así que verified exige además esta prueba. Un nombre TXT admite varios valores: dos organizaciones que se transfieren un dominio pueden publicar lado a lado. El registro de desafío se sirve incluso cuando el proveedor no está disponible, porque su valor sale de nuestra propia base de datos.
    json
    {
      "success": true,
      "data": [
        {
          "id": "…",
          "domain": "atelier-nord.fr",
          "dkimStatus": "PENDING",
          "mailFromStatus": "PENDING",
          "verified": false,
          "ownershipProved": false,
          "lastCheckedAt": "2026-08-12T12:00:00.000Z",
          "sesUnavailable": false,
          "dnsRecords": [
            {"type": "TXT", "name": "_agentmail-challenge.atelier-nord.fr", "value": "Xy7pQ2rL9mNv4KtB1sZaWg"},
            {"type": "CNAME", "name": "abc._domainkey.atelier-nord.fr", "value": "abc.dkim.amazonses.com"},
            {"type": "MX", "name": "mail.atelier-nord.fr", "value": "feedback-smtp.eu-west-1.amazonses.com", "priority": 10},
            {"type": "TXT", "name": "mail.atelier-nord.fr", "value": "v=spf1 include:amazonses.com ~all"},
            {"type": "TXT", "name": "_dmarc.atelier-nord.fr", "value": "v=DMARC1; p=none;"}
          ]
        }
      ]
    }
  3. Publícalos en el registrador. Esa parte queda fuera de la API.
  4. Vuelve a comprobar. POST /api/v1/domains/{domainId}/verify vuelve a consultar al proveedor de correo y guarda la respuesta. Sondéalo: la propagación DNS tarda desde unos minutos hasta 72 h.
  5. Confirma. GET /api/v1/me responde ahora "ready": true.
DKIM y la propiedad condicionan el envío, juntos. mailFromStatus y el registro DMARC mejoran la entregabilidad: un MAIL FROM pendiente nunca bloquea un envío. El campo verified significa utilizable: dkimStatus === "SUCCESS" y el desafío de propiedad probado, en el mismo dominio. Lee verified y nunca tendrás que reimplementar la regla; lee ownershipProved y dkimStatus para saber cuál de los dos registros falta todavía.

La propiedad se prueba una vez y nunca se revoca

La prueba es un evento fechado, no un estado continuo. Una vez probado un dominio, retirar después el registro TXT no la revoca; de lo contrario, cualquier caída de DNS cortaría el envío. Volver a publicar el desafío para otra organización transfiere el dominio: un dominio probado pertenece exactamente a una organización a la vez. La comprobación es solo síncrona: ocurre cuando llamas a verify o abres la pantalla del dominio. No hay ninguna tarea en segundo plano.

Los registros nunca se guardan

Los registros del proveedor se vuelven a leer en cada llamada, porque cambian si la identidad se vuelve a crear. No los guardes en caché: una copia desactualizada manda a alguien a publicar registros que ya no verifican nada. El registro de desafío es la excepción solo en su origen —su valor es nuestro, por eso sobrevive a una caída del proveedor—, pero se sirve de la misma manera, y tú nunca lo guardas en caché.

Cuando el proveedor de correo no está disponible

Las lecturas no fallan. GET /api/v1/domains devuelve el último estado conocido con "sesUnavailable": true y su lastCheckedAt. verify sí falla: comprobar es precisamente lo que pediste, y fingir lo contrario sería mentir.