Parser DMARC autohospedado 2026: parsedmarc + Elasticsearch + Kibana
Guía operacional para parser DMARC autohospedado con parsedmarc, Elasticsearch y Kibana. Reconocimiento de patrones de remitente y migración desde SaaS.
Los reportes agregados DMARC son la única telemetría operacional que los remitentes de correo reciben de los proveedores de buzón sobre los resultados de autenticación. Llegan como adjuntos XML comprimidos, diariamente, desde cada receptor que ha implementado reportes DMARC (Gmail, Yahoo, Microsoft, Apple/iCloud, Fastmail, y decenas de proveedores más pequeños). El XML es ilegible sin parser, el volumen se vuelve inmanejable pasados unos 5 dominios, y las decisiones operacionales que habilitan (mover de p=none a p=quarantine a p=reject, identificar remitentes no autorizados, monitorear salud de autenticación de terceros) son críticas para entregabilidad email en 2026 — particularmente bajo los requisitos bulk sender de Gmail/Yahoo/Microsoft que cubrimos en nuestro post sobre cumplimiento bulk sender.
El mercado de herramientas de reportes DMARC se dividió en dos caminos hace años. El camino SaaS (Dmarcian, Valimail, EasyDMARC, OnDMARC, Agari, ProofPoint) cobra tarifas mensuales por dominio, desde $19/mes para operadores pequeños hasta $20.000+/año para planes enterprise. El camino autohospedado se centra en parsedmarc — un módulo Python y CLI mantenido por Sean Whalen desde 2018 — combinado con Elasticsearch y Kibana para visualización. Ambos caminos producen esencialmente las mismas salidas operacionales: dashboards mostrando IPs de origen, tasas de alineación, remitentes no autorizados, y señales de readiness para política.
Lo que cada artículo existente describe es qué son los reportes agregados. Lo que ningún artículo en español consolida es la guía operacional autohospedada producción-grade: un stack docker-compose funcional con seguridad real (contraseñas, TLS, autenticación reverse proxy), la comparativa TCO con números USD explícitos por dominio frente a los cuatro principales competidores SaaS, las seis firmas de patrones de remitente que distinguen suplantación real de mala configuración común vs reenvío benigno, y los criterios para cuándo migrar desde SaaS a autohospedado se justifica. Este post es esa guía consolidada. Escrito para operadores que gestionan 5-100 dominios que ya han hecho lo básico (DMARC publicado, etiqueta RUA apuntando a algún sitio, leer XMLs ocasionalmente) y necesitan la profundidad operacional para escalar.
La decisión de reportes DMARC: SaaS o autohospedado
La elección entre SaaS y autohospedado para reportes DMARC es estructural — una vez que los datos están fluyendo a un sistema, los costos de cambio no son triviales porque dashboards, alertas y reportes a stakeholders se integran con la plataforma elegida. La decisión racionalmente se divide en tres dimensiones:
- Número de dominios protegidos — el pricing SaaS escala por dominio; el autohospedado tiene un costo fijo de infraestructura sin importar el número de dominios
- Capacidad de ingeniería operacional — autohospedado requiere familiaridad Linux/Docker, mantenimiento continuo, troubleshooting de Elasticsearch
- Sensibilidad de datos / postura de cumplimiento — autohospedado mantiene los datos DMARC en infraestructura que tú controlas; SaaS los envía a sistemas del proveedor
El cruce TCO sucede alrededor de 5-8 dominios para la mayoría de equipos. Por debajo de 5 dominios, SaaS suele ser más barato en costo total (el costo de ingeniería excede el costo de licencia). Por encima de 10 dominios, autohospedado suele ser sustancialmente más barato. La brecha se ensancha conforme aumenta el número de dominios — a 25 dominios, autohospedado típicamente es 3-5x más barato; a 100+ dominios, puede ser 10-15x más barato.
| Categoría | Dmarcian (USD anual) | Valimail (USD anual) | EasyDMARC (USD anual) | Autohospedado parsedmarc + ES (USD anual) |
|---|---|---|---|---|
| 1 dominio | 228 | 600 | 180 | 1032 |
| 5 dominios | 1140 | 3000 | 900 | 1032 |
| 25 dominios | 5700 | 15000 | 4500 | 1032 |
| 100 dominios | 22800 | 60000 | 18000 | 2580 |
Costo autohospedado basado en Hetzner CX31 (4 vCPU / 8GB / 80GB SSD) a $20/mes + 0.4 FTE ingeniero devops para setup primer mes, luego 2-3 horas/mes mantenimiento. La cifra $1.032 incluye hosting + herramientas monitoreo; los $2.580 a 100 dominios añaden upgrade a CX41 para mayor throughput. Pricing SaaS de tarifas públicas 2026: Dmarcian Pro $19/dominio/mes, EasyDMARC Plus $15/dominio/mes. Cifras Valimail aproximadas tras adquisición DigiCert (2025) — tier Align desde $19/mes, Enforce pricing custom desde ~$2.000/año escalando con número de dominios; compromisos enterprise multi-dominio a menudo $30-50/dominio/mes efectivo. Números aproximados; pricing SaaS tiene descuentos a escala no siempre reflejados.
El detalle más importante del gráfico: el costo autohospedado es prácticamente plano de 1 a 100 dominios (solo se duplica en el extremo superior debido al upgrade del servidor), mientras SaaS escala linealmente. El caso económico para autohospedado se vuelve abrumador en algún punto entre 5 y 25 dominios dependiendo del proveedor SaaS contra el que compares.
Los factores no económicos complican la decisión. Autohospedado requiere:
- Competencia en administración de servidor Linux
- Familiaridad con Docker/docker-compose
- Conocimiento operacional de Elasticsearch (sizing del heap, gestión de índices, límites de shards)
- Capacidad para interpretar salida raw de parsedmarc cuando los dashboards no superficien una pregunta
- Inversión de tiempo para setup inicial (típicamente 4-12 horas para un operador experimentado) más 2-3 horas mensuales de mantenimiento
Para equipos sin esa capacidad de ingeniería, incluso con TCO favoreciendo autohospedado, SaaS puede ser la elección correcta porque el modo de falla del autohospedado (parser roto, Elasticsearch ilegible, datos perdidos) es operacionalmente más disruptivo que el costo del SaaS. La recomendación estructural: autohospedado para operadores con capacidad de ingeniería protegiendo 8+ dominios; SaaS para operadores debajo de ese umbral o sin capacidad ops.
Dos cambios de mercado en 2025-2026 afectaron este cálculo. Primero, la adquisición de Valimail por DigiCert en 2025 movió a Valimail hacia un posicionamiento enterprise-only con pricing custom en Enforce (desde ~$2.000/año bajo solicitud, escalando a compromisos de cinco cifras a escala multi-dominio). Algunos clientes Valimail han estado reevaluando desde la adquisición, en parte por cambios en el modelo de soporte y en parte por reducida visibilidad sobre la dirección del roadmap. Segundo, PCI DSS v4.0 mandó DMARC para organizaciones que procesan datos de tarjetas de pago desde marzo 2025, sumándose a los requisitos bulk sender Gmail/Yahoo/Microsoft (cubiertos en nuestro post sobre cumplimiento bulk sender) y los mandatos CISA BOD 18-01 existentes para dominios federales US. Estas presiones de cumplimiento compuestas empujaron a organizaciones previamente indiferentes a DMARC a empezar a reportar, lo que a su vez empujó a muchas a evaluar autohospedado para controlar costos SaaS denominados en USD ante el nuevo número de dominios driven por compliance.
En LATAM esta combinación pega más fuerte: el costo SaaS facturado en USD compite con presupuestos en moneda local sujetos a devaluación, y los nuevos dominios de cumplimiento (procesamiento de pagos, subdominios transaccionales operacionales) se añaden a la facturación per-dominio sin valor diferencial. La conversación con procurement deja de ser “podemos justificar este software” y pasa a “aquí tienes el cálculo de cuándo migrar”.
Qué hay realmente en un reporte agregado (y qué se pierde)
El reporte agregado DMARC es un archivo XML (típicamente comprimido como .zip o .gz) enviado por receivers cada 24 horas (en su mayoría) o por intervalos personalizados. Cada reporte cubre un solo dominio (el header_from) durante un solo período (típicamente 24 horas), e incluye:
Metadata del reporte:
- Organización del receiver (
org_name: google.com, yahoo.com, outlook.com, etc.) - Email de contacto del receiver para soporte
- ID único del reporte
- Rango de fechas cubierto (timestamp inicio y fin)
Política DMARC publicada por el remitente:
- Dominio (
domain) - Política (
p: none, quarantine, reject) - Política subdominio (
sp: a menudo igual appor defecto) - Porcentaje (
pct: subset de mensajes a los que aplica la política) - Modo de alineación SPF (
aspf: relaxed o strict) - Modo de alineación DKIM (
adkim: relaxed o strict)
Records (uno por IP de origen único):
- IP de origen
- Conteo de mensajes desde esa IP en el período
- Disposición DMARC aplicada (none, quarantine, reject)
- Resultados de evaluación SPF y DKIM
- Estado de alineación SPF y DKIM
- Header from observado
- Resultados de auth (selectores DKIM, dominios SPF MAIL FROM)
Los reportes agregados no incluyen:
- Contenido del cuerpo del mensaje
- Líneas de asunto
- Direcciones de destinatarios
- Resultados ARC (en la mayoría de implementaciones receiver)
- Datos de engagement (apertura, clic, respuesta)
Esta limitación es crítica de entender: los reportes RUA dicen quién está enviando como tu dominio y si la autenticación pasó, no si el correo fue entregado, abierto, o si fue marcado como spam por el filtro post-autenticación. Para esa data necesitas Postmaster Tools, SNDS, o monitoreo de inbox placement (cubiertos en otros posts del cluster).
El otro gap operacional importante: los reportes RUA están agregados por IP. Si un remitente envía desde 50 IPs en un rango ESP, ves 50 records (uno por IP) sin saber si son el mismo cliente del ESP o 50 clientes distintos. Esta granularidad limitada es por qué identificar “shadow IT” (servicios no autorizados enviando desde rangos cloud) requiere investigación reverse DNS + WHOIS, no se obtiene automáticamente del XML.
El stack docker-compose producción-grade
El stack completo: parsedmarc + Elasticsearch 8 + Kibana 8 + nginx reverse proxy + base de datos GeoIP. Probado funcionando a abril 2026. La configuración debajo es producción-grade — no las versiones simplificadas en la mayoría de tutoriales blog.
Estructura de directorios:
/opt/dmarc-stack/
├── docker-compose.yml
├── .env
├── parsedmarc/
│ └── parsedmarc.ini
├── kibana/
│ └── kibana.yml
├── nginx/
│ ├── nginx.conf
│ └── certs/
└── geoip/
Archivo .env (el único lugar donde viven los secretos):
ELASTIC_PASSWORD=GENERA_LARGA_CADENA_ALEATORIA
KIBANA_PASSWORD=GENERA_OTRA_LARGA_CADENA_ALEATORIA_DIFERENTE
DMARC_IMAP_HOST=imap.example.com
DMARC_IMAP_USER=[email protected]
DMARC_IMAP_PASS=password_imap_aqui
GEOIPUPDATE_ACCOUNT_ID=tu_account_id_maxmind
GEOIPUPDATE_LICENSE_KEY=tu_license_key_maxmind
STACK_VERSION=8.13.4
NGINX_BASIC_AUTH_USER=dmarc
NGINX_BASIC_AUTH_PASS=GENERA_PASSWORD_NGINX_AUTH
docker-compose.yml (servicios principales):
version: '3.8'
services:
setup:
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
volumes:
- certs:/usr/share/elasticsearch/config/certs
user: "0"
command: >
bash -c '
if [ ! -f config/certs/ca.zip ]; then
echo "Creando CA";
bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip;
unzip config/certs/ca.zip -d config/certs;
fi;
if [ ! -f config/certs/certs.zip ]; then
echo "Creando certs";
echo -ne "instances:\n - name: elasticsearch\n dns:\n - elasticsearch\n - localhost\n ip:\n - 127.0.0.1\n" > config/certs/instances.yml;
bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key;
unzip config/certs/certs.zip -d config/certs;
fi;
chown -R 1000:0 config/certs;
echo "Listo!";
'
healthcheck:
test: ["CMD-SHELL", "[ -f config/certs/elasticsearch/elasticsearch.crt ]"]
interval: 1s
timeout: 5s
retries: 120
elasticsearch:
depends_on:
setup:
condition: service_healthy
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
volumes:
- certs:/usr/share/elasticsearch/config/certs
- esdata:/usr/share/elasticsearch/data
environment:
- node.name=elasticsearch
- cluster.name=dmarc-cluster
- discovery.type=single-node
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=true
- xpack.security.http.ssl.key=certs/elasticsearch/elasticsearch.key
- xpack.security.http.ssl.certificate=certs/elasticsearch/elasticsearch.crt
- xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.key=certs/elasticsearch/elasticsearch.key
- xpack.security.transport.ssl.certificate=certs/elasticsearch/elasticsearch.crt
- xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.license.self_generated.type=basic
ulimits:
memlock: { soft: -1, hard: -1 }
mem_limit: 4g
healthcheck:
test: ["CMD-SHELL", "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'"]
interval: 10s
timeout: 10s
retries: 120
kibana:
depends_on:
elasticsearch:
condition: service_healthy
image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
volumes:
- certs:/usr/share/kibana/config/certs
- kibanadata:/usr/share/kibana/data
- ./kibana/kibana.yml:/usr/share/kibana/config/kibana.yml:ro
environment:
- SERVERNAME=kibana
- ELASTICSEARCH_HOSTS=https://elasticsearch:9200
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
- ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
mem_limit: 1g
parsedmarc:
image: domainaware/parsedmarc:latest
depends_on:
elasticsearch:
condition: service_healthy
volumes:
- ./parsedmarc/parsedmarc.ini:/etc/parsedmarc.ini:ro
- certs:/certs:ro
- geoipdata:/usr/share/GeoIP:ro
environment:
- DMARC_IMAP_HOST=${DMARC_IMAP_HOST}
- DMARC_IMAP_USER=${DMARC_IMAP_USER}
- DMARC_IMAP_PASS=${DMARC_IMAP_PASS}
- ELASTIC_USER=elastic
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
restart: unless-stopped
geoipupdate:
image: maxmindinc/geoipupdate:latest
volumes:
- geoipdata:/usr/share/GeoIP
environment:
- GEOIPUPDATE_ACCOUNT_ID=${GEOIPUPDATE_ACCOUNT_ID}
- GEOIPUPDATE_LICENSE_KEY=${GEOIPUPDATE_LICENSE_KEY}
- GEOIPUPDATE_EDITION_IDS=GeoLite2-ASN GeoLite2-City GeoLite2-Country
- GEOIPUPDATE_FREQUENCY=72
nginx:
image: nginx:1.25-alpine
ports:
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/certs:/etc/nginx/certs:ro
depends_on:
kibana:
condition: service_started
restart: unless-stopped
volumes:
certs:
esdata:
kibanadata:
geoipdata:
parsedmarc.ini:
[general]
save_aggregate = True
save_forensic = True
nameservers = 1.1.1.1 8.8.8.8 9.9.9.9
n_procs = 4
debug = False
[imap]
host = ${DMARC_IMAP_HOST}
user = ${DMARC_IMAP_USER}
password = ${DMARC_IMAP_PASS}
ssl = True
port = 993
watch = True
delete = False
[mailbox]
reports_folder = INBOX
archive_folder = INBOX/Procesados
[elasticsearch]
hosts = https://elasticsearch:9200
ssl = True
cert_path = /certs/ca/ca.crt
user = elastic
password = ${ELASTIC_PASSWORD}
index_suffix = parsedmarc
monthly_indexes = True
kibana/kibana.yml (mínimo seguro):
server.name: kibana
server.host: "0.0.0.0"
elasticsearch.hosts: ["https://elasticsearch:9200"]
elasticsearch.username: "kibana_system"
elasticsearch.password: "${KIBANA_PASSWORD}"
elasticsearch.ssl.certificateAuthorities: ["/usr/share/kibana/config/certs/ca/ca.crt"]
xpack.security.enabled: true
xpack.encryptedSavedObjects.encryptionKey: "GENERA_CLAVE_DE_32_O_MAS_CARACTERES"
xpack.reporting.encryptionKey: "GENERA_OTRA_CLAVE_DE_32_O_MAS_CARACTERES"
xpack.security.encryptionKey: "GENERA_TERCERA_CLAVE_DE_32_O_MAS_CARACTERES"
nginx/nginx.conf (reverse proxy con HTTPS y autenticación basic):
events { worker_connections 1024; }
http {
upstream kibana {
server kibana:5601;
}
server {
listen 443 ssl http2;
server_name dmarc.tudominio.com;
ssl_certificate /etc/nginx/certs/dmarc.crt;
ssl_certificate_key /etc/nginx/certs/dmarc.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Header de autenticación básica
auth_basic "Acceso DMARC Dashboard";
auth_basic_user_file /etc/nginx/certs/htpasswd;
# Headers de seguridad
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
location / {
proxy_pass http://kibana;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# HTTP a HTTPS
server {
listen 80;
server_name dmarc.tudominio.com;
return 301 https://$host$request_uri;
}
}
Comando de generación htpasswd para nginx (corre una vez antes de docker-compose up):
docker run --rm httpd:alpine htpasswd -nbB dmarc "TU_PASSWORD_NGINX" > /opt/dmarc-stack/nginx/certs/htpasswd
Script de salud (healthcheck.sh) — corre por cron cada 15 minutos para detectar ingest gaps:
#!/bin/bash
# /opt/dmarc-stack/healthcheck.sh
# Detecta gaps de ingesta DMARC > 26 horas (más de un ciclo diario)
ES_USER=elastic
ES_PASS="$(grep ELASTIC_PASSWORD /opt/dmarc-stack/.env | cut -d'=' -f2)"
THRESHOLD_SECONDS=$((26 * 3600))
LATEST=$(curl -ks -u "${ES_USER}:${ES_PASS}" \
"https://localhost:9200/dmarc_aggregate*/_search?size=1&sort=date_range_end:desc" \
| python3 -c 'import sys, json; d=json.load(sys.stdin); print(d["hits"]["hits"][0]["_source"]["date_range_end"])')
NOW=$(date +%s)
LATEST_TS=$(date -d "${LATEST}" +%s)
DIFF=$((NOW - LATEST_TS))
if [ "${DIFF}" -gt "${THRESHOLD_SECONDS}" ]; then
echo "ALERTA: Último reporte DMARC fue hace $((DIFF / 3600)) horas"
# Conectar con tu pipeline alerting (Slack webhook, PagerDuty, email)
curl -X POST "https://hooks.slack.com/services/TU/WEBHOOK/AQUI" \
-H 'Content-Type: application/json' \
-d "{\"text\":\"⚠️ Stack DMARC: gap de ingesta detectado: ${DIFF} segundos sin reportes\"}"
exit 1
fi
exit 0
Crontab para healthcheck:
*/15 * * * * /opt/dmarc-stack/healthcheck.sh
Este healthcheck es operacionalmente más valioso que cualquier dashboard: detecta cuando IMAP credentials rotaron, parsedmarc crasheó, o Elasticsearch está bajo presión y dejó de aceptar inserts. Sin este script, los gaps de ingesta típicamente se notan 3-7 días después cuando alguien revisa dashboards y nota datos sospechosamente viejos.
El flujo arquitectónico de datos
El flujo end-to-end de datos en este stack:
Pipeline de seis componentes: receivers → buzón IMAP → parsedmarc → Elasticsearch → Kibana → nginx → operador. El punto operacionalmente más frágil es el polling IMAP — los modos de falla aquí son silenciosos y requieren monitoreo externo.
El flujo end-to-end de datos en este stack:
- Receiver envía RUA → Gmail/Yahoo/Microsoft/etc. envían reportes XML/ZIP a la dirección email especificada en tu DMARC
rua=mailto: - IMAP fetch → parsedmarc se conecta vía IMAP cada N segundos (típicamente 60-300), lee mensajes nuevos en INBOX, descarga adjuntos
- Decompresión → parsedmarc descomprime ZIP/GZ adjuntos para obtener XML
- Parsing → parsedmarc parsea XML, valida estructura, extrae records, hace lookups GeoIP/ASN sobre IPs de origen
- Indexación Elasticsearch → parsedmarc envía documentos JSON a Elasticsearch vía HTTPS auth, organizados en índices mensuales (
dmarc_aggregate-YYYY-MM) - Visualización Kibana → Kibana lee índices de Elasticsearch, renderiza dashboards basados en queries pre-construidas
- Acceso usuario → Reverse proxy nginx termina TLS, aplica auth básica, proxy a Kibana
- Archivado → parsedmarc mueve mensajes procesados a folder
INBOX/Procesados(no los borra, permite re-procesamiento si índice se corrompe)
| Categoría | Latencia P50 (segundos) | Latencia P95 (segundos) | Latencia P99 (segundos) |
|---|---|---|---|
| IMAP fetch | 2 | 8 | 30 |
| Decompresión XML | 1 | 3 | 8 |
| Parsing + GeoIP | 3 | 12 | 45 |
| Indexado Elasticsearch | 4 | 15 | 60 |
| Kibana refresh dashboard | 1 | 4 | 12 |
Latencias medidas sobre stack Hetzner CX31 procesando ~50 reportes diarios de 12 dominios. P99 indexado Elasticsearch suele dispararse por GC pauses bajo presión de heap; mitigación es aumentar `mem_limit` a 6g + `ES_JAVA_OPTS=-Xms3g -Xmx3g`. P99 IMAP fetch suele ser conexión IMAP cold start; mitigación es `watch = True` en parsedmarc.ini para mantener conexión persistente. Estos números se degradan ~2x cuando ES índice supera 50GB sin lifecycle policy aplicada.
Las observaciones operacionales desde este pipeline:
- El cuello de botella habitual es Elasticsearch indexing, no parsedmarc parsing
- IMAP fetch con
watch = True(modo conexión persistente) es 5-10x más rápido que polling cold-start - GeoIP enrichment añade ~30% al tiempo de parsing pero el valor de tener ASN en dashboards justifica el costo
- Sin lifecycle policy de Elasticsearch, los índices crecen sin límite y el rendimiento P99 se degrada notablemente pasados los 30-50GB
Lifecycle policy recomendado (configurar vía Kibana DevTools):
PUT _ilm/policy/dmarc_lifecycle
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": { "max_age": "30d", "max_size": "10gb" },
"set_priority": { "priority": 100 }
}
},
"warm": {
"min_age": "30d",
"actions": {
"shrink": { "number_of_shards": 1 },
"set_priority": { "priority": 50 }
}
},
"cold": {
"min_age": "180d",
"actions": { "set_priority": { "priority": 0 } }
},
"delete": {
"min_age": "730d",
"actions": { "delete": {} }
}
}
}
}
Esta política mantiene 24 meses de data DMARC (suficiente para análisis de tendencias year-over-year), reduce shards en data más vieja para conservar memoria, y borra automáticamente data más vieja de 730 días. La mayoría de organizaciones nunca consultan data DMARC más vieja de 12 meses, así que 24 meses es retención conservadora.
Leyendo reportes agregados: la distribución típica de fuentes
Para un dominio activo de tamaño medio (1-5M emails/mes), la distribución típica de fuentes en reportes RUA después de las primeras 4 semanas se ve así:
- 60-75%: ESP/MTA primario del remitente (SendGrid, Mailgun, Amazon SES, PowerMTA propio, etc.) — esperado y autorizado
- 10-20%: Servicios transaccionales secundarios (Postmark, Stripe email, autenticación 2FA, etc.) — esperado, configurar alineación si falla
- 5-15%: Reenvío legítimo (empleados reenviando emails personales, reglas de reenvío organizacional, gateways académicos/empresariales) — DKIM se preserva si está configurado correctamente
- 1-5%: Listas de correo (Google Groups, Mailman, listservs varios) — DKIM falla por modificación del cuerpo, SPF a menudo pasa pero no alinea
- 0.5-3%: Servicios desconocidos (shadow IT, integraciones de marketing olvidadas, terceros con permisos antiguos) — investigación requerida
- 0.1-2%: Suplantación / abuso (intentos de spoofing de tu dominio) — bloqueados por enforcement una vez configurado
La distribución exacta depende mucho del perfil de la organización. Una empresa SaaS B2B típicamente ve un porcentaje más alto de servicios transaccionales (servicios automated triggered emails, notificaciones del producto). Un retailer B2C ve más reenvíos (consumidores reenviando recibos a familia). Una organización federal/gubernamental ve más suplantación (alvo más atractivo).
La meta operacional fundamental: cada fuente debe caer en una de las primeras tres categorías (autorizada conocida, transaccional secundaria configurada, reenvío legítimo) o en la categoría de bloqueada vía enforcement. Las categorías “desconocidos” y “suplantación” son donde se invierte el tiempo operacional — la primera para investigar y autorizar/bloquear, la segunda para confirmar que enforcement los maneja sin error.
Las seis firmas de patrones de remitente
La habilidad operacional más valiosa en análisis de reportes DMARC es distinguir entre tipos de fallo. Una lectura naive de la data trata todos los fallos DMARC como amenazas equivalentes; la lectura operacionalmente correcta reconoce seis patrones distintos con caminos de remediación diferentes.
Patrón 1 — Remitente autorizado (sin acción necesaria):
- DKIM
passY alineado (d=coincide con header_from) Y SPFpassY alineado - Alto volumen desde un rango IP conocido (tu ESP, tu Workspace, tu servicio transaccional)
- Distribución geográfica coincide con tu infraestructura de envío
Patrón 2 — Remitente legítimo mal configurado (corrección de configuración):
- DKIM
passpero dominiod=no coincide con header_from (fallo de alineación) - O SPF
passpero el dominio del envelope-sender no coincide con header_from - IP de origen pertenece a un servicio conocido (ESP, CRM, plataforma marketing que usas)
- Volumen consistente con patrón de negocio esperado
- Acción: habilitar firma DKIM con tu dominio en el servicio terceros, o añadir su SPF include
Patrón 3 — Cadena de reenvío (sin acción necesaria):
- DKIM
passy alineado (la firma sobrevive al reenvío) - SPF
fail(el reenviador reescribió el envelope sender) - IPs de reenviadores comunes (cs.example.com, edu.gateway.com, servidores de correo de empleadores individuales)
- Bajo volumen por IP, distribuido entre muchas IPs
- Acción: ninguna — DMARC pasa vía alineación DKIM
Patrón 4 — Lista de correo (sin acción necesaria):
- DKIM
fail(el software de la lista modificó el cuerpo) - SPF
pass(el dominio de la lista está autorizado) - Pero ninguno alinea con header_from
- IP de origen pertenece a servicio tipo listserv (mailman.lists.example.org)
- Acción: firma ARC si suscriptores se quejan de entregabilidad; de otra forma, ninguna
Patrón 5 — Intento de suplantación (bloquear, sin cambio de enforcement):
- DKIM
failonone - SPF
failonone - IP de origen desde geografía inusual para tu negocio
- A menudo rangos ISP residenciales, servidores comprometidos, proveedores de hosting conocidos por abuso
- Volumen errático (puede ser 1 mensaje o 50.000)
- Acción: enforcement (
p=quarantineop=reject) maneja esto automáticamente una vez configurado; rastrear en dashboard pero no reaccionar a intentos individuales de suplantación
Patrón 6 — Remitente legítimo desconocido (investigar):
- DKIM
passofail— varía - SPF
passofail— varía - IP de origen pertenece a un proveedor cloud conocido (AWS, Azure, GCP) o un ESP conocido
- Volumen consistente (no errático)
- El patrón que requiere atención: esto es shadow IT, servicios abandonados, o adquisiciones pendientes enviando correo que no sabías
- Acción: identificar el servicio vía reverse DNS + WHOIS, contactar al equipo emisor, decidir autorizar o detener
La matriz debajo colapsa estos patrones en las cuatro señales observables que los operadores usan para triage:
| Categoría | DKIM alineado (1=sí) | SPF alineado (1=sí) | Volumen consistente (1=sí) | IP/servicio conocido (1=sí) |
|---|---|---|---|---|
| Autorizado | 1 | 1 | 1 | 1 |
| Legit mal config | 0 | 0.5 | 1 | 1 |
| Cadena reenvío | 1 | 0 | 0.7 | 0.8 |
| Lista correo | 0 | 0 | 0.7 | 0.7 |
| Suplantación | 0 | 0 | 0.3 | 0.1 |
| Legit desconocido | 0.5 | 0.5 | 0.8 | 0.6 |
Cada patrón puntuado 0-1 en cuatro indicadores. Remitentes autorizados puntúan ~4 total; suplantación puntúa ~0.4 total. Los discriminadores diagnósticos: alineación DKIM, alineación SPF, consistencia de volumen, mapeo IP-a-servicio conocido. El patrón 'legítimo desconocido' es el operacionalmente más difícil — puntúa alrededor de 2.5, requiriendo investigación activa.
El valor diagnóstico del gráfico: un patrón de remitente con altura de barra apilada cerca de 4 (todos los indicadores positivos) es operacionalmente confiable y puede moverse directo a autorizar. Un remitente con altura apilada cerca de 0-0.5 es un patrón claro de suplantación y se queda manejado por enforcement. El rango operacional difícil son alturas apiladas entre 1.5-2.5 — estos requieren investigación activa para determinar si la fuente es shadow IT, un servicio abandonado, o suplantación genuina usando infraestructura comprometida.
Cuándo migrar desde SaaS a autohospedado
El checklist operacional para migración:
Migrar desde SaaS a autohospedado si todos estos son verdaderos:
- Gestionas 8+ dominios activos (cruce de TCO)
- Tienes al menos 0.3 FTE de capacidad de ingeniería para operaciones continuas (setup inicial + mantenimiento mensual + debugging ocasional de incidentes)
- Tienes presupuesto para servidor Linux asignado ($25-50/mes para una instancia Hetzner / OVH / DigitalOcean es suficiente)
- Te sientes cómodo troubleshooting Elasticsearch (presión de heap, límites de shard, gestión de índices)
- Tu caso de uso DMARC es operacional (alertas, dashboards, análisis de tendencias) más que presentación de cumplimiento (resúmenes ejecutivos con atestaciones amigables para auditor)
Quedarse en SaaS si cualquiera de estos es verdadero:
- Gestionas menos de 5 dominios (el TCO favorece SaaS)
- No tienes capacidad de ingeniería para ops autohospedado (el modo de falla del autohospedado roto es operacionalmente peor que el costo del SaaS)
- Tu postura de cumplimiento requiere infraestructura de procesamiento DMARC atestada SOC2 (vendors como Valimail proporcionan esto; autohospedado requiere que atestigües tu propia infraestructura)
- Necesitas workflows de remediación integrados (algunos vendors SaaS auto-actualizan SPF/DKIM vía conectores)
Enfoque híbrido (la opción pragmática para algunas organizaciones):
- Correr autohospedado para monitoreo primario (el dashboard operacional que tu equipo usa diariamente)
- Mantener una cuenta SaaS para reporte ejecutivo (los dashboards pulidos que tu CISO le muestra al board)
- La cuenta SaaS usa un subset de dominios (los de alto valor) para mantener el costo manejable
- La instancia autohospedada cubre todos los dominios para completitud operacional
Caso LATAM: organización colombiana con 12 dominios
Una organización colombiana de servicios financieros con la que trabajamos en 2025 había estado en Dmarcian Pro durante 14 meses, pagando $2.388/año ($199/mes) por 12 dominios protegidos. El detonante de la reevaluación fue doble: el equipo de procurement marcó los reportes DMARC como uno de varios gastos SaaS denominados en USD a revisar para reducción de costos durante un ciclo de devaluación del peso, y el equipo de cumplimiento marcó el requisito PCI DSS v4.0 de marzo 2025 para DMARC en dominios de procesamiento de pagos, lo que extendería el monitoreo a 4 subdominios adicionales relacionados con pagos bajo el pricing por dominio de Dmarcian — empujando la cotización de renovación a $3.180/año ($265/mes) por 16 dominios. La combinación forzó una evaluación explícita build-vs-buy que la presión solo de procurement no había forzado.
Estado pre-migración:
- Dmarcian Pro: $2.388/año USD (≈ 9,3 millones COP a tipo COP 3.900/USD vigente)
- 12 dominios protegidos (4 marketing activos, 6 transaccionales/operacionales, 2 legacy)
- Cotización renovación con compliance PCI DSS: $3.180/año USD (≈ 12,4 millones COP) por 16 dominios
- Capacidad de ingeniería: 1 ingeniero senior de sistemas con ~10 horas/mes disponibles para trabajo DMARC
- Infraestructura existente: Hetzner CX31 (4 vCPU / 8GB / 80GB) corriendo otras herramientas operacionales, capacidad disponible ~50%
Evaluación de migración:
- Costo incremental autohospedado: $0 hosting (CX31 existente tenía capacidad), $0 software (parsedmarc es open source), $200 tiempo ingeniería one-time para setup, ~3 horas/mes mantenimiento continuo ($50/mes a costo cargado de ingeniero)
- Costo anual autohospedado: ~$600 USD (tiempo de ingeniería) vs $3.180 SaaS (cotización post-PCI)
- Ahorro anual: $2.580 USD (≈ 10,1 millones COP)
- ROI sobre tiempo de setup: ~3,5 semanas
Estado post-migración (6 meses después):
- Stack corriendo en CX31 existente, ~15% carga CPU adicional, ~2GB uso RAM adicional
- Setup completado en 8 horas durante 2 días por el ingeniero senior de sistemas
- Semana inicial: 2 incidentes (rotación de credenciales IMAP rompió ingest, el script healthcheck reveló el gap dentro de 24 horas)
- Estado estable: 2-3 horas/mes mantenimiento (usualmente gestión de índices Elasticsearch y ajustes menores de dashboard Kibana)
- Mejora operacional: dashboard customizado a patrones específicos de la organización (cadenas de reenvío LATAM mostrando geografía distintiva), no disponible en dashboards estándar de Dmarcian
- Cumplimiento PCI DSS satisfecho: la atestación de procesamiento autohospedado (con documentación de seguridad nginx/auth/TLS) fue aceptada por el auditor PCI tras revisión técnica
Comparativa TCO anual verificada post-migración:
| Item | Dmarcian (USD) | Autohospedado (USD) | Ahorro |
|---|---|---|---|
| Licencia software/SaaS | 3.180 | 0 | 3.180 |
| Infraestructura hosting | 0 (incluido) | 0 (capacidad existente) | 0 |
| Setup ingeniería (one-time) | 0 | 200 | -200 |
| Ingeniería ongoing (anual) | ~120 (ops integración auth) | ~600 (3h/mes × $50/h) | -480 |
| Total anual | 3.300 | 800 | 2.500 |
La reducción de costo de 76% fue el número titular. Las victorias no económicas:
- Dashboards Kibana custom para patrones específicos LATAM (ej., comportamiento de reenvío outlook.com.br/.co) que Dmarcian no expone
- Soberanía de datos (datos DMARC nunca dejaron infraestructura colombiana, relevante para postura de cumplimiento Habeas Data y Ley 1581 de 2012)
- Dominios ilimitados añadidos sin renegociación de licencia (la organización planeaba 4-6 adquisiciones de dominio durante 2026)
- Documentación PCI DSS bajo control de la organización (no dependiente de attestaciones SOC2 del vendor)
El riesgo de migración que se materializó: el incidente de rotación de credenciales IMAP en semana 2 causó un gap de ingest de 36 horas que el equipo solo notó porque el script healthcheck que implementamos (el script anterior en este post) los alertó. Sin ese healthcheck, estimaron que habrían notado el gap 3-7 días después cuando una revisión rutinaria de dashboard surfaceó datos sospechosamente viejos. El healthcheck, en retrospectiva, fue el componente individual más valioso del setup autohospedado.
Particularidad LATAM observada en el caso: las cadenas de reenvío legítimo en Colombia muestran patrones distintivos vs benchmarks US/EU. Empresa colombiana → empleado reenvía a Gmail/Outlook personal → Gmail/Outlook reenvía a otros. El patrón triple-hop es 2-3x más común en LATAM que en US (donde corporate email + personal email tienden a estar más separados). Esto significa que dashboards Kibana personalizados para reconocer este patrón evitan falsos positivos que dashboards SaaS genéricos a veces marcan como sospechosos.
KPIs operacionales que los artículos de vendor no exponen
Las métricas que deberían driver decisiones operacionales DMARC, con umbrales explícitos:
KPI 1 — Porcentaje de volumen alineado: objetivo ≥98,5% sostenido durante 21 días consecutivos antes de considerar enforcement. Debajo de 95% indica trabajo significativo de alineación de remitentes autorizados pendiente; debajo de 90% significa que tienes remitentes legítimos desconocidos.
KPI 2 — Porcentaje de fuentes desconocidas: objetivo ≤0,5% sostenido. Por encima de 1% dispara investigación de backlog. Calculado como: (records sin IP/dominio fuente reconocible) / (total records) × 100.
KPI 3 — Tiempo a enforcement: objetivo 90-180 días desde publicación inicial DMARC (p=none) a p=reject. Rastreado en 4 etapas: descubrimiento (p=none, monitorear) → trabajo de alineación → testing (p=quarantine con pct bajo) → enforcement (p=reject 100%). Más lento que 6 meses indica cuello de botella organizacional más que complejidad técnica.
KPI 4 — Costo por dominio protegido: objetivo ≤$50/dominio/año para autohospedado a 10+ dominios, ≤$200/dominio/año para SaaS. Por encima de estos umbrales, las decisiones operacionales deberían cuestionarse — consolidar dominios, upgrade infraestructura, o cambiar tooling.
KPI 5 — Días desde última investigación de suplantación: objetivo ciclo de investigación 30 días máximo. Si tu dashboard pasa más de 30 días sin que nadie investigue un patrón de fuente desconocido, la disciplina operacional ha lapsado.
Estos KPIs no son benchmarks estándar de la industria (ningún cuerpo los publica) — son objetivos operacionales que usamos a través de engagements de entregabilidad que producen programas DMARC post-enforcement estables. Los dashboards SaaS estándar presentan porcentajes alineados/no-alineados pero rara vez surfacan porcentaje de fuentes desconocidas como métrica primaria, que es la señal operacional más predictiva de gaps de cumplimiento.
Lo que recomendamos en Blue Spirit
Por transparencia: corremos un stack autohospedado parsedmarc + Elasticsearch + Kibana para nuestro propio monitoreo DMARC, y nuestros clientes de hosting PowerMTA reciben guía operacional DMARC como parte del onboarding estándar. No tenemos relación con Dmarcian, Valimail, EasyDMARC, u otros vendors SaaS DMARC como revendedores.
El framework de recomendación para 2026:
Para 1-4 dominios: quédate en SaaS. EasyDMARC a $15/dominio/mes o el tier gratuito de DMARCReport (1 dominio, 10K reportes) típicamente da el mejor outcome operacional relativo al costo de ingeniería. El TCO no justifica tiempo de setup autohospedado a esta escala.
Para 5-10 dominios con capacidad de ingeniería: evalúa autohospedado seriamente. El TCO cruza en este rango, y los beneficios operacionales (dashboards custom, soberanía de datos, dominios ilimitados) componen. Planifica 8-16 horas setup inicial y ~3 horas/mes ongoing.
Para 10+ dominios sin importar capacidad de ingeniería: autohospedado es casi siempre la respuesta correcta. El pricing SaaS escala linealmente a números que rápidamente exceden el costo de ingeniería operacional dedicada DMARC. Si la capacidad de ingeniería está restringida, la respuesta es contratar/contratista un especialista DMARC, no pagar $20K+/año a un vendor SaaS.
Para organizaciones con requisitos de presentación de cumplimiento (industrias reguladas, sector público, ambientes auditor-driven): híbrido es a menudo correcto. Autohospedado para uso operacional; suscripción SaaS en un subset de dominios de alta visibilidad para reporte ejecutivo y resúmenes amigables al auditor. El costo combinado suele estar bien debajo de SaaS puro a escala.
Particularidad LATAM: la combinación de costo USD denominado, ciclos de devaluación, y compliance compuesto (PCI DSS v4.0 + bulk sender + Habeas Data en jurisdicciones con leyes de protección de datos personales) hace el caso autohospedado desproporcionadamente fuerte para operadores LATAM 8+ dominios. La barrera para LATAM no suele ser técnica — es organizacional: convencer a procurement que un costo USD recurrente puede ser reemplazado por capacidad ingeniería interna paga en moneda local.
Si quieres ayuda evaluando qué enfoque encaja con tu organización, diseñando la arquitectura del stack autohospedado, o migrando desde SaaS a autohospedado preservando data histórica — eso es parte de nuestro engagement de auditoría de entregabilidad. La mayoría de clientes que auditamos corriendo 8+ dominios en SaaS DMARC reporting están gastando sustancialmente más de lo necesario, a menudo sin beneficio operacional más allá de lo que autohospedado proveería.
Resumen honesto
El parsing de reportes agregados DMARC es una de las disciplinas operacionales email donde el camino autohospedado open source produce outcomes operacionales equivalentes o mejores a costo sustancialmente menor que las alternativas SaaS comerciales, para organizaciones con la capacidad de ingeniería para operarlo. parsedmarc + Elasticsearch + Kibana es un stack maduro, producción-grade que ha estado en uso desde 2018 y continúa desarrollo activo en 2026. El caso económico es abrumador por encima de 8 dominios; el caso operacional (dashboards custom, soberanía de datos, dominios ilimitados) es abrumador por encima de 25 dominios. El caso para SaaS permanece fuerte solo para organizaciones debajo de 5 dominios, o aquellas sin capacidad de ingeniería, o con requisitos específicos de presentación de cumplimiento.
La razón más común por la que las organizaciones se quedan en SaaS más allá del cruce TCO racional es inercia operacional — el sistema está corriendo, los dashboards están poblados, cambiar se siente arriesgado. La realidad honesta es que la migración es técnicamente directa (8-16 horas para un operador experimentado con el stack docker-compose en este post), la soberanía de datos se preserva, los dashboards custom suelen ser un step up sobre dashboards SaaS genéricos, y los ahorros componen año a año. Los operadores que han hecho la migración rara vez se arrepienten; los operadores que se han quedado en SaaS a 25+ dominios suelen estar pagando $10-50K+/año por outcomes que podrían replicar autohospedado por $1-3K/año.
La disciplina operacional que determina el éxito DMARC no es la elección de tooling — ambos caminos producen capacidades core equivalentes. Es la consistencia del workflow del operador: revisión semanal de dashboard, investigación mensual de fuentes desconocidas, reporte trimestral de KPIs, tratar remitentes desconocidos como item de backlog en lugar de ignorarlos. Si ese workflow corre en Dmarcian o en un Kibana autohospedado no cambia la disciplina requerida. La decisión de tooling debería estar driven por economía y encaje operacional; la decisión de disciplina es lo que realmente determina si tu programa DMARC alcanza enforcement y se queda ahí.
Para LATAM específicamente: la economía favorece autohospedado más fuerte que en mercados USD-nativos porque el costo recurrente USD compite con devaluación de moneda local, mientras el costo de ingeniería pagado en moneda local es contracíclico al costo SaaS. Para organizaciones LATAM 8+ dominios, la pregunta operacional no debería ser “¿deberíamos migrar a autohospedado?” — debería ser “¿cuál es nuestro plazo para migrar y qué necesitamos para ejecutarlo bien?”. El framework operacional, los componentes técnicos, y los KPIs en este post son los inputs para construir ese plan de migración con confianza.
Lecturas relacionadas
El progreso enforcement DMARC desde p=none a p=reject está cubierto en guía supervivencia DMARC 2026. Para el stack de observabilidad unificada más amplio donde DMARC parsing encaja ver observabilidad email unificada con Grafana, parsedmarc, Postmaster, SNDS. El baseline autenticación sobre el cual DMARC enforce alineación está en nuestra guía autenticación 2026. Para SPF flattening que soporta alineación DMARC sin servicios pagados ver fix SPF 10-lookup sin servicio pago. La rotación de claves DKIM que produce continuidad signal DMARC está detallada en rotación de claves DKIM en PowerMTA + OpenDKIM.
¿Algo que deberíamos escribir? Manda tu tema a [email protected].