Rutas de Entrada
Configure reglas de enrutamiento para dirigir los correos entrantes a almacenamiento, webhooks u otras acciones
Las rutas definen cómo MailLand gestiona los correos entrantes de un dominio. Cada ruta coincide con
la parte local del destinatario (la parte de la dirección antes de @) y ejecuta una o más
acciones: almacenar, entregar a un webhook, reenviar, rechazar en SMTP o descartar. Las rutas se
evalúan en orden de prioridad (el número más bajo primero) y la primera coincidencia gana.
Las rutas solo coinciden con la parte local de la dirección del destinatario. No hay coincidencia
por remitente, asunto ni otros encabezados: una ruta no puede filtrar por from o subject.
Tipos de coincidencia
| Tipo de coincidencia | Descripción |
|---|---|
exact | La parte local coincide exactamente con el patrón |
prefix | La parte local comienza con el patrón |
suffix | La parte local termina con el patrón |
contains | La parte local contiene el patrón |
plusaddressing | La parte local es el patrón seguido de +cualquier cosa (support coincide con support+ticket123) |
catchall | Coincide con todos los destinatarios; no requiere patrón |
regex | La parte local coincide con el patrón como expresión regular (máx. 200 caracteres, tiempo de espera de 1 segundo) |
La coincidencia no distingue mayúsculas de minúsculas y siempre se evalúa contra la parte local,
[email protected] y [email protected] coinciden ambos con una ruta con patrón
support limitada al mismo dominio.
El tipo de coincidencia regex requiere un plan con enrutamiento entrante por expresión regular
(hoy Pro y Max, no Free). Crear una ruta con matchType: "regex", o actualizar una ruta existente
para que su tipo de coincidencia pase a ser regex, en un plan sin esa función devuelve
400 PLAN_LIMIT_REACHED. Una ruta que ya usa regex sigue coincidiendo aunque el espacio de
trabajo baje de plan después, y editarla sin cambiar su tipo de coincidencia no se ve afectado.
Acciones de ruta
El campo actions de una ruta es una lista de uno o más de los siguientes valores de cadena:
| Acción | Descripción |
|---|---|
store | Almacenar el correo procesado para recuperarlo mediante la API y el panel |
webhook | Entregar el correo procesado a un webhook (requiere webhookId) |
forward | Enviar una copia del correo a forwardToEmail, a través de la vía normal de envío |
reject | Rechazar el mensaje a nivel SMTP con rejectStatus/rejectMessage |
drop | Aceptar el mensaje por SMTP y luego descartarlo silenciosamente, sin almacenamiento, sin webhook |
unsubscribe | Tratar la dirección como un buzón de List-Unsubscribe; terminal, ver abajo |
store y webhook pueden combinarse entre sí y con forward. reject, drop y unsubscribe son
terminales: cada una debe ser la única acción de la ruta; la API rechaza una solicitud que
combine una de ellas con cualquier otra acción.
Una copia reenviada no se envía por retransmisión SMTP en bruto: pasa por la misma canalización de envío que cualquier otro correo transaccional, por eso necesita el consentimiento del destino (ver abajo), cuenta contra su cuota de envío y aparece en su registro de mensajes como cualquier otro envío.
Destinos de reenvío
Antes de reenviar cualquier correo a una dirección, el propietario de esa dirección debe confirmarlo: excepto si la dirección está en uno de sus propios dominios totalmente verificados para envío. Para una dirección externa no hay forma de evitarlo: protege al propietario del destino de recibir correo que nunca aceptó, y protege su reputación de envío de una dirección que rebota o se queja.
Al crear o actualizar una ruta con forward en actions, MailLand automáticamente:
- Crea (o reutiliza) un registro de destino de reenvío para
forwardToEmail, con alcance a su tenant: la misma dirección se recuerda en todas las rutas que reenvían a ella. - Si la dirección necesita confirmación y nunca se le ha preguntado, envía un correo de confirmación con un enlace.
El guardado de la ruta en sí siempre tiene éxito; un correo de confirmación fallido no hace fallar
la ruta: el destino simplemente queda pending (no se reenvía nada) hasta que reenvíe la
confirmación.
Enlace de confirmación
El enlace del correo de confirmación es válido durante 7 días y es de un solo uso: una vez
que el destinatario confirma o rechaza, visitar el enlace de nuevo solo muestra la misma decisión,
no se puede revertir volviendo a visitarlo. Un enlace expirado que nunca se decidió devuelve
410 Gone si se abre de nuevo.
- Confirmar: el correo reenviado a este tenant ahora se enviará a la dirección.
- Rechazar: definitivo. Nunca se vuelve a reenviar nada a la dirección para este tenant, y el tenant no puede volver a solicitar confirmación para ella.
Obtener un destino de reenvío
GET https://api.mail.land/v1/transactional/inbound/forward-destinations/{destinationId}{
"id": "f2k9m3q7p4w8x1",
"email": "[email protected]",
"status": "pending",
"confirmedVia": null,
"lastSentAt": "2026-09-26T10:00:00Z",
"confirmedAt": null,
"declinedAt": null
}status es uno de pending, confirmed o declined. confirmedVia es link cuando el
propietario confirmó por correo, verified_domain cuando la dirección está en uno de sus propios
dominios verificados para envío y no necesitó confirmación, o null en otro caso. La respuesta de
una ruta también incluye este mismo objeto bajo forwardDestination (ver la respuesta de ruta más
abajo).
Reenviar una confirmación
POST https://api.mail.land/v1/transactional/inbound/forward-destinations/{destinationId}/resendSolo para un destino que sigue pending y realmente necesita un enlace (una dirección en uno de
sus propios dominios de envío verificados devuelve 409 FORWARD_DESTINATION_NO_CONFIRMATION_NEEDED,
ya que no hay nada que reenviar). Con límite de frecuencia: como máximo una vez cada 5 minutos y 5
veces al día por destino, y 50 veces al día para todo el tenant. Superar cualquiera de los límites
devuelve 429 FORWARD_CONFIRMATION_RATE_LIMITED.
No hay forma de deshacer el rechazo de un destino a través de la API una vez que ha rechazado: una dirección rechazada queda bloqueada para ese tenant.
Crear una ruta
Las rutas pertenecen a un dominio y se crean bajo ese dominio.
POST https://api.mail.land/v1/transactional/inbound/domains/{domainId}/routes{
"name": "Support Inbox",
"matchType": "exact",
"matchPattern": "support",
"actions": ["store", "webhook"],
"webhookId": "w4k8m2q7p9x3z1",
"priority": 10
}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre de la ruta |
matchType | string | Sí | Uno de los tipos de coincidencia anteriores |
matchPattern | string | Sí | Patrón para coincidir con la parte local (se ignora en catchall, máx. 64 caracteres, máx. 200 en regex) |
actions | string[] | Sí | Uno o más de store, webhook, forward, reject, drop, unsubscribe |
webhookId | string | Cond. | ID público de un webhook existente; requerido cuando actions incluye webhook. Las rutas nunca crean un webhook en línea: créelo primero en la página de Webhooks |
forwardToEmail | string | Cond. | Destino para forward; requerido cuando actions incluye forward. Debe ser una dirección simple (sin nombre de visualización, sin corchetes angulares). El propio dominio de la ruta debe estar totalmente verificado para envío, la copia reenviada se envía desde él, o la solicitud se rechaza con 400 FORWARD_DOMAIN_NOT_VERIFIED. El destino mismo debe confirmar por separado, salvo que esté en uno de sus propios dominios verificados para envío (ver Destinos de reenvío) |
rejectStatus | string | No | Estado SMTP para reject, p. ej. 550 o 550 5.1.1 (por defecto 550 5.1.1) |
rejectMessage | string | No | Texto de rechazo SMTP para reject |
priority | int | No | Número más bajo = se evalúa primero. Por defecto es uno más que la prioridad más alta actual del dominio. Debe ser único por dominio |
curl -X POST https://api.mail.land/v1/transactional/inbound/domains/k3v9x2m8q1w7z4/routes \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Support Inbox",
"matchType": "exact",
"matchPattern": "support",
"actions": ["store", "webhook"],
"webhookId": "w4k8m2q7p9x3z1",
"priority": 10
}'Respuesta
{
"id": "r7k3m9q2p4w8x1",
"name": "Support Inbox",
"domainId": "k3v9x2m8q1w7z4",
"domainName": "yourdomain.com",
"priority": 10,
"isEnabled": true,
"matchType": "Exact",
"matchPattern": "support",
"actions": ["store", "webhook"],
"webhookId": "w4k8m2q7p9x3z1",
"webhookName": "Support Webhook",
"webhookUrl": "https://yourapp.com/webhooks/support",
"forwardToEmail": null,
"forwardDestination": null,
"rejectStatus": null,
"rejectMessage": null,
"createdAt": "2026-02-17T12:00:00Z",
"updatedAt": "2026-02-17T12:00:00Z"
}Las solicitudes aceptan matchType en cualquier combinación de mayúsculas/minúsculas; las
respuestas siempre devuelven el nombre del enum capitalizado: Exact, Prefix, Suffix,
Contains, PlusAddressing, CatchAll, Regex. No compare el matchType de una respuesta con
una cadena en minúsculas.
forwardDestination solo se completa cuando actions incluye forward; incluye el mismo objeto
descrito en Obtener un destino de reenvío:
{
"...": "...",
"actions": ["store", "forward"],
"forwardToEmail": "[email protected]",
"forwardDestination": {
"id": "f2k9m3q7p4w8x1",
"email": "[email protected]",
"status": "pending",
"confirmedVia": null,
"lastSentAt": "2026-09-26T10:00:00Z",
"confirmedAt": null,
"declinedAt": null
}
}Listar rutas de un dominio
GET https://api.mail.land/v1/transactional/inbound/domains/{domainId}/routesDevuelve todas las rutas del dominio, ordenadas por prioridad (la más baja primero).
curl https://api.mail.land/v1/transactional/inbound/domains/k3v9x2m8q1w7z4/routes \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"items": [
{ "id": "r7k3m9q2p4w8x1", "name": "Support Inbox", "priority": 10, "isEnabled": true, "..." : "..." }
],
"totalCount": 1
}Listar todas las rutas
Para listar rutas de todos los dominios del tenant, use en su lugar el endpoint paginado por cursor:
GET https://api.mail.land/v1/transactional/inbound/routes| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
cursor | string | - | Cursor opaco de nextCursor de la página anterior. Omitir en la primera página |
limit | int | 50 | Elementos por página |
Obtener detalles de una ruta
GET https://api.mail.land/v1/transactional/inbound/routes/{routeId}curl https://api.mail.land/v1/transactional/inbound/routes/r7k3m9q2p4w8x1 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Actualizar una ruta
PUT https://api.mail.land/v1/transactional/inbound/routes/{routeId}El cuerpo de la solicitud coincide con el de creación, pero todos los campos son opcionales: solo se actualizan los campos que envíe.
curl -X PUT https://api.mail.land/v1/transactional/inbound/routes/r7k3m9q2p4w8x1 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"matchPattern": "help",
"priority": 5
}'Activar o desactivar una ruta
Cambia isEnabled sin tocar ningún otro campo. Sin cuerpo de solicitud.
POST https://api.mail.land/v1/transactional/inbound/routes/{routeId}/togglecurl -X POST https://api.mail.land/v1/transactional/inbound/routes/r7k3m9q2p4w8x1/toggle \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Reordenar rutas
Actualiza la prioridad de todas las rutas de un dominio a la vez, pasando los IDs de ruta en el orden deseado: el primer ID pasa a prioridad 1, el segundo a prioridad 2, y así sucesivamente.
POST https://api.mail.land/v1/transactional/inbound/domains/{domainId}/routes/reorder{
"routeIds": ["r7k3m9q2p4w8x1", "m2p8w4x1k7q3z9", "x4k1p7m3q9w2z8"]
}curl -X POST https://api.mail.land/v1/transactional/inbound/domains/k3v9x2m8q1w7z4/routes/reorder \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"routeIds": ["r7k3m9q2p4w8x1", "m2p8w4x1k7q3z9", "x4k1p7m3q9w2z8"]
}'Probar una ruta
Compruebe qué ruta coincidiría con una dirección de destinatario dada sin procesar un correo.
POST https://api.mail.land/v1/transactional/inbound/domains/{domainId}/routes/test{
"emailAddress": "[email protected]"
}curl -X POST https://api.mail.land/v1/transactional/inbound/domains/k3v9x2m8q1w7z4/routes/test \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"emailAddress": "[email protected]"
}'{
"matched": true,
"matchedRouteId": "r7k3m9q2p4w8x1",
"matchedRouteName": "Support Inbox",
"actions": ["store", "webhook"]
}Si ninguna ruta coincide, la respuesta es 200 con matched: false, y matchedRouteId/matchedRouteName/actions son todos null. 404 significa que el dominio no se encontró, o que la dirección probada no es válida (sin @).
Eliminar una ruta
DELETE https://api.mail.land/v1/transactional/inbound/routes/{routeId}curl -X DELETE https://api.mail.land/v1/transactional/inbound/routes/r7k3m9q2p4w8x1 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Ejemplos de rutas
Ruta catch-all: almacenar todo destinatario no reconocido:
{
"name": "Catch All",
"matchType": "catchall",
"matchPattern": "*",
"actions": ["store"],
"priority": 999
}Direccionamiento plus: enrutar todas las variantes de support+*@yourdomain.com a un webhook:
{
"name": "Support Tickets",
"matchType": "plusaddressing",
"matchPattern": "support",
"actions": ["store", "webhook"],
"webhookId": "w4k8m2q7p9x3z1",
"priority": 5
}Rechazo en SMTP: rechazar correo a un buzón retirado antes de que sea aceptado:
{
"name": "Retired Mailbox",
"matchType": "exact",
"matchPattern": "old-team",
"actions": ["reject"],
"rejectStatus": "550 5.1.1",
"rejectMessage": "Mailbox does not exist",
"priority": 1
}Las rutas se evalúan en orden de prioridad (el número más bajo primero). Coloque las rutas específicas en números de prioridad más bajos y las rutas catch-all en el número más alto para que se ejecuten al final.
Cómo es una copia reenviada
Una copia reenviada es un correo transaccional nuevo y normal, no una retransmisión en bruto de los bytes originales, enviado desde su dominio verificado para que pueda pasar DKIM y DMARC en el buzón del destino:
- From:
"<nombre del remitente original> via <dirección coincidente>@<su dominio>", p. ej."Jane Doe via [email protected]". Un nombre de visualización que parece una dirección (contiene@,<o>) se reemplaza por la dirección original simple, para que una copia nunca pueda suplantar una marca bajo su DKIM. - Reply-To: el
Reply-Todel mensaje original si lo tenía, si no la dirección del remitente original, para que las respuestas lleguen al autor real, no a usted. - Sin seguimiento: el seguimiento de apertura y clics siempre está desactivado en una copia reenviada, sean cuales sean los ajustes de seguimiento de su workspace.
- Sin pie de marca: el pie de página del plan gratuito que pueden llevar otros envíos nunca se añade.
- Adjuntos: filtrados con las mismas reglas que un envío saliente por API (tipo, cantidad, tamaño total). Lo que se omite se indica con una nota al principio de la copia: "Forwarded without N attachment(s) that exceed the outbound attachment limits: ...", la copia igual llega, solo sin esas partes.
- Etiqueta: cada copia reenviada lleva la etiqueta
inbound-forward, para que pueda encontrarlas en su registro de mensajes habitual; su estado de entrega (queued, sent, delivered, bounced, etc.) es el mismo estado que recibe cualquier otro envío transaccional, porque pasa por la misma canalización de entrega. - Uso: cada copia reenviada cuenta como un envío contra la cuota y facturación de su plan, y se muestra como su propia línea "Inbound forward" en el uso, separada de los envíos por API, SMTP, campañas y automatizaciones.
Lo que nunca se reenvía
Un mensaje que coincide con una ruta forward no se reenvía, y nunca se factura, cuando:
- Se marcó como spam, o el remitente está bloqueado como spam.
- Falló DMARC según la política efectiva del dominio remitente, que es
quarantineoreject, resuelta subiendo desde el dominio del remitente hasta encontrar el registro aplicable más cercano, de modo que elsp=propio de un subdominio prevalece sobre elp=de su dominio organizacional, y un registrot=y(de prueba) opct=0se trata un nivel de política por debajo, reenviarlo volvería a firmar un mensaje que el remitente pidió explícitamente a los receptores rechazar. - Él, o su cuerpo HTML/texto, supera los límites de tamaño de salida de la plataforma.
- Reenviarlo crearía un bucle: el destino es uno de los propios destinatarios del mensaje, o ya
lleva demasiados saltos o cabeceras
Received.
Una copia que es elegible pero no se puede enviar temporalmente (una pausa de política, una ventana de cuota, una interrupción) se reintenta con espera creciente hasta 24 horas, y luego expira sin enviarse. Una ruta que se deshabilita, se elimina o cambia su destino después de recibir un mensaje también detiene cualquier copia que aún esperaba: la configuración actual de la ruta siempre es la autoridad.
Comprobar el resultado de un reenvío
Todo correo entrante que coincidió con una ruta forward lleva un array forwards en su
respuesta de detalle (GET /v1/transactional/inbound/emails/{id}): una entrada por cada destino al que el
mensaje se puso en cola para reenviar, para que veas lo que realmente ocurrió, no solo a dónde se
configuró.
"forwards": [
{
"destination": "[email protected]",
"status": "Admitted",
"reason": null,
"omittedAttachmentCount": 0,
"messageId": "m_01hz3k...",
"createdAt": "2026-09-26T10:00:00Z",
"updatedAt": "2026-09-26T10:00:02Z"
}
]| Campo | Tipo | Descripción |
|---|---|---|
destination | string | La dirección de destino del reenvío |
status | string | Uno de los estados de abajo |
reason | string | null | Código de detalle legible por máquina (por ejemplo hop_limit), o null |
omittedAttachmentCount | número | Adjuntos excluidos de la copia por superar los límites de adjuntos salientes |
messageId | string | null | El id del mensaje de la copia reenviada una vez admitida, si no null |
createdAt / updatedAt | string | Marcas de tiempo ISO-8601 del registro de reenvío |
status es uno de:
| Estado | Significado |
|---|---|
Pending | Escrito junto con el correo entrante; aún no reclamado por el worker de reenvío |
Processing | Reclamado por el worker de reenvío; en curso |
Deferred | Un rechazo transitorio (retraso de política, tasa, ventana de cuota, interrupción); se reintenta con backoff hasta 24 horas |
Admitted | Enviado a través del pipeline de envío normal: messageId identifica la copia, cuyo propio estado de entrega (en cola/enviado/entregado/rebotado) es el autoritativo |
SkippedLoop | Protección contra bucles: límite de saltos, demasiados encabezados Received, o el destino es uno de los propios destinatarios del mensaje |
SkippedSpam | El mensaje fue marcado como spam, o el remitente está en la lista de bloqueo como spam |
SkippedAuthFail | Falló DMARC según la política efectiva del dominio remitente (quarantine o reject, con el sp= del subdominio respetado) |
SkippedTooLarge | El mensaje supera el límite de tamaño de reenvío saliente |
RefusedSuppressed | El destino está suprimido, o rechazado por la protección de destinatarios |
RefusedDomainNotVerified | El dominio de la ruta no está (o ya no está) verificado para envío |
RefusedPolicy | Un rechazo terminal por política o cuenta |
RefusedRouteInactive | La ruta fue deshabilitada, eliminada, perdió su acción forward, o cambió de destino después de recibir el mensaje |
RefusedInvalid | El mensaje almacenado no pudo convertirse en una copia enviable |
Expired | Seguía en Deferred cuando se cerró la ventana de reintento de 24 horas |
RefusedDestinationUnconfirmed | El destino aún no ha confirmado (ver Destinos de reenvío) |
RefusedDestinationDeclined | El propietario del destino declinó; nunca se reenvía nada a esa dirección |
Pending, Processing y Deferred son los únicos estados no finales, cualquier otro valor es
terminal.
Respuestas de error de reenvío
| Estado | Código | Descripción |
|---|---|---|
400 | VALIDATION_FAILED (campo forwardToEmail) | Al crear: actions incluye forward pero forwardToEmail está vacío |
400 | FORWARD_DESTINATION_REQUIRED | Al actualizar (PUT): la ruta efectiva resultante reenvía pero no tiene forwardToEmail |
400 | FORWARD_DOMAIN_NOT_VERIFIED | El dominio de la ruta no está totalmente verificado para envío, así que nunca podría enviarse desde él una copia reenviada |
404 | RESOURCE_NOT_FOUND | Destino de reenvío no encontrado |
409 | FORWARD_DESTINATION_NOT_PENDING | Se solicitó reenviar para un destino que ya confirmó o rechazó |
409 | FORWARD_DESTINATION_NO_CONFIRMATION_NEEDED | Se solicitó reenviar para un destino en uno de sus propios dominios de envío verificados |
410 | FORWARD_CONFIRMATION_EXPIRED | El enlace de confirmación expiró (7 días) sin decidirse |
409 | FORWARD_CONFIRMATION_ALREADY_DECIDED | El enlace se usó para la otra decisión |
429 | FORWARD_CONFIRMATION_RATE_LIMITED | Se solicitó reenviar demasiado pronto, o se alcanzó el límite diario de reenvíos |
Respuestas de error
| Estado | Código | Descripción |
|---|---|---|
400 | VALIDATION_FAILED | Faltan campos requeridos, matchType/actions inválidos, o una acción terminal combinada con otra |
400 | INVALID_REQUEST | Ya existe una ruta con esta priority para el dominio, o no se encontró el webhookId referenciado |
400 | PLAN_LIMIT_REACHED | Crear una ruta con matchType: "regex", o actualizar una ruta para que su tipo de coincidencia pase a ser regex, en un plan sin soporte de rutas regex (Free hoy) |
403 | FORBIDDEN | Permisos insuficientes |
404 | RESOURCE_NOT_FOUND | Dominio o ruta no encontrados (endpoint de prueba: también una dirección no válida sin @; sin coincidencia es 200 con matched: false, no un 404) |
Próximos pasos
- Inbound Overview: cómo funciona el procesamiento de correo entrante
- Inbound Webhooks: formato de payload y entrega de webhooks
- Domains: configurar registros MX para correo entrante