Correo (email)
Correo propio para cada negocio: conectás un dominio,
creás casillas (ej. ventas@tudominio.com) y alias, y
leés, borrás y enviás mensajes por API. Pensado para
que un agente de IA opere las casillas de forma autónoma. Sabado corre
el servidor de correo — vos nunca ves el token de administración ni las
contraseñas de las casillas.
Dos planos. La gestión (dominios, casillas, alias) es una API REST normal. Los mensajes (leer / enviar) corren sobre IMAP/SMTP por detrás, pero vos los usás con los mismos endpoints REST y la misma API key. No tenés que tocar IMAP ni SMTP directamente.
Flujo típico
- Conectás el dominio:
POST /v1/mail/domains→ te devolvemos los registros DNS a publicar. - El dueño del dominio carga esos registros (MX, SPF, DKIM, DMARC) en su proveedor de dominio.
- Verificás propagación:
POST /v1/mail/domains/{domain}/verifyhasta que dédns_verified: true. - Creás casillas:
POST /v1/mail/accounts. - Operás mensajes:
GET .../messages,POST .../send, etc.
Scopes: mail.read para listar/leer,
mail.write para crear/borrar/enviar. Si la plataforma
todavía no tiene el correo habilitado para tu cuenta, los endpoints
responden 503 not_configured.
Conectar un dominio
POST /v1/mail/domains
Da de alta el dominio, genera sus llaves DKIM y devuelve los registros DNS que hay que publicar.
Scope: mail.write.
POST /v1/mail/domains
{
"tenant_ref": "panaderia-lo-de-juan",
"domain": "panaderia.com"
}
Respuesta:
{
"tenant_ref": "panaderia-lo-de-juan",
"domain": "panaderia.com",
"dkim_generated": true,
"dns_verified": false,
"dns_verified_at": null,
"dns_records": {
"dns_mx": "panaderia.com. 600 IN MX 10 mail.sabado.cloud.",
"dns_spf": "panaderia.com. 600 IN TXT \"v=spf1 mx a:mail.sabado.cloud ~all\"",
"dns_dkim": "dkim._domainkey.panaderia.com. 600 IN TXT \"v=DKIM1; k=rsa; p=...\"",
"dns_dmarc": "_dmarc.panaderia.com. 600 IN TXT \"v=DMARC1; p=reject;\""
},
"created_at": "2026-06-01T12:00:00+00:00"
}
Mostrale dns_records al dueño del dominio para que los
cargue en su proveedor. El correo no funciona hasta que esos registros
propaguen.
GET /v1/mail/domains · GET /v1/mail/domains/{domain}
Lista los dominios del negocio, o trae uno con sus
dns_records y estado de verificación.
Scope: mail.read. Query:
tenant_ref (requerido).
GET /v1/mail/domains?tenant_ref=panaderia-lo-de-juan
Authorization: Bearer TU_API_KEY
DELETE /v1/mail/domains/{domain}
Borra el dominio (arrastra sus casillas y alias). Scope:
mail.write. Solo borra de nuestro lado si el servidor de
correo confirmó el borrado.
Errores:
404 tenant_not_found— eltenant_refno existe en tu cuenta.404 domain_not_found— el dominio no pertenece a ese negocio.409 conflict— el dominio ya existe.503 not_configured— el correo no está habilitado en la plataforma.
Configurar el DNS
Los registros que devuelve POST /v1/mail/domains hay que
cargarlos en el proveedor del dominio. Son cuatro obligatorios:
| Tipo | Para qué |
|---|---|
| MX | Dónde se entrega el correo del dominio (apunta a nuestro servidor). |
| TXT (SPF) | Autoriza a nuestro servidor a enviar en nombre del dominio. |
| TXT (DKIM) | Firma criptográfica de los mensajes salientes. |
| TXT (DMARC) | Política de qué hacer con el correo que no pasa SPF/DKIM. |
POST /v1/mail/domains/{domain}/verify
Resuelve el DNS real y te dice qué registros ya propagaron. Marca el
dominio como verificado solo si MX + SPF + DKIM resuelven.
Scope: mail.write.
POST /v1/mail/domains/panaderia.com/verify
{ "tenant_ref": "panaderia-lo-de-juan" }
Respuesta:
{
"tenant_ref": "panaderia-lo-de-juan",
"domain": "panaderia.com",
"dns_checks": { "mx": true, "spf": true, "dkim": true, "all": true },
"dns_verified": true
}
El DNS puede tardar hasta 24-48hs en propagar.
Reintentá verify cada tanto; mientras
all sea false, todavía no está listo.
Crear casillas
POST /v1/mail/accounts
Crea una casilla en un dominio del negocio. La plataforma genera la contraseña y la usa internamente para enviar/recibir — no se devuelve nunca por la API.
Scope: mail.write.
POST /v1/mail/accounts
{
"tenant_ref": "panaderia-lo-de-juan",
"domain": "panaderia.com",
"local_part": "ventas",
"displayed_name": "Ventas Panadería",
"quota_bytes": 2147483648
}
local_part: lo que va antes del@(ej.ventas).displayed_name,quota_bytes: opcionales.
Respuesta:
{
"tenant_ref": "panaderia-lo-de-juan",
"email": "ventas@panaderia.com",
"displayed_name": "Ventas Panadería",
"quota_bytes": 2147483648,
"enabled": true,
"created_at": "2026-06-01T12:00:00+00:00"
}
GET /v1/mail/accounts · GET /v1/mail/accounts/{email}
Lista las casillas del negocio (filtrable con ?domain=) o
trae una. Scope: mail.read. Query:
tenant_ref (requerido).
PATCH /v1/mail/accounts/{email}
Actualiza quota_bytes, displayed_name,
enabled, o rota la contraseña con
"rotate_password": true. Scope:
mail.write.
DELETE /v1/mail/accounts/{email}
Borra la casilla. Scope: mail.write.
Errores:
404 domain_not_found— el dominio no pertenece al negocio.404 account_not_found— la casilla no pertenece al negocio.409 conflict— la casilla ya existe.
Alias
Un alias reenvía una dirección a otra(s). Sirve para tener
info@, hola@, etc. cayendo en una casilla
real, sin crear buzones nuevos.
GET /v1/mail/aliases · POST /v1/mail/aliases · DELETE /v1/mail/aliases/{alias}
Scopes: mail.read (listar) /
mail.write (crear, borrar). El alias tiene que caer en un
dominio del negocio.
POST /v1/mail/aliases
{
"tenant_ref": "panaderia-lo-de-juan",
"alias": "info@panaderia.com",
"destination": "ventas@panaderia.com",
"wildcard": false
}
destination puede ser varias direcciones separadas por
coma. wildcard: true hace catch-all del dominio.
Leer y enviar mensajes
Estos endpoints operan el buzón de una casilla. Es lo que le da a un agente la capacidad de leer y responder correo de forma autónoma.
GET /v1/mail/accounts/{email}/messages
Lista mensajes (resúmenes, sin cuerpo). Scope:
mail.read. Query: tenant_ref (requerido),
folder (default INBOX), limit
(1–100, default 25). Listar no marca como leído.
GET /v1/mail/accounts/ventas@panaderia.com/messages?tenant_ref=panaderia-lo-de-juan
Authorization: Bearer TU_API_KEY
Respuesta:
{
"tenant_ref": "panaderia-lo-de-juan",
"email": "ventas@panaderia.com",
"folder": "INBOX",
"messages": [
{
"uid": 12,
"subject": "Pedido del sábado",
"from": ["Ana "],
"date": "2026-06-01T10:00:00+00:00",
"seen": false
}
]
}
GET /v1/mail/accounts/{email}/messages/{uid}
Trae un mensaje completo (cuerpo en texto y HTML, destinatarios, si
tiene adjuntos). Scope: mail.read.
DELETE /v1/mail/accounts/{email}/messages/{uid}
Borra un mensaje del buzón. Scope: mail.write.
POST /v1/mail/accounts/{email}/send
Envía un correo desde la casilla. Requiere text o
html (o ambos). Scope:
mail.write.
POST /v1/mail/accounts/ventas@panaderia.com/send
{
"tenant_ref": "panaderia-lo-de-juan",
"to": ["cliente@gmail.com"],
"cc": [],
"reply_to": "ventas@panaderia.com",
"subject": "Tu pedido está listo",
"text": "Hola! Tu pedido te espera.",
"html": "Hola! Tu pedido te espera.
"
}
Respuesta:
{
"ok": true,
"tenant_ref": "panaderia-lo-de-juan",
"from": "ventas@panaderia.com",
"sent": true
}
Errores (mensajes):
404 account_not_found— la casilla no pertenece al negocio.404 folder_not_found— la carpeta no existe en el buzón.502 imap_error/502 smtp_error— falló la lectura o el envío (vermessage).
Privacidad. No guardamos ni mostramos el contenido de los correos en ningún panel nuestro — el cuerpo de los mensajes vive en el buzón, no en nuestra base. Las contraseñas de las casillas se guardan cifradas y nunca se devuelven por la API.