Guías

Guías16 min de lectura

Envía los envíos de formularios HTML a tu email

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.

Preet SutharFundador, Ikiform

Un formulario HTML no puede enviar emails por sí solo, porque el navegador no tiene forma de hablar con un servidor de correo. Apunta el action del formulario a un backend de formularios, que recibe el envío, filtra el spam, lo guarda y te manda un email a ti y a tu equipo. Llama email al campo del email y, al pulsar Reply en tu bandeja, responderás directamente a quien rellenó el formulario.

La mayoría de los sitios necesitan una sola cosa de un formulario de contacto: que el mensaje llegue a una bandeja que alguien lea. Resulta más difícil de lo que parece. HTML tiene un elemento <form>, pero no una forma de enviar correo, y los viejos atajos le devuelven el trabajo al visitante o acaban en spam. Esta guía explica por qué, compara las opciones con honestidad y monta un formulario que te envía un email en cualquier sitio y con cualquier stack.

Por qué un formulario no puede enviar emails por sí solo

Cuando un visitante pulsa Send, el navegador hace una petición HTTP a la URL del action del formulario. Es todo lo que puede hacer un formulario. Enviar un email requiere una conversación SMTP con un servidor de correo, desde una máquina en la que confíe el servidor receptor. Un navegador no puede abrir esa conexión y, aunque pudiera, el correo desde el portátil de un visitante cualquiera se rechazaría. Así que siempre hay algo en un servidor entre el formulario y tu bandeja: tu propio código, un script en tu hosting o un servicio.

Con un backend de formularios, ese algo es una URL. El formulario envía a https://ikiform.com/f/<id> e Ikiform hace el resto:

Cómo un envío de formulario se convierte en un email en tu bandejatuformulariocualquiersitio o stackIkiformvalida,puntúa spam,guardaun emailpordestinatarioreply-to esel remitentetu bandejaReplyresponde alvisitanteguardadocomo spamsin email niwebhookenvíono es spamsegundospuntuación de spam alcanzadaCómo un envío de formulario se convierte en un email en tu bandejatu formulariocualquier sitio ostackIkiformvalida, puntúa spam,guardaun email pordestinatarioreply-to es elremitentetu bandejaReply responde alvisitanteguardadocomo spamsin email niwebhookenvíono es spamsegundospuntuación de spam alcanzada
  1. El visitante envía tu formulario, y el navegador o tu servidor lo manda a tu endpoint de Ikiform.
  2. Ikiform comprueba los campos con la definición del formulario, puntúa el envío como posible spam y lo guarda.
  3. Un envío que alcanza la puntuación de spam se guarda como spam. Recibe la misma respuesta de éxito, pero no envía ningún email ni webhook.
  4. Cualquier otro envío manda un email a cada destinatario, con la dirección del visitante como reply-to.
  5. El email llega a tu bandeja segundos después. Al pulsar Reply respondes al visitante.
El visitante nunca ve una dirección de email ni abre una app de correo. Lo único que hay en tu página es un formulario.

Seis formas de llevar un formulario a tu bandeja

Cada una le sirve a alguien. La tabla trata de lo que te cuesta cada una cuando visitantes reales, y bots reales, empiezan a usar el formulario.

OpciónBueno paraContras
action="mailto:you@example.com"Sin servidor, sin cuenta, un solo atributo.No se envía nada. El navegador abre la app de correo del visitante con un borrador, o no hace nada si no tiene ninguna configurada. Tu dirección queda en la página al alcance de los scrapers. Consulta la guía de Gmail.
Un script PHP con mail()Funciona en casi cualquier hosting PHP compartido, sin terceros.Depende de la configuración de correo del hosting, y el correo que dice venir de tu dominio suele fallar SPF o DMARC y acaba en spam. Sin filtro antispam, sin almacenamiento y sin PHP en absoluto en los hostings estáticos. Consulta sin PHP.
Un SDK de email en el navegador, como EmailJSSin servidor. Plantillas de email que diseñas en su panel.Las claves y los ids de plantilla están en el JavaScript de tu página, así que cualquiera puede enviar tus plantillas con su propio texto. Consulta la alternativa a EmailJS.
Tu propia ruta más una API de email, como Resend, Postmark, Amazon SES o Nodemailer por SMTPControl total: tu asunto, tu HTML, una confirmación al visitante.Tienes que construir la validación, el filtro antispam, los límites de frecuencia, el almacenamiento y los reintentos, verificar un dominio de envío y necesitas un servidor incluso para un sitio estático. Consulta la guía de Next.js.
Google Apps Script como app webFunciona con una cuenta de Google que ya tienes.Las cuotas de scripts limitan a cuántos destinatarios puede enviar al día, la URL no tiene protección antispam y el script lo mantienes tú.
Un backend de formularios, como Ikiform, Formspree o Web3FormsUna URL en action. Filtro antispam, almacenamiento y email sin servidor.El diseño y el asunto del email los pone el servicio. Con Ikiform, nunca se envía nada por email al visitante.

Si necesitas un email totalmente con tu marca, o una confirmación al visitante, escribe tu propia ruta con una API de email. Si quieres el mensaje en tu bandeja y poder responder, sin spam, un backend de formularios es lo que menos código requiere. El resto de esta guía usa Ikiform.

El formulario

Tres campos cubren la mayoría de los formularios de contacto: quién es, a dónde responder y qué quiere. Elige tu stack abajo; la elección se mantiene en todos los ejemplos de código de estas guías.

Este formulario funciona sin nada de JavaScript: el navegador lo envía, Ikiform te manda un email y el visitante llega a la página de _redirect. Cada campo tiene debajo un hueco vacío para errores, que usa el script de abajo.

contact.html
<form id="contact" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST">
  <label for="name">Name</label>
  <input id="name" name="name" autocomplete="name" required maxlength="120" />
  <p data-error="name"></p>

  <label for="email">Your email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />
  <p data-error="email"></p>

  <label for="message">Message</label>
  <textarea id="message" name="message" rows="6" required minlength="10"></textarea>
  <p data-error="message"></p>

  <input type="hidden" name="page" value="/contact" />
  <input type="hidden" name="_redirect" value="https://example.com/contact/sent" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send message</button>
  <p id="contact-status" role="status"></p>
</form>

El script mantiene al visitante en la página. Envía con fetch, escribe cada error del servidor debajo de su campo y cambia el formulario por una línea que repite la dirección a la que responderás, para que una errata sea fácil de detectar.

contact.js
const form = document.getElementById("contact");
const status = document.getElementById("contact-status");
const button = form.querySelector("button");

form.addEventListener("submit", async (event) => {
  event.preventDefault();
  for (const slot of form.querySelectorAll("[data-error]")) slot.textContent = "";
  button.disabled = true;
  status.textContent = "Sending";

  try {
    const response = await fetch(form.action, {
      method: "POST",
      headers: { Accept: "application/json" },
      body: new FormData(form),
    });
    const result = await response.json();
    if (result.ok) {
      const email = form.elements.namedItem("email").value;
      const done = document.createElement("p");
      done.setAttribute("role", "status");
      done.textContent = `Sent. We'll reply to ${email}.`;
      form.replaceWith(done);
      return;
    }
    for (const [field, messages] of Object.entries(result.error.fields ?? {})) {
      const slot = form.querySelector(`[data-error="${field}"]`);
      if (slot) slot.textContent = messages[0];
    }
    status.textContent = result.error.fields ? "Check the fields above." : result.error.message;
  } catch {
    status.textContent = "Couldn't send. Check your connection and try again.";
  }
  button.disabled = false;
});
  • Sustituye frm_xxxxxxxxxxxxxxxx por el id de tu formulario, que está en el panel.
  • name="email" convierte ese campo en la dirección reply-to del email de notificación. Conserva el nombre aunque la etiqueta diga "Tu email".
  • page es un campo oculto normal. Aparece en el email, así sabes desde qué página llegó el mensaje.
  • _gotcha es el honeypot. Las personas nunca lo ven; un bot que lo rellena se guarda como spam y no se envía ningún email.
  • _redirect solo funciona con una URL https: en uno de los Allowed domains del formulario. Omítelo y configura Redirect after submit en los ajustes del formulario, o Ikiform muestra su propia página de agradecimiento.

Las guías de frameworks van más allá: Next.js, Astro, SvelteKit, Nuxt, React, Vue y HTML simple. Los creadores de sitios como Webflow y Carrd tienen sus propias páginas, y la plantilla de formulario de contacto añade un campo de tema.

Define también los campos en el panel, e Ikiform rechaza un envío que no coincida con 422 validation_failed y un mensaje por campo, que el código de arriba muestra junto a cada input. Pruébalo aquí; esto ejecuta el mismo validador en tu navegador:

Vista previa

Ejecuta el validador de Ikiform en tu navegador. No se envía nada.

Pega esta definición en la pestaña Fields del formulario. Sin definición, Ikiform acepta cualquier nombre de campo y te envía por email lo que llegue.

Cómo es el email

Cada envío aceptado manda un email sencillo y legible. Esta es la versión de texto de uno:

Email de notificación
From: Ikiform <notifications@ikiform.com>
To: you@yourcompany.com
Reply-To: ada@example.com
Subject: New submission: Contact

Contact got a new submission on Oct 25, 2026, 9:14 AM UTC.

name: Ada Lovelace
email: ada@example.com
message: Do you ship to Canada? I'd like to order 40 units before December.
page: /contact

View it in Ikiform:
https://ikiform.com/dashboard/submissions?form=frm_xxxxxxxxxxxxxxxx&submission=sub_...
  • Llega desde notifications@ikiform.com. No configuras registros DNS ni un dominio de envío, porque el correo sale del dominio de Ikiform.
  • El asunto es siempre New submission: <form name>. _subject no cambia el asunto de los emails de notificación. Se pasa a los webhooks y a la API como meta.subject. Para distinguir los formularios, dale a cada uno un nombre claro en el panel, como "Contacto, página de precios".
  • Los campos aparecen en el orden en que se enviaron, etiquetados por su name. Los campos que empiezan con _ se omiten.
  • Un formulario o una respuesta muy largos se acortan, y el email indica cuántos campos más hay en el panel. La página de límites tiene las cifras.
  • Los campos que parecen contraseñas o números de tarjeta se omiten, y el email de un envío que los contiene se retiene para revisión. No recojas credenciales con un backend de formularios.
  • Los miembros del espacio de trabajo reciben un botón View submission. Las personas de fuera del espacio de trabajo reciben los campos y un enlace para darse de baja.

Quién recibe el email

Los destinatarios se configuran por formulario en el panel, nunca desde el propio formulario. Un campo que indicara el destinatario permitiría a cualquiera usar tu formulario para enviar emails a quien quisiera, así que Ikiform no tiene ninguno.

QuiénCómo se añadenNotas
Por defectoNo hay que hacer nadaEl miembro elegido como Notification email del espacio de trabajo, o todos los propietarios del espacio de trabajo si no hay ninguno elegido
Miembros elegidosMárcalos en los ajustes de Notifications del formularioSolo miembros con una dirección de email verificada
Personas de fuera del espacio de trabajoAdd someone outside the workspace y luego Send linkReciben emails solo después de confirmar. Hasta 5 por formulario, y cada una puede darse de baja

Cada formulario envía emails a 10 direcciones como máximo. Cada destinatario recibe su propia copia en lugar de un CC compartido, así nadie ve las direcciones de los demás. Si el buzón de un destinatario rebota, Ikiform pausa los emails a esa dirección durante un tiempo y el panel muestra Emails bounced a su lado. Varios destinatarios explica cómo repartir por tema, algo que los destinatarios por sí solos no pueden hacer.

Responde a la persona, no a Ikiform

Ikiform toma la dirección reply-to primero de un campo _replyto y, si no, de un campo llamado email, email_address, your_email, reply_to, contact_email. El valor debe ser una única dirección de email válida o se ignora. Con un reply-to configurado, al pulsar Reply en Gmail, Outlook o Apple Mail se abre una respuesta al visitante, y tu respuesta sale desde tu propia dirección.

Sin él, una respuesta va a notifications@ikiform.com, que nadie lee. Es la sorpresa más habitual, y casi siempre se debe a un campo llamado user_email o Email Address con un espacio. Renómbralo o añade _replyto. La guía de reply-to cubre formularios con dos campos de email y creadores de sitios que renombran los campos por ti.

Cuando llega mucho a la vez

Cada formulario envía hasta 50 emails de notificación por hora, o 10 mientras el espacio de trabajo tenga menos de 7 días. A partir de ahí, el resto de los envíos de esa hora se guardan como siempre y llegan en un único email de resumen cuando termina la hora. El límite protege tu bandeja, y la opinión que tu proveedor de correo tiene del correo de Ikiform, cuando un formulario se publica en algún sitio grande o un bot se cuela entre los filtros.

Qué pasa con los emails de notificación en una hora con mucho tráficoun formulario, una hora de reloj en UTCenvíos 1 a 50un email cada uno,en segundosenvío 51 enadelanteguardado, va alresumenfin de la horaun resumen porformulariolímite alcanzadohora siguienteQué pasa con los emails de notificación en una hora con mucho tráficoun formulario, una hora de reloj en UTCenvíos 1 a 50un email cada uno, en segundosenvío 51 en adelanteguardado, va al resumenfin de la horaun resumen por formulariolímite alcanzadohora siguiente
  1. Los primeros 50 envíos a un formulario dentro de una hora de reloj envían cada uno un email como siempre.
  2. Los envíos posteriores de esa misma hora se guardan y aparecen en el panel al instante, sin un email por cada uno.
  3. Cuando termina la hora, cada destinatario recibe un resumen que los cuenta y enlaza al panel.
El límite se cuenta por formulario, así que una ráfaga en un formulario no frena a otro. Los webhooks no tienen límite y se disparan con cada envío.

El asunto del resumen es el número de envíos y el nombre del formulario; no enumera los campos ni configura un reply-to, así que responde a esos mensajes desde el panel. Si superas el límite con frecuencia, el email no es el canal adecuado para ese formulario: envíalo a Slack o a una bandeja compartida mediante un webhook.

Mantén el spam fuera de tu bandeja

El email encarece el spam: cada envío de un bot es una notificación que alguien abre. Ikiform guarda el spam con una respuesta de éxito normal, así el bot no aprende nada, y no envía ningún email por él. Cuatro cosas deciden qué cuenta como spam:

DefensaQué detectaConfiguración
HoneypotBots que rellenan todos los inputsEl input oculto _gotcha
Puntuación de spamEnlaces en el campo del nombre, tres o más enlaces, frases de spam conocidas, direcciones desechables y repeticiones idénticas. Con 5, el envío es spamNinguna
Dominios permitidosEnvíos desde otros sitiosAñade tu dominio en los ajustes del formulario
Verificación humanaBots que usan un navegador realPon Spam check en Ikiform

Revisa de vez en cuando el filtro Spam del panel. Si un mensaje real acaba ahí, márcalo como no spam y su email se envía en ese momento. La documentación de spam explica cada señal, incluido cuándo activar la verificación humana.

Lo que el email no puede hacer

Ikiform no envía emails a la persona que rellena el formulario. Los emails de notificación van solo a ti y a tu equipo, así que no hay respuesta automática, email de confirmación ni doble opt-in. Envíalos desde tu herramienta de email, activada por un webhook. Si tu sitio promete "hemos recibido tu mensaje", muéstralo en la página tras el envío, donde ya lo hace el código de arriba.

  • Una bandeja compartida del equipo. Añade la dirección del equipo como destinataria, o reenvía desde tu proveedor de correo.
  • Un canal de chat. Envía cada envío a Slack, Discord o Microsoft Teams por webhook. El chat va bien para formularios que reciben más de unos pocos mensajes al día.
  • Una hoja de cálculo o un CRM. Google Sheets, o cualquier herramienta a través de Zapier o n8n.
  • Archivos adjuntos. La subida de archivos aún no está disponible. Un envío con un archivo recibe 422 files_not_supported. Pide en su lugar un enlace a un archivo compartido.

Desactivar el email

Algunos formularios funcionan mejor sin email, como un registro a una newsletter con mucho tráfico. Desactiva Email new submissions en los ajustes de Notifications del formulario. Los envíos se siguen guardando y los webhooks se siguen disparando.

El límite empieza más bajo en los espacios de trabajo nuevos: 10 emails por formulario por hora durante los primeros 7 días. Si estás probando con un script, cuenta con recibir un resumen antes de lo que pasaría más adelante.

Elige tu caso

La configuración de arriba es la misma en todas partes. Estas páginas cubren una bandeja concreta, un stack concreto o la herramienta que estás dejando.

Comprueba que funciona

Repasa esto antes de publicar el formulario. Ikiform no tiene plan gratuito. Probar es gratis: un espacio de trabajo sin plan acepta 50 envíos de prueba al mes desde localhost. Para pasar a producción, elige Pro desde 6 $/mes por 500 envíos, o paga una sola vez: 10.000 envíos por 49 $ o 50.000 envíos por 149, $ con créditos que no caducan. Consulta los precios.

  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. En los ajustes de Notifications del formulario, comprueba que Email new submissions está activado y que están marcadas las personas correctas.
  3. Rellena el formulario en tu página y envíalo. Llegas a tu página de agradecimiento, o a la alojada de Ikiform.
  4. Abre Submissions en el panel. El nuevo envío está ahí con todos los campos que mandaste.
  5. Abre el email de notificación. El asunto es New submission: y el nombre del formulario, y aparecen todos los campos que enviaste.
  6. Pulsa Reply. La línea To muestra la dirección que escribiste en el formulario, no la de Ikiform.
  7. 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.
  8. ¿No llegó nada? Cambia el filtro de estado del panel a Spam. El spam recibe la misma respuesta de éxito que un envío real.

Solución de problemas

ProblemaQué hacer
El envío está en el panel, pero no llegó ningún emailMira primero en tu carpeta de spam o de promociones, y añade notifications@ikiform.com a tus contactos. Después revisa los ajustes de Notifications del formulario: puede que el email esté desactivado, que una dirección externa siga en Waiting for confirmation o que muestre Emails bounced.
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.
Reply va a notifications@ikiform.comNo se encontró ningún reply-to. Llama al campo del email email, email_address, your_email, reply_to o contact_email, o añade un campo _replyto con la dirección del visitante.
Los emails se detuvieron y llegó un resumen en su lugarEl formulario superó los 50 emails en una hora (10 en un espacio de trabajo nuevo). Todo está en el panel. Busca una ráfaga de bots en Spam, o usa un webhook para los formularios con mucho tráfico.
_subject no cambia el asunto_subject no cambia el asunto de los emails de notificación. Se pasa a los webhooks y a la API como meta.subject.
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.
422 validation_failedEl envío no coincide con la definición de campos del formulario. error.fields indica cada campo y el motivo. Haz que el name del input coincida con el id del campo.
402 test_limit_reachedEl espacio de trabajo no tiene plan y ya usó sus 50 pruebas gratuitas desde localhost este mes. Elige un plan o usa Send test en el panel.

Preguntas

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