Envía un formulario a tu email

Envía un formulario a tu email6 min de lectura

Envía un formulario HTML a tu email sin PHP

Sustituye un script contact.php que llama a mail() por un formulario que envía a un endpoint alojado, conservando tus nombres de campo, tu página de agradecimiento y las respuestas.

Preet SutharFundador, Ikiform

Cambia el action del formulario de tu script PHP a la URL de un backend de formularios, conserva los nombres de campo y borra el script. El backend hace lo que hacía mail(), más lo que nunca hizo bien: filtrar spam, guardar los envíos y enviar correo que no acaba en spam. Funciona en hostings estáticos donde PHP no se puede ejecutar.

Qué cambia aquí

La mayoría de los formularios de contacto en PHP son las mismas veinte líneas, copiadas de un tutorial hace años. Leen $_POST, construyen una cadena, llaman a mail() y redirigen. Este es uno típico:

contact.php
<?php
$name = $_POST["name"];
$email = $_POST["email"];
$phone = $_POST["phone"];
$message = $_POST["message"];

$to = "hello@example.com";
$subject = "Website enquiry from $name";
$body = "Name: $name\nEmail: $email\nPhone: $phone\n\n$message";
$headers = "From: $email\r\nReply-To: $email";

if (mail($to, $subject, $body, $headers)) {
  header("Location: /thanks.html");
} else {
  echo "Sorry, something went wrong.";
}

Parece inofensivo, y funcionaba cuando se escribió. Hoy falla de cuatro maneras, y solo la primera es evidente:

ProblemaPor qué pasa
No hay PHP en el hostingGitHub Pages, Netlify, Vercel, Cloudflare Pages y S3 sirven archivos; no ejecutan PHP. El formulario envía a un archivo que nunca se ejecuta, y recibes un 404 o un 405.
El correo acaba en spam o desaparecemail() pasa el mensaje al programa de correo local del servidor. La cabecera From: dice ser la dirección del visitante, pero el correo sale del servidor de tu hosting, así que falla las comprobaciones SPF y DMARC del dominio del visitante. Gmail y Outlook lo filtran o lo rechazan, muchas veces sin avisar.
Inyección de cabeceras$email entra en las cabeceras sin comprobar. Un bot que envía un valor con un salto de línea puede añadir su propia línea Bcc: y usar tu formulario para enviar spam, lo que mete la IP de tu hosting en listas de bloqueo.
No se guarda nadaSi se pierde el email, se pierde el mensaje. No hay registro, ni filtro antispam, ni forma de revisar las consultas del mes pasado.

Podrías arreglar cada problema: validar cada valor, enviar a través de un proveedor SMTP con una librería como PHPMailer, configurar SPF y DKIM para tu dominio, añadir un honeypot y un límite de frecuencia, y registrar en una base de datos. Es un proyecto razonable si ya usas PHP. Si prefieres no hacerlo, pasa el trabajo a un backend de formularios.

El mismo formulario con mail() de PHP y con un backend de formularioscon contact.phpcon un backend de formulariostu formularioaction="/contact.php"mail()From: el visitante,enviado por tuhostingcarpeta de spamfalla SPF y DMARCtu formulariomismos campos, nuevoactionIkiformfiltra spam, loguardatu bandejaReply-To: elvisitanteenvíocorreo localenvíoemailEl mismo formulario con mail() de PHP y con un backend de formularioscon contact.phpcon un backend de formulariostu formularioaction="/contact.php"mail()From: el visitante, enviado portu hostingcarpeta de spamfalla SPF y DMARCtu formulariomismos campos, nuevo actionIkiformfiltra spam, lo guardatu bandejaReply-To: el visitanteenvíocorreo localenvíoemail
  1. Con contact.php, el formulario envía a tu hosting y mail() manda un mensaje que dice venir del visitante. Los servidores receptores ven un remitente que no coincide con el dominio y lo clasifican como spam o lo descartan.
  2. Con un backend de formularios, el formulario envía los mismos campos a Ikiform. Ikiform manda el email desde su propio dominio y pone la dirección del visitante en Reply-To, que es justo para lo que sirve Reply-To.
La solución a la entregabilidad no es un script mejor. Es enviar desde un dominio que tiene permiso para enviar.

Saca el formulario de PHP

Conserva los nombres de campo tal cual. Solo cambia el action, más dos inputs ocultos:

Antes
<form action="/contact.php" method="post">
  <input name="name" required />
  <input name="email" type="email" required />
  <input name="phone" type="tel" />
  <textarea name="message" required></textarea>
  <button>Send</button>
</form>
Después
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <input name="name" required />
  <input name="email" type="email" required />
  <input name="phone" type="tel" />
  <textarea name="message" required></textarea>
  <input type="hidden" name="_redirect" value="https://example.com/thanks.html" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send</button>
</form>

Después, ubica cada cosa que hacía el script en su nuevo sitio:

En contact.phpAhora
$to = "hello@example.com"Destinatarios en los ajustes de Notifications del formulario
header("Location: /thanks.html")El input oculto _redirect, o Redirect after submit en los ajustes del formulario
Reply-To: $emailAutomático, porque el campo se llama email
$subject = "Website enquiry from $name"Fijo: New submission: <form name>. Llama al formulario "Consulta web" para mantener el texto
echo "Sorry, something went wrong."La página de error de Ikiform para un envío normal, o tu propio mensaje con fetch
Comprobaciones que nunca escribisteEl honeypot _gotcha, la puntuación de spam, los límites de frecuencia y la validación de campos
  • Añade tu dominio en Allowed domains. _redirect solo funciona con una URL https: en uno de esos dominios.
  • Borra contact.php del servidor cuando el nuevo formulario funcione. Un script olvidado sigue siendo un relay de correo abierto para los bots que recuerdan la URL.
  • Si te pasaste a un hosting estático, la antigua URL /contact.php ya no existe. Los bots que envían directamente a ella reciben un 404, y no pasa nada.
Si tu formulario era un plugin de WordPress en lugar de un script, se aplica la misma idea. La guía de WordPress muestra dónde poner el formulario en un tema de bloques.

Comprueba que funciona

  1. En Allowed domains del formulario, añade el dominio de tu sitio, más localhost mientras desarrollas. Déjalo vacío para aceptar envíos desde cualquier lugar.
  2. Envía el formulario en tu página publicada. Llegas a tu antigua thanks.html.
  3. Abre Submissions en el panel. El nuevo envío está ahí con todos los campos que mandaste.
  4. Abre el email. Viene de Ikiform, no de la dirección del visitante, y no está en spam. Añade el remitente a tus contactos para que los siguientes tampoco lo estén.
  5. Pulsa Reply. La dirección del visitante está en la línea To.
  6. Envía con el honeypot relleno, _gotcha=bot. Sigue recibiendo una respuesta de éxito, pero el envío se guarda como spam y no manda ningún email ni webhook.

Detalles a tener en cuenta

  • Nombres antiguos con corchetes. Los formularios PHP suelen usar nombres como contact[email]. Ikiform los guarda tal cual, pero el reply-to solo sale de un campo llamado email o de unas pocas variantes parecidas. Renombra el campo o añade _replyto.
  • El asunto no puede incluir el nombre. El asunto del script llevaba el nombre del visitante. El asunto de la notificación es fijo, y _subject se pasa a los webhooks y a la API sin cambiar el email.
  • Codificación de caracteres. Los scripts con mail() solían estropear los acentos porque nunca definían un charset. El email de Ikiform es UTF-8, así que los nombres en cualquier alfabeto llegan intactos.
  • Varias direcciones en $to. Una lista separada por comas en el script pasa a ser destinatarios separados en el panel. Las direcciones externas confirman mediante un enlace antes de recibir nada. Consulta varios destinatarios.

Si algo sale mal

ProblemaQué hacer
El navegador llega a la página de agradecimiento de Ikiform en lugar de a la tuya_redirect se ignora salvo que su dominio esté en Allowed domains y sea una URL https:. Añade el dominio o configura Redirect after submit en los ajustes del formulario.
403 origin_not_allowed, o todos los envíos acaban en spamEl dominio de la página no está en Allowed domains del formulario. Añádelo, más localhost para las pruebas locales. Los subdominios de un dominio de la lista están permitidos.
El formulario sigue enviando al archivo PHPUna página en caché o una segunda copia del formulario, como un include del pie de página, aún tiene el action antiguo. Busca contact.php en todo el sitio.
El envío está en el panel, pero no llegó ningún email ni webhookSe guardó como spam. El spam no envía nada. Ábrelo en el filtro Spam para ver los motivos y márcalo como no spam para enviar su email y sus webhooks.

Preguntas

¿Te atascaste en un paso o quieres una guía para tu caso? Escribe a hello@ikiform.com.