SolidHooksSolidHooks
Empezar
Casos de usoIngerir webhooks por correo

Convierte el correo entrante en un webhook

Muchos sistemas nunca te enviarán un webhook. Un proveedor manda un aviso por correo, un banco envía una alerta, una herramienta interna envía un informe cada noche. Dale a cualquiera de ellos una dirección de SolidHooks y lo que llegue ahí se convierte en un evento guardado con un sobre analizado, enrutado por las mismas conexiones y reintentado con el mismo calendario que el tráfico HTTP.
Una dirección por origenDeduplicación por Message-IDMismos reintentos y comprobantes
Qué cubre esta guía
  1. 01Crear un origen de correo y encontrar su dirección
  2. 02El sobre que recibe tu destino
  3. 03Enrutar según remitente o asunto
  4. 04Deduplicación, presupuesto de tamaño y adjuntos
  5. 05La única regla: un origen recibe correo o HTTP, nunca ambos

Cómo encaja en el pipeline

El correo es un proveedor de un origen, que se elige igual que GitHub o Stripe, no un producto aparte. Una vez analizado, el correo es un evento como cualquier otro, así que las partes de SolidHooks que ya conoces siguen funcionando: las conexiones lo emparejan, las entregas lo reintentan, la retención lo hace caducar y tu consumidor recibe JSON por HTTP como siempre.

Sender
any mail client
Source address
<maskId>@sdhk.events
Stored event
parsed envelope, typed
Destination
HTTP POST
Tu consumidor nunca habla SMTP. Recibe el mismo POST JSON que recibiría de un proveedor de webhooks.

Configúralo

  1. 1

    Crea un origen con el proveedor email

    Pasa provider: "email" al crearlo, o cambia un origen existente con un PATCH. La respuesta incluye emailAddress, que es null en cualquier otro proveedor.

    curl
    curl -s "$API/v1/sources" \  -H "authorization: Bearer $SDHK_KEY" \  -H 'content-type: application/json' \  -d '{ "name": "Supplier notices", "provider": "email",       "verifierConfig": {} }' → { "id": "src_...", "maskId": "Kb3xk29ZtQm7Rv1A",    "emailAddress": "Kb3xk29ZtQm7Rv1A@sdhk.events", ... }

    Convertir un origen que ya tiene un verificador necesita verifierType: "noop" en el mismo PATCH. Nada firma un correo entrante, así que la API se niega a trasladar la credencial guardada en lugar de conservar un secreto que nunca leería. El mismo PATCH también borra el eventTypeField del origen y cualquier idempotencyKeys, ya que ambos describían una forma de payload que ya no llega.

  2. 2

    Dale la dirección al remitente

    Pégala donde el otro sistema espere un destinatario. No hay paso de verificación ni DNS que configurar por tu parte.

  3. 3

    Conecta el origen a un destino

    Igual que con cualquier otro origen. Filtras por el remitente o por el asunto, según lo que indique el eventTypeField del origen, o por email.received si no lo configuraste. El enrutado por remitente o asunto se explica más abajo.

Qué recibe tu destino

El payload guardado es un sobre normalizado en lugar de un bloque MIME sin procesar, así que tu handler no necesita un analizador de correo. Las direcciones van separadas, los dos cuerpos van por separado y los adjuntos llegan en base64 con sus metadatos.

payload
{  "from": "billing@supplier.example",  "to": ["Kb3xk29ZtQm7Rv1A@sdhk.events"],  "cc": [],  "subject": "Invoice #42",  "messageId": "<abc123@mail.supplier.example>",  "date": "Tue, 14 Jul 2026 09:00:00 +0000",  "text": "plain-text body",  "html": "<p>html body</p>",  "spamStatus": "NotSpam",  "bounce": false,  "attachments": [    { "name": "invoice.pdf", "contentType": "application/pdf", "size": 12345, "data": "<base64>" }  ]}

from es la cabecera From: del mensaje reducida a una dirección simple, así que Acme Billing <billing@supplier.example> llega como billing@supplier.example. Eso es lo que permite usarla como clave de filtro. El nombre visible cambia, y el Return-Path subyacente es una dirección de rebote por mensaje en todo lo que se envía a través de un servicio de correo. Ese remitente del sobre solo se usa como último recurso, cuando un mensaje no lleva ninguna cabecera From:.

El cuerpo sin procesar del evento conserva el payload original completo del proveedor de correo, incluidos los campos que no aparecen arriba, con attachments[].data reducido a null. Los bytes de los adjuntos solo están en el sobre, así que un PDF grande no se guarda dos veces.

Un origen hace una cosa o la otra

En un origen de correo, un POST HTTP a la URL de ingesta de ese origen devuelve 400 BAD_REQUEST con el mensaje de que el origen ingiere correo. Es intencionado. El correo y los webhooks llegan por caminos distintos y solo uno de ellos produce un sobre, así que un origen que aceptara ambos le daría a tu consumidor dos formas de payload bajo un mismo tipo de evento.

Consecuencia para la idempotencia
idempotencyKeys se rechaza con 400 en un origen de correo. Ahí la deduplicación es el Message-ID, y esa ruta no la eliges tú.

Enrutar según remitente o asunto

El tipo de evento de un correo sale del eventTypeField del origen, el mismo ajuste que usa un origen HTTP. Apúntalo a body.from y cada mensaje recibe como tipo la dirección del remitente, que un filtro de conexión compara como cualquier otro tipo de evento. La comparación no distingue mayúsculas y minúsculas, porque los sistemas de correo no conservan las mayúsculas de una cabecera From:, así que una lista de permitidos escrita una vez sigue coincidiendo con un remitente que más adelante llega como Billing@Supplier.example. Al repetir un evento se enruta según el tipo guardado en la ingesta, así que los filtros se comportan igual la segunda vez.

Hay dos rutas disponibles y ninguna más: body.from y body.subject. Son los campos que de verdad distinguen un mensaje de otro. El panel ofrece las mismas dos, así que un origen configurado por la API sigue siendo editable en el SolidHooks Dashboard.

curl
# Type each email with its sender instead of email.receivedcurl -s -X PATCH "$API/v1/sources/src_..." \  -H "authorization: Bearer $SDHK_KEY" \  -H 'content-type: application/json' \  -d '{ "data": { "eventTypeField": "body.from" } }' # Then a connection takes only that supplier:#   "filterRules": { "eventTypes": ["billing@supplier.example"] }
Si no lo configuras, obtienes un solo tipo
Sin eventTypeField, cada correo aceptado tiene el tipo email.received. Se puede seguir filtrando, pero no separar por remitente. La misma alternativa se aplica a cada mensaje: un correo sin asunto en un origen con body.subject cae en email.received en lugar de quedar fuera de todos los filtros.

Deduplicación y presupuesto de tamaño

El correo es más grande y más desordenado que el JSON de un webhook, así que conviene conocer las reglas sobre lo que se conserva antes de que llegue un adjunto de 20 MB a las 3 de la madrugada. No se rechaza nada por ser demasiado grande. Se recorta para que quepa, y el presupuesto en el que tiene que caber tiene un máximo de 4096 KB.

deduplicaciónPor Message-ID. Una repetición devuelve duplicate: true y no guarda nada.
presupuestoEl maxPayloadSizeKb del origen, compartido por cuerpos y adjuntos. Entre 1 y 4096 KB, con 256 por defecto.
texto primeroEl texto plano se descuenta primero y se recorta si por sí solo supera el presupuesto.
html despuésSe descarta entero a null si el texto más el html siguieran superándolo, nunca se corta en parte. En ambos casos se establece bodyTruncated: true.
adjuntosSe conservan los metadatos, data pasa a null y se establece truncated: true. Los bytes nunca se cortan en parte. Lo que se descuenta es el base64, así que calcula aproximadamente un tercio más que el tamaño del archivo.
rotaciónrotate-mask cambia la dirección, porque se deriva del maskId.

Prácticas que conviene adoptar

  • Configura eventTypeField como body.from antes de necesitarlo. Los filtros escritos contra email.received hay que reescribirlos en cuanto aparece un segundo remitente en la misma dirección.
  • Sube maxPayloadSizeKb antes de necesitarlo si el remitente adjunta PDF. El máximo es 4096 KB, y el base64 ocupa aproximadamente un tercio más que el propio archivo. Descubrir el presupuesto por un indicador truncated es una forma peor de conocerlo.
  • Lee spamStatus y bounce en tu handler. Están en el sobre porque el correo llega de remitentes que no controlas.
  • Trata la dirección como una credencial. Cualquiera que la tenga puede crear eventos en ese origen, así que rótala si acaba en algún sitio público.

Preguntas

Dale un webhook a los sistemas que solo te envían correos

Elige email como proveedor, comparte la dirección y trata el resultado como cualquier otro evento.