Formulario de contacto en un sitio estático7 min de lectura
Añade un formulario de contacto a un sitio de GitHub Pages
GitHub Pages no ejecuta código de servidor, así que un POST de formulario recibe 405 Not Allowed; envía a un backend de formularios y configura bien las redirecciones del project site.
GitHub Pages solo sirve archivos estáticos, así que un formulario que envía a tu propio sitio recibe 405 Not Allowed y el mensaje se pierde. Pon un endpoint de Ikiform en el action del formulario, añade username.github.io y tu dominio personalizado, si tienes, a Allowed domains, y redirige a una página de agradecimiento que incluya la ruta de tu project site. No cambia nada en tu repositorio ni en los ajustes de Pages, y ningún secreto acaba en el repositorio público.
Qué cambia en GitHub Pages
GitHub Pages publica lo que genera tu repositorio o tu workflow de Actions, y nada más. Jekyll se ejecuta en el build si lo usas, y el resultado son archivos. No hay manejador de peticiones, así que mail() de PHP, un script de Node o un formulario CGI en Python no van a funcionar, hagas el commit que hagas.
Puedes ver el fallo desde una terminal. Un POST a cualquier página de un sitio de Pages recibe esto:
curl -i -X POST -d "message=hello" https://ada.github.io/notebook/contact.htmlHTTP/2 405
server: Varnish
content-length: 131
<html>
<head><title>405 Not Allowed</title></head>Otras cuatro cosas distinguen a Pages de otros hosts estáticos, y cada una afecta al formulario de contacto:
| Rasgo de Pages | Qué significa para el formulario |
|---|---|
Los project sites viven bajo una ruta, username.github.io/repo/ | Una URL de agradecimiento /thanks.html apunta al user site, no a tu proyecto. Cada URL necesita la parte /repo/ |
| No hay ajuste para cabeceras de respuesta personalizadas | Una Content-Security-Policy solo puede venir de una etiqueta <meta> en la página |
| El repositorio suele ser público | Todo lo que contiene es público. El id del formulario puede estar ahí; una clave de API secreta o la contraseña de un email, nunca |
| GitHub dice que los sitios de Pages no deben usarse para transacciones sensibles como enviar contraseñas o números de tarjeta de crédito | Que el formulario de contacto sea solo eso. No recojas datos de tarjetas ni contraseñas de cuentas con él |
- Haces push a la rama desde la que publica Pages.
- Jekyll o tu workflow de Actions genera el sitio una vez.
- Pages sirve el resultado como archivos estáticos en github.io o en tu dominio personalizado.
- Un visitante envía el formulario de contacto. Si su action apunta a tu propio sitio, Pages responde 405 Not Allowed.
- Con el action apuntando a tu endpoint de Ikiform, Ikiform guarda el mensaje y te envía un email.
- Ikiform redirige el navegador a la página de agradecimiento, que Pages sirve como cualquier otro archivo.
El formulario
En un sitio escrito a mano, añade contact.html junto a index.html. Este es para un project site en ada.github.io/notebook, así que la redirección incluye /notebook/:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
/>
<title>Contact</title>
</head>
<body>
<h1>Get in touch</h1>
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
<label for="name">Name</label>
<input id="name" name="name" autocomplete="name" required />
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email" required />
<label for="about">What is it about?</label>
<select id="about" name="about">
<option value="question">A question about the project</option>
<option value="hire">Work together</option>
<option value="other">Something else</option>
</select>
<label for="message">Message</label>
<textarea id="message" name="message" rows="6" minlength="10" required></textarea>
<input type="hidden" name="page" value="docs-home" />
<input type="hidden" name="_redirect" value="https://ada.github.io/notebook/thanks.html" />
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
<button type="submit">Send</button>
</form>
</body>
</html>- La Content-Security-Policy en
<meta>es opcional. Mantenla si ya tienes una, y asegúrate de queform-actionyconnect-srcincluyenhttps://ikiform.com. Pages no puede enviar la cabecera por ti. - El select
aboutte dice por qué alguien escribió antes de que abras el mensaje. Cambia las opciones por los temas sobre los que la gente te escribe de verdad. - El input oculto
pageregistra en qué página estaba el formulario, algo útil cuando el mismo formulario está en varias páginas de documentación. - Mantén
emailcomo nombre del campo. Los emails de notificación lo usan como dirección de respuesta.
Si el mismo HTML se despliega bajo varias rutas, o no sabes cuál será la ruta final, construye la redirección en el navegador a partir de la dirección de la propia página. Pon esto después del formulario:
<script>
document.querySelectorAll('input[name="_redirect"]').forEach((input) => {
input.value = new URL("thanks.html", document.baseURI).href;
});
</script>¿Usas Jekyll? No escribas la URL a mano. La guía de Jekyll tiene un include que la construye con absolute_url, que añade tu baseurl en los project sites. ¿Generas con Astro, Vite o Hugo mediante un workflow de Actions? Pon la ruta base del framework en /repo/ para que carguen los assets del formulario, y usa la guía de Hugo o la de tu framework para el formulario en sí.
Dominios permitidos en github.io
Añade ada.github.io, con tu propio nombre de usuario. Cubre tu user site y todos tus project sites, porque los project sites comparten el mismo host. Añade también tu dominio personalizado si usas uno; example.com también cubre www.example.com.
Nunca añadas github.io por sí solo. Coincidiría cualquier sitio de Pages, incluidas las copias de tu formulario en sitios de otras personas. Con dominios permitidos configurados, se sigue un _redirect a https://ada.github.io/notebook/thanks.html; sin ellos, Ikiform lo ignora y muestra su página de agradecimiento alojada.
_redirect que empiezan por https:, y un dominio personalizado que aún no tiene certificado sirve páginas http:.Reemplazar un enlace mailto:
Muchos sitios de Pages empiezan con un enlace mailto: en el pie de página. Cambiarlo por el formulario impide que los nuevos scrapers lean tu dirección en la página, y los visitantes sin una app de correo configurada por fin pueden contactarte. Dos cosas que debes saber antes de borrarlo:
- La dirección sigue en el historial de tu repositorio, y en cualquier fork o archivo de la página antigua. El formulario ayuda a partir de ahora; no vuelve privada una dirección que lleva años siendo pública.
- Las respuestas salen de tu propia bandeja de entrada. Los emails de notificación ponen al remitente como dirección de respuesta, así que pulsar Reply funciona como el enlace
mailto:, pero desde el otro lado.
Ikiform nunca envía emails al visitante, así que indica en la página de agradecimiento cuándo puede esperar una respuesta. Si recibes más mensajes de los que puedes contestar por email, un webhook puede dejar cada uno en Slack o Discord.
Comprueba que funciona
Haz esto en la dirección github.io en producción. Pages no tiene despliegues de preview, así que prueba primero en local con un servidor local.
- Añade
localhostyusername.github.ioen Allowed domains, más tu dominio personalizado si tienes uno. - Haz commit de
contact.htmlythanks.html, espera a que termine el despliegue de Pages en la pestaña Actions del repositorio y abre la página publicada. - Envía el formulario. Deberías llegar a tu propio
thanks.html, con la ruta del proyecto en la barra de direcciones. - Abre Submissions en el panel. El nuevo envío está ahí con todos los campos que enviaste.
- Revisa la bandeja de entrada de cada destinatario de notificaciones. Cada uno recibe un email con los campos, y Reply va a quien envió el formulario cuando este tiene un campo
email. - ¿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.
Problemas habituales
| Problema | Qué hacer |
|---|---|
405 Not Allowed al pulsar Enviar | El formulario desplegado sigue enviando a tu propio sitio. Mira el código fuente de la página en github.io y revisa el action; un build antiguo en caché puede seguir publicado unos minutos. |
| La página de agradecimiento de Ikiform en lugar de la tuya | Al valor de _redirect le falta la ruta del repositorio, es http:, o el formulario no tiene dominios permitidos. Añade username.github.io y usa la URL https: completa. |
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. |
| Los envíos funcionan en local, pero la consola muestra un error de CSP en github.io | A una Content-Security-Policy en <meta> de tu layout le falta https://ikiform.com en form-action o connect-src. |
Preguntas
No. GitHub Pages sirve archivos estáticos y no ejecuta código cuando un visitante envía un formulario, así que un POST a una URL de Pages recibe 405 Not Allowed. Apunta el action del formulario a un backend de formularios.
Sí. El id del formulario acaba en tu HTML público de todos modos. Protege el formulario con dominios permitidos y las comprobaciones antispam, y nunca hagas commit de una clave de API secreta, porque un sitio estático no tiene ningún lugar seguro donde guardarla.
Una ruta como /thanks.html apunta a la raíz de username.github.io, no a tu proyecto. Usa la URL completa con la ruta del repositorio, o constrúyela a partir de document.baseURI en el navegador.
Sí. El formulario envía a Ikiform sea cual sea el dominio que sirve la página. Añade el dominio personalizado en Allowed domains junto a username.github.io, y cambia cualquier valor de _redirect para que use el dominio personalizado cuando HTTPS esté forzado.
No, no hay plan gratuito. Probar es gratis: puedes enviar 50 envíos de prueba al mes desde localhost antes de pagar. Para pasar a producción, Pro empieza en 6 $/mes por 500 envíos, o puedes pagar una sola vez 10.000 envíos por 49 $ o 50.000 envíos por 149, $ con créditos que no caducan nunca.
¿Te atascaste en un paso o quieres una guía para tu caso? Escribe a hello@ikiform.com.