# 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.

Publicado el 2026-10-25 · https://ikiform.com/es/guides/send-form-to-email/without-php

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
<?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:

| Problema | Por qué pasa |
| --- | --- |
| No hay PHP en el hosting | GitHub 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 desaparece | `mail()` 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 nada | Si 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.

Diagrama: El mismo formulario con mail() de PHP y con un backend de formularios

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`:

```html
<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`:

```html
<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.php | Ahora |
| --- | --- |
| `$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: $email` | Automá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 escribiste | El 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](https://ikiform.com/es/docs/guides/wordpress.md) 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](https://ikiform.com/es/guides/send-form-to-email/multiple-recipients.md).

## Si algo sale mal

| Problema | Qué 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 spam | El 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 PHP | Una 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 webhook | Se 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

### ¿Mi formulario antiguo seguirá funcionando mientras hago el cambio?

Sí. El script antiguo sigue funcionando hasta que cambies el action del formulario, así que puedes probar primero el nuevo endpoint en una copia de la página y después hacer el cambio y borrar el script.

### ¿Puedo enviar un formulario HTML a mi email sin PHP?

Sí. Apunta el action del formulario a un backend de formularios en lugar de a un script PHP. El backend recibe el envío y te manda un email, así tu sitio puede ser HTML simple en cualquier hosting estático.

### ¿Por qué los emails de mail() de PHP van a spam?

Los scripts suelen poner en la cabecera From la dirección del visitante, pero el correo sale del servidor de tu hosting. Eso falla las comprobaciones SPF y DMARC del dominio del visitante, así que Gmail y Outlook lo tratan como falsificado. Un backend de formularios envía desde su propio dominio y pone al visitante en Reply-To.

### ¿Tengo que cambiar los nombres de los campos?

No. Ikiform guarda los nombres que envíes, sean cuales sean. Llama al campo del email email, email_address, your_email, reply_to o contact_email, o añade un campo _replyto, para que las respuestas vayan al visitante.

### ¿Es mejor opción PHPMailer con SMTP?

Resuelve la entregabilidad si envías a través de un proveedor con tu dominio configurado para SPF y DKIM. Sigues necesitando un hosting PHP, validación, filtro antispam y un sitio donde guardar los mensajes. Es una buena opción si ya mantienes código PHP.

## Más guías

- [Envía un formulario a tu email](https://ikiform.com/es/guides/send-form-to-email.md): Recibe cada envío de formulario en tu bandeja sin servidor de correo: por qué fallan mailto: y mail() de PHP, y una configuración que filtra spam y te deja responder.
- [A Gmail](https://ikiform.com/es/guides/send-form-to-email/gmail.md): Recibe los envíos de formularios en Gmail sin enlaces mailto:, contraseñas de aplicación ni Apps Script; luego etiquétalos, mantenlos fuera del spam y responde desde Gmail.
- [Responde desde tu bandeja](https://ikiform.com/es/guides/send-form-to-email/reply-to.md): Haz que Reply en una notificación de formulario responda a quien lo rellenó: qué nombres de campo funcionan, cuándo usar _replyto y por qué se pierden las respuestas.
- [Varios destinatarios](https://ikiform.com/es/guides/send-form-to-email/multiple-recipients.md): Envía un formulario por email a todo tu equipo, o dirige cada mensaje a la persona adecuada según el tema, sin dejar que el propio formulario elija quién recibe el correo.
- [Alternativa a EmailJS](https://ikiform.com/es/guides/send-form-to-email/emailjs-alternative.md): Saca un formulario de contacto de EmailJS: por qué las claves de email en el navegador son un riesgo, qué cambia en tu código y qué pierdes, como la respuesta automática.
- [Next.js](https://ikiform.com/es/guides/send-form-to-email/nextjs.md): Dos formas de enviar por email un formulario de Next.js con una Server Action: enviarlo tú con Resend o Nodemailer, o reenviarlo a un backend de formularios, comparadas con honestidad.
