Saltar al contenido
Plataforma para developers · Eventos

Recibe eventos de correo firmados

Los webhooks se entregan al menos una vez. Verifica antes de parsear, deduplica por event ID y responde 2xx antes de cinco segundos.

Handshake de verificación del endpoint

Antes de guardar un endpoint, Omnero Mail envía webhook.endpoint_verification. Parsea el JSON y devuelve { "challenge": payload.data.challenge } con HTTP 2xx antes de cinco segundos. Redirecciones, timeout, respuestas no 2xx, JSON inválido o un challenge diferente impiden la creación. El handshake demuestra que controlas un handler funcional; su firma aún no debe considerarse confiable porque el secreto se revela solo después de crear correctamente.

                        const payload = JSON.parse(rawBody);
if (payload.type === 'webhook.endpoint_verification') {
  return Response.json({ challenge: payload.data.challenge });
}
                      

Verifica HMAC-SHA256 sobre los bytes crudos

Para cada evento operativo, lee los tres headers MailDeck-Webhook antes de parsear. Construye id + "." + timestamp + "." + rawBody, calcula HMAC-SHA256 con tu secreto whsec_ y compara v1=<hex> en tiempo constante. Rechaza headers ausentes, timestamps alejados más de cinco minutos de tu reloj, hex malformado o una firma diferente. Nunca reconstruyas el body con JSON.stringify: incluso un JSON equivalente produce bytes distintos.

                        import { createHmac, timingSafeEqual } from 'node:crypto';

const id = request.headers.get('maildeck-webhook-id')!;
const timestamp = request.headers.get('maildeck-webhook-timestamp')!;
const supplied = request.headers.get('maildeck-webhook-signature')!;
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!Number.isFinite(age) || age > 300) throw new Error('stale webhook');

const expected = createHmac('sha256', process.env.MAILDECK_WEBHOOK_SECRET!)
  .update(`${id}.${timestamp}.${rawBody}`)
  .digest('hex');
const received = supplied.startsWith('v1=') ? supplied.slice(3) : '';
const valid = /^[a-f0-9]{64}$/.test(received) && timingSafeEqual(
  Buffer.from(received, 'hex'), Buffer.from(expected, 'hex')
);
if (!valid) throw new Error('invalid webhook signature');
                      

Envelope y headers de entrega

Las solicitudes operativas usan Content-Type: application/json y User-Agent: MailDeck-Webhooks/1.0. El envelope JSON contiene id, type, apiVersion, occurredAt y data. data siempre incluye tipo de objeto e ID canónicos más los campos propios del evento; el consumidor debe ignorar campos y tipos desconocidos para conservar compatibilidad futura.

  • MailDeck-Webhook-Id — event ID estable y clave de deduplicación
  • MailDeck-Webhook-Timestamp — segundos Unix para impedir replay
  • MailDeck-Webhook-Signature — v1=<HMAC de 64 caracteres hex>

Cifrado en reposo frente a firma en tránsito

Omnero Mail genera un valor whsec_ aleatorio y lo revela una sola vez. Internamente se almacena como un envelope AES-256-GCM versionado, con IV nuevo de 96 bits y authentication tag. El dispatcher lo descifra solo en memoria del worker, firma los bytes exactos que envía y descarta el texto plano con la invocación. El body no usa cifrado de aplicación: HTTPS protege el transporte y HMAC demuestra autenticidad e integridad. El receptor verifica la firma; nunca descifra el JSON.

Catálogo de eventos

Suscríbete a tipos individuales o a * para todos los soportados. El ciclo de mensaje incluye message.received, message.queued, message.sent, message.delivered, message.bounced, message.failed y message.updated. Los recursos emiten mailbox.created, mailbox.updated, mailbox.suspended y domain.health_changed.

Diseña para entrega al menos una vez

Parsea y procesa el evento únicamente después de verificar la firma. En una transacción durable, guarda el event ID bajo una restricción única y encola o aplica el efecto. Una repetición conserva el mismo ID y puede confirmarse sin duplicar trabajo. Responde 2xx después de aceptar durablemente, no solo después de leer el request.

  • Sin garantía de orden global
  • Cinco segundos para responder
  • Reintentos automáticos y retención en dead-letter queue
  • Replay manual desde la actividad de integraciones

Reintentos, fallos terminales y salud del endpoint

Cualquier timeout, resolución insegura de URL, redirect, fallo de red o respuesta no 2xx cuenta como intento fallido. Omnero Mail registra el fallo y reintenta mediante la cola estándar hasta cinco intentos. Las entregas agotadas quedan dead y disponibles para replay manual. Diez fallos consecutivos desactivan el endpoint; una entrega correcta reinicia el contador.

Recupérate después de una caída

Usa GET /v1/events?limit=25&cursor=<timestamp ISO> con messages:read para conciliar el historial canónico. Procesa items, guarda nextCursor solo después de aceptar durablemente y continúa hasta null. Los webhooks optimizan latencia; events recupera completitud sin asumir orden global.

Prueba el pipeline con eventos sandbox

Desde Dashboard → Integraciones, elige una aplicación sandbox y un tipo de evento. Omnero Mail crea un evento canónico sintético marcado demo: true, lo envía únicamente a los endpoints suscritos de esa aplicación y aplica la misma firma HMAC, reintentos, actividad y replay que en una entrega operativa.

Siguiente paso

Crea el primer buzón sin coste.

Comenzar gratisIniciar sesión