Contact Form 7 webhook WordPress es la combinación que resuelve un problema que arrastra el plugin desde hace años: la dependencia de la función mail() de PHP para enviar formularios, que falla silenciosamente sin registro ni reintento. Con más de 5 millones de instalaciones activas, CF7 sigue usando email como transporte por defecto, y cuando ese email no llega — por problemas de SPF, DKIM o simplemente porque el servidor no tiene configurado un MTA decente — el envío se pierde y nadie se entera.
En 30 segundos
- Contact Form 7 depende de
mail()de PHP por defecto, que tiene un timeout de 5 segundos en WordPress y si falla no reintenta ni registra nada - Los webhooks envían los datos del formulario como JSON a cualquier endpoint (CRM, Slack, API propia) con código de respuesta HTTP verificable
- Plugins como CF7 to Webhook (30,000+ instalaciones) soportan POST/GET/PUT/DELETE con headers personalizados
- CF7 tuvo vulnerabilidades críticas: CVE-2020-35489 (CVSS 10.0, upload no restringido) y XSS reflejado en la versión 5.9
- Para entrega garantizada se necesita cola de jobs con reintentos exponenciales y system cron real, no WP-Cron
El problema crónico: por qué Contact Form 7 pierde emails
Si alguna vez administraste un WordPress con CF7 y un cliente te dijo «no me llegan los formularios», ya sabés de qué hablo. El problema de fondo es arquitectónico: CF7 usa wp_mail(), que a su vez llama a mail() de PHP. Esa función depende del MTA del servidor — y en hostings compartidos, ese MTA suele estar mal configurado o directamente bloqueado.
El resultado es predecible. Los emails caen en spam, rebotan por falta de registros SPF/DKIM/DMARC, o directamente se pierden en el void sin que WordPress registre nada. Como documenta WP Mail SMTP, el timeout por defecto de WordPress es de 5 segundos — si el envío no se completa en ese lapso, falla silenciosamente. Sin log. Sin reintento. Sin notificación.
Lo peor: el usuario que llenó el formulario ve el mensaje de «enviado correctamente» porque CF7 no verifica si el email efectivamente llegó a destino.
Webhooks vs. email vs. SMTP: cuándo conviene cada uno
Antes de saltar a webhooks, vale aclarar que SMTP autenticado (vía WP Mail SMTP u otro plugin) resuelve el problema de autenticación. Tu servidor manda el email a través de Gmail, SendGrid o lo que uses, con SPF y DKIM bien configurados. Eso mejora la entrega enormemente.
Pero sigue siendo email. Y el email tiene limitaciones inherentes: no sabés en tiempo real si llegó, no podés reintentar automáticamente si el servidor de destino está caído, y no podés rutear los datos a múltiples destinos sin configurar reglas de reenvío. Si te interesa, podés leer más sobre nuestra guía sobre firewalls y microsegmentación.
Los webhooks cambian la ecuación. Mandás un POST con JSON a un endpoint HTTP y recibís un código de respuesta: 200 llegó, 500 falló, timeout reintentá. Podés verificar la entrega, implementar reintentos con backoff exponencial, y mantener un log completo de cada intento.
| Criterio | PHP mail() | SMTP autenticado | Webhooks |
|---|---|---|---|
| Autenticación | Ninguna | SPF/DKIM/DMARC | API key / Bearer token |
| Verificación de entrega | No | Parcial (bounces) | Sí (código HTTP) |
| Reintentos automáticos | No | Depende del SMTP | Sí (configurable) |
| Logging | No | Depende del plugin | Completo (request/response) |
| Integración con servicios | Solo email | Solo email | CRM, Slack, APIs, DBs |
| Complejidad de setup | Ninguna | Media | Media-Alta |

La respuesta corta: si solo necesitás que llegue un email de notificación, SMTP autenticado alcanza. Si necesitás garantía de entrega, logs de auditoría, o integración con sistemas externos, webhooks.
Plugins para conectar CF7 con webhooks
Hay dos opciones maduras que vale la pena evaluar.
CF7 to Webhook
CF7 to Webhook es el más popular, con más de 30,000 instalaciones activas y versión 5.0.0. Soporta POST, GET, PUT y DELETE, envía los datos como JSON, permite headers personalizados y múltiples URLs de destino. También tiene soporte para formularios multi-step y un template nativo para Slack.
Eso sí: no incluye sistema de reintentos robusto. Si el endpoint responde con error o no responde, el envío se pierde igual que con email. Lo usás para la conectividad, pero la resiliencia la tenés que resolver por otro lado.
RT Webhook for Contact Form 7
RT Webhook tiene una ventaja interesante: logging de las últimas 10 requests con URLs, headers, payloads y respuestas completas. Eso te da visibilidad real de qué pasó con cada envío. Además incluye conditional logic (enviá el webhook solo si cierto campo tiene cierto valor) y field mapping dinámico.
Para debugging y auditoría básica, RT Webhook le gana a CF7 to Webhook. Para integraciones complejas con múltiples endpoints, CF7 to Webhook tiene más flexibilidad.
Implementación custom: webhooks con reintentos y logs reales
Ninguno de los plugins anteriores resuelve el problema de fondo: qué pasa cuando el endpoint falla. Para eso necesitás una cola de jobs con reintentos. La arquitectura tiene tres componentes: Si te interesa, podés leer más sobre los feature plugins gratuitos de WordPress.
- Tabla de jobs en la base de datos: almacena endpoint, payload, headers, cantidad de intentos, próximo reintento, estado (pending/processing/completed/failed/dead)
- Listener enganchado al hook
wpcf7_mail_sent: cuando CF7 procesa un formulario, encola el job en vez de (o además de) mandar email - Worker que ejecuta vía cron: levanta jobs pendientes, hace el
wp_remote_post(), actualiza el estado según la respuesta
El backoff exponencial es clave: primer reintento a 1 minuto, segundo a 2, tercero a 4, cuarto a 8, quinto a 16. Después de 5 intentos fallidos, el job pasa a estado «dead-letter» — no se reintenta más, pero queda registrado para revisión manual. Cada intento loguea URL, headers enviados, payload, response code, body de respuesta y timestamp.
Acá viene lo bueno: con esta arquitectura no perdés un solo envío. Si tu CRM está caído 10 minutos, los formularios se encolan y se despachan cuando vuelva. Si hay un error 500 intermitente, los reintentos lo absorben.
WP-Cron no alcanza para webhooks críticos
WP-Cron no es un cron real. Se dispara cuando alguien visita el sitio. Si tu WordPress tiene poco tráfico — ponele, un sitio corporativo que recibe 50 visitas por día — los jobs encolados pueden tardar horas en ejecutarse.
La solución es desactivar WP-Cron y usar el cron del sistema operativo. Agregás esta línea en wp-config.php:
define('DISABLE_WP_CRON', true);
Y configurás un cron real cada minuto que llame a wp-cron.php. En un servidor con acceso SSH: Si te interesa, podés leer más sobre los parches críticos de marzo en AWS.
* * * * * wget -q -O /dev/null https://tusitio.com/wp-cron.php?doing_wp_cron
Si usás un hosting en donweb.com con cPanel, lo configurás desde la sección «Cron Jobs» sin tocar la terminal. Con esto, tus webhooks se despachan cada minuto independientemente del tráfico del sitio.
Seguridad del webhook: no abras la puerta de par en par
Un webhook mal configurado es un vector de ataque. Estás exponiendo un endpoint que recibe datos desde tu WordPress — si alguien descubre la URL y no tiene autenticación, puede inyectar datos falsos en tu CRM o en tu base de datos.
Reglas mínimas:
- HTTPS siempre — los datos del formulario viajan en el payload y pueden incluir información sensible
- Autenticación con API key o Bearer token en los headers, nunca en la URL como query parameter
- Sanitizá los datos del formulario antes de enviarlos — CF7 no escapa HTML por defecto en los valores
- Validá la respuesta del endpoint: si no es 2xx, logueá y reintentá
- Considerá HMAC signature para que el receptor verifique que el request viene de tu WordPress y no fue manipulado en tránsito
Recordá que CF7 tiene un historial de vulnerabilidades que no es menor. La CVE-2020-35489 fue un CVSS 10.0 perfecto: upload de archivos sin restricción en la versión 5.3.1, que permitía subir PHP al servidor. Más recientemente, Wordfence documentó un XSS reflejado en la versión 5.9. Cuantos menos plugins tengas procesando datos de formularios, menor tu superficie de ataque.
Casos prácticos: Slack, CRM y APIs propias
El payload JSON que envía CF7 to Webhook tiene esta estructura básica:
{"your-name": "Juan Pérez", "your-email": "juan@ejemplo.com", "your-message": "Consulta sobre..."}
A partir de ahí, las integraciones más comunes:
Notificaciones a Slack
CF7 to Webhook tiene un template nativo. Apuntás el webhook a la URL de un Incoming Webhook de Slack y cada formulario llega como mensaje al canal que elijas. Útil para equipos de ventas que necesitan respuesta inmediata.
CRM y automatización
Con Make.com o n8n podés recibir el webhook y rutear los datos a HubSpot, Salesforce, Google Sheets, Notion o lo que uses. La ventaja sobre Zapier es que n8n es self-hosted y no pagás por ejecución — algo a considerar si tenés un sitio con volumen alto de formularios. Si te interesa, podés leer más sobre el ataque a Trivy en GitHub Actions.
API REST propia
Si tenés un backend propio, recibís el POST, validás el token en el header, y procesás como necesites. Podés guardar en base de datos, disparar workflows internos, o alimentar un dashboard de leads. Acá es donde la implementación custom con reintentos tiene más sentido: tu API puede caer y no querés perder leads.
Monitoreo: cómo saber si tus webhooks funcionan
De nada sirve armar toda la infraestructura si no monitoreás. RT Webhook te da las últimas 10 requests — es un punto de partida, pero para producción necesitás más.
Lo mínimo viable: una tabla en WordPress que registre cada request con timestamp, endpoint, response code y body de respuesta. Un WP-CLI command o una página en el admin que te muestre los últimos 50 envíos con filtro por estado. Y una alerta — puede ser un email, un mensaje a Telegram, lo que sea — cuando un webhook falle 3 veces consecutivas.
Para testing usá webhook.site o RequestBin: te dan un endpoint temporal donde podés inspeccionar exactamente qué manda tu WordPress. Validá headers, payload, encoding. Después apuntá al endpoint real.
Errores comunes
Confiar en que «el email llegó» porque CF7 mostró el mensaje verde
CF7 muestra «Tu mensaje fue enviado con éxito» cuando wp_mail() no devuelve false. Eso no significa que el email llegó — significa que PHP no tiró error al intentar mandarlo. Son cosas muy distintas. Con webhooks al menos tenés un response code que verificar.
Usar WP-Cron para jobs críticos sin desactivar el pseudo-cron
Si encolás webhooks con reintentos pero dejás WP-Cron en modo default (disparado por visitas), los reintentos se acumulan y se despachan todos juntos cuando alguien entra al sitio. En el mejor caso, tu endpoint recibe un pico de requests. En el peor, los jobs expiran antes de ejecutarse. Si te interesa, podés leer más sobre comparativa de plugins de seguridad para WordPress.
Exponer el webhook endpoint sin autenticación
Vi esto más de una vez: el endpoint del CRM acepta POST sin API key porque «total es interno». Alguien descubre la URL (no es difícil, basta inspeccionar el tráfico de red del formulario) y empieza a inyectar leads falsos. Siempre autenticá, aunque sea con un token estático en un header custom.
Preguntas Frecuentes
¿Puedo usar webhooks y email al mismo tiempo en CF7?
Sí. Los plugins de webhook se enganchan al evento de envío sin desactivar el email. Podés mantener la notificación por email como backup y usar el webhook como canal principal. Lo ideal es tener ambos hasta que verifiques que el webhook funciona de forma estable.
¿CF7 to Webhook es gratis o tiene versión premium?
La versión gratuita en wordpress.org cubre POST/GET con JSON y headers personalizados. La versión premium agrega soporte para formularios multi-step, conditional logic avanzado y prioridad en soporte. Para la mayoría de los casos de uso, la versión free alcanza.
¿Cómo pruebo si mi webhook funciona antes de ponerlo en producción?
Usá webhook.site: te da una URL temporal donde podés ver exactamente qué headers, payload y método recibe. Configurá esa URL en CF7 to Webhook, mandá un formulario de prueba, y verificá que los datos lleguen correctos. Después reemplazá por la URL real.
¿Los webhooks funcionan con hosting compartido?
Sí, wp_remote_post() funciona en cualquier hosting que permita conexiones HTTP salientes (prácticamente todos). La limitación está en WP-Cron: en hosting compartido no siempre podés configurar un system cron real, así que los reintentos dependen del tráfico del sitio. Si tu hosting lo permite, configurá el cron desde cPanel.
Conclusión
Contact Form 7 sigue siendo el plugin de formularios más usado en WordPress, pero su sistema de envío por email es un punto ciego que muchos administradores ignoran hasta que pierden un lead importante. Reemplazar o complementar el email con webhooks te da algo que mail() de PHP nunca va a darte: verificación de entrega, reintentos automáticos y un log de auditoría completo.
Si tu caso es simple — notificaciones a Slack o integración con un CRM — CF7 to Webhook o RT Webhook resuelven sin escribir código. Si necesitás garantía de entrega con reintentos, la implementación custom con cola de jobs y system cron es el camino. En cualquier caso, dejá de confiar en que el email «probablemente llegó».