Docs / Módulo / Mail

Módulo de Mail

Correo transaccional por evento: registros, confirmaciones de compra, recuperación de contraseña, notificaciones. Un correo por request, con tu propio HTML y variables de personalización.

¿Buscas newsletters o campañas masivas a listas segmentadas? Ese es un producto distinto — ver Marketing.

Introducción

La API de Mail te permite enviar correos transaccionales directamente desde tu backend, sin configurar SMTP ni gestionar infraestructura de entrega. Envías tu HTML/texto y las variables de personalización; Webability se encarga de la cola, reintentos y entregabilidad.

¿Para qué sirve?

  • • Correos de bienvenida y confirmación de cuenta
  • • Comprobantes de compra y facturas
  • • Recuperación de contraseña con enlaces de un solo uso
  • • Notificaciones de estado (envíos, pagos, alertas)

Características

  • • Envío síncrono o asíncrono (wait_send)
  • • Consulta de estatus por correo (GET /status)
  • • Variables de personalización {{variable}}
  • • Plantillas registradas reutilizables (template)
  • • Envío a múltiples destinatarios en un solo request

Quickstart

Un correo, un request.

CLIENTID="tu-client-id"
TOKEN="tu-token-secreto"
TS=$(date +%s)
PATH="/v1/mail/send"
MSG="POST|${PATH}|${TS}|${CLIENTID}"
DIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$TOKEN" | awk '{print $2}')

curl -s -X POST https://api.webability.info${PATH} \
  -H "X-WA-Client: $CLIENTID" \
  -H "X-WA-Timestamp: $TS" \
  -H "X-WA-Digest: $DIG" \
  -H "Content-Type: application/json" \
  -d '{
    "from": { "email": "no-reply@tuempresa.com", "name": "Tu Empresa" },
    "to":   { "email": "cliente@ejemplo.com", "name": "Ana", "vars": { "nombre": "Ana" } },
    "subject": "Confirma tu compra",
    "html": "<p>Hola {{nombre}}, tu compra fue confirmada.</p>"
  }'
{ "status": "ok", "queue_key": 42, "queue_status": "pending", "to": "cliente@ejemplo.com" }

El correo se encola y se envía en segundo plano. Consulta GET /v1/mail/status/{queue_key} para saber si ya se entregó, o usa wait_send para esperar el resultado en el mismo request.

POST /v1/mail/send

Envía un correo a un solo destinatario.

Body JSON

CampoTipoReq.Descripción
from.emailstringCorreo remitente
from.namestringNombre del remitente
to.emailstringCorreo destinatario
to.namestringNombre del destinatario
to.varsobjectVariables de personalización, con los nombres que quieras — sin prefijos. Cada clave sustituye {{clave}} en subject/html/text, o dentro del content de la plantilla si usas template — mismo {{clave}}, sin diferencia (ver Con plantilla registrada)
templatestringId de una plantilla ya registrada, activa y de tipo email (ver Con plantilla registrada) — un template de tipo "layout" no se puede mandar directo. Si template viene, subject/html/text se ignoran
langstringCódigo de idioma destino (BCP-47, p. ej. fr, en, de). Ignorado si no usas template (ver Plantillas en varios idiomas)
subjectstring✓ *Asunto. * No requerido si usas template
htmlstringCuerpo HTML (al menos uno de html/text, salvo que uses template)
textstringCuerpo en texto plano
tagsstring[]Etiquetas libres para tus propios reportes
track_opensboolPixel de apertura
track_clicksboolLink wrapping para clics
wait_sendboolVer wait_send abajo

Respuesta (200)

{
  "status": "ok",
  "queue_key": 42,
  "queue_status": "pending",
  "to": "cliente@ejemplo.com"
}

queue_status viene "pending" salvo que uses wait_send (ver abajo). El envío real ocurre en segundo plano.

Enviar con una plantilla registrada

En vez de mandar subject/html/text en cada request, puedes registrar una plantilla reutilizable desde tu cuenta y referenciarla por su id con el campo template. El servidor arma el correo con esa plantilla — solo mandas to.vars con los valores a inyectar.

La plantilla debe existir y estar activa para tu cuenta (tabla interna templates_template). El servidor valida esto antes de encolar el correo — si el template no existe o no está activo, la respuesta es un error inmediato (3025/3026, ver Errores), no un envío que falla en segundo plano.

curl -s -X POST https://api.webability.info/v1/mail/send \
  -H "X-WA-Client: $CLIENTID" -H "X-WA-Timestamp: $TS" -H "X-WA-Digest: $DIG" \
  -H "Content-Type: application/json" \
  -d '{
    "from": { "email": "no-reply@tuempresa.com", "name": "Tu Empresa" },
    "to":   { "email": "cliente@ejemplo.com", "name": "Ana", "vars": { "nombre": "Ana", "codigo": "482913" } },
    "template": "recuperacion"
  }'
{ "status": "ok", "queue_key": 55, "queue_status": "pending", "to": "cliente@ejemplo.com" }

Si el id de plantilla no existe (o no pertenece a tu cuenta) o no está activa, la respuesta llega de inmediato con status: "error" — no se encola nada:

{ "status": "error", "code": 3025, "message": "Plantilla 'recuperacion' no encontrada para esta cuenta" }

📝 Las plantillas no se crean por API — se agregan y editan directamente desde Consola → Correos → Plantillas. Ahí defines el id que vas a usar en el campo template, el tipo, el estado (activa/inactiva) y el contenido — un único bloque que debe traer las secciones [[subject]], [[text]] y [[html]] del metalenguaje de plantillas de Xamboo. La API de /v1/mail solo consume plantillas ya creadas ahí.

El tipo debe ser Correo electrónico — la consola también ofrece un tipo Layout de correo, pensado para envolver a otras plantillas (un encabezado/pie reutilizable que inyecta el cuerpo de la plantilla hija), no para enviarse solo. Si intentas usar el id de un layout directo en template, la API responde 3026.

Cómo referenciar tus vars dentro de la plantilla

Igual que en el envío ad-hoc: cada clave de to.vars se referencia directo, con su mismo nombre y sin ningún prefijo — {{clave}}. El contenido de la plantilla solo ve tus vars, nunca el resto del request (destinatario, remitente, asunto, etc.); si necesitas imprimir alguno de esos datos dentro del cuerpo, agrégalo también como var.

[[subject]]Recupera tu contraseña, {{nombre}}[[]]
[[text]]Tu código de recuperación es: {{codigo}}[[]]
[[html]]<p>Hola {{nombre}}, tu código es <strong>{{codigo}}</strong>.</p>[[]]

Contenido de plantilla de ejemplo para "template": "recuperacion" con las vars del request de arriba (nombre, codigo).

Plantillas en varios idiomas

Si tu correo va a distintos países, manda el campo lang junto con template — un código de idioma BCP-47 (fr, en, de, etc., sin distinguir mayúsculas ni región — fr-CA también sirve).

curl -s -X POST https://api.webability.info/v1/mail/send \
  -H "X-WA-Client: $CLIENTID" -H "X-WA-Timestamp: $TS" -H "X-WA-Digest: $DIG" \
  -H "Content-Type: application/json" \
  -d '{
    "from": { "email": "no-reply@tuempresa.com", "name": "Tu Empresa" },
    "to":   { "email": "cliente@ejemplo.com", "name": "Ana", "vars": { "nombre": "Ana", "codigo": "482913" } },
    "template": "recuperacion",
    "lang": "fr"
  }'

Qué hace el servidor con lang

  1. Busca la variante ya traducida — el id template + "_" + lang (en el ejemplo, recuperacion_fr). Si existe y está activa, la usa directo.
  2. Si no existe, usa la plantilla base (recuperacion) y revisa su opción auto-traducir (configurable en la consola, por plantilla):
    • Activada — genera la traducción con IA en ese momento, la guarda como recuperacion_fr para no volver a traducir la próxima vez, y la usa para este envío.
    • Desactivada, o si la traducción falla — usa la plantilla base tal cual (el correo se envía igual, en el idioma original).

En ningún caso lang hace fallar el envío: en el peor caso, degrada a enviar en el idioma de la plantilla base. lang se ignora por completo si no mandas template.

wait_send — envío síncrono

Por defecto /v1/mail/send responde de inmediato con el correo encolado (queue_status: "pending") — el envío real (conexión SMTP, entrega) sucede después, de forma asíncrona. Si necesitas saber el resultado real en el mismo request (por ejemplo, para decidir si reintentar con otro proveedor o marcar algo en tu base de datos), manda "wait_send": true.

Con wait_send: true, el servidor espera hasta 20 segundos el resultado real antes de responder. Si el envío se resuelve a tiempo, queue_status viene "sent" o "error" (con error_detail). Si no se resuelve a tiempo, la respuesta degrada a "pending" igual que sin la bandera — el queue_key sigue siendo válido para consultar después con GET /status.

curl -s -X POST https://api.webability.info/v1/mail/send \
  -H "X-WA-Client: $CLIENTID" -H "X-WA-Timestamp: $TS" -H "X-WA-Digest: $DIG" \
  -H "Content-Type: application/json" \
  -d '{ "from": {...}, "to": {...}, "subject": "...", "html": "...", "wait_send": true }'
{ "status": "ok", "queue_key": 42, "queue_status": "sent", "to": "cliente@ejemplo.com" }
{ "status": "ok", "queue_key": 43, "queue_status": "error",
  "error_detail": "550 5.1.1 The email account does not exist", "to": "no-existe@dominio.com" }

GET /v1/mail/status/{queue_key}

Consulta el estatus real de un envío hecho con POST /v1/mail/send. Solo el cliente dueño de la cuenta que lo encoló puede consultarlo — cualquier otro queue_key responde 404, sin distinguir "no existe" de "no es tuyo".

PATH="/v1/mail/status/42"
MSG="GET|${PATH}|$(date +%s)|${CLIENTID}"
DIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$TOKEN" | awk '{print $2}')

curl -s https://api.webability.info${PATH} \
  -H "X-WA-Client: $CLIENTID" \
  -H "X-WA-Timestamp: $(date +%s)" \
  -H "X-WA-Digest: $DIG"
{ "status": "ok", "queue_key": 42, "queue_status": "sent" }

Valores de queue_status

ValorSignificado
pendingEncolado, aún no se procesa.
processingEl mailer lo tomó de la cola y está enviándolo.
sentEntregado al servidor destino sin errores.
errorFalló — revisa error_detail para el motivo (SMTP rechazado, dominio inexistente, buzón lleno, etc.).

POST /v1/mail/send-bulk

Envía el mismo correo (con variables por destinatario) a varios destinatarios en un solo request. Cada destinatario se encola por separado — no soporta wait_send.

{
  "from": { "email": "newsletter@tuempresa.com", "name": "Tu Empresa" },
  "subject": "Novedades de la semana",
  "html": "<p>Hola {{nombre}}!</p>",
  "recipients": [
    { "email": "ana@ejemplo.com", "vars": { "nombre": "Ana" } },
    { "email": "luis@ejemplo.com", "vars": { "nombre": "Luis" } }
  ]
}
{
  "status": "ok", "total": 2, "queued": 2, "failed": 0,
  "results": [
    { "email": "ana@ejemplo.com", "queue_key": 10, "status": "queued" },
    { "email": "luis@ejemplo.com", "queue_key": 11, "status": "queued" }
  ]
}

Cada queue_key se puede consultar individualmente con GET /v1/mail/status/{queue_key}.

Errores

CódigoHTTPDescripción
3001401Faltan headers de autenticación
3002401Firma inválida o timestamp expirado
3003401Cliente no encontrado
3010404Servicio desconocido (usa send / send-bulk / status)
3011405Método HTTP no soportado
3020400Body JSON inválido o vacío
3021400Campo requerido faltante (from.email, to.email o recipients)
3022500Error al encolar el correo
3023400Clave de cola inválida (GET status)
3024404Cola no encontrada, o no pertenece a este cliente (GET status)
3025404El template indicado no existe (o no pertenece a tu cuenta)
3026400El template indicado existe pero no está activo, o no es de tipo email