Recibe cada formulario en un canal de Discord en unos cinco minutos. Puedes programar una función que convierta datos al formato del webhook o usar un endpoint que ya lo haga. Esta guía explica ambos.
Por qué Discord en vez del correo
Si creas proyectos personales, probablemente ya tienes Discord abierto. El email es el destino habitual de los formularios y también donde se pierden: entre boletines, recibos y avisos de GitHub, en una bandeja que consultas dos veces al día. Una alerta en un #contact se ve en minutos. Un canal se comparte por defecto: un colaborador puede ver y responder sin que reenvíes nada.
Paso 1: crea un webhook de Discord
Un webhook es una URL que permite publicar mensajes en un canal concreto de tu servidor. Crearlo lleva un minuto:
- Abre tu servidor de Discord, pulsa su nombre arriba a la izquierda y elige Server Settings.
- En el menú lateral, abre Integraciones, después Webhooks.
- Haz clic en New Webhook. Discord crea uno con un nombre aleatorio. Cámbialo por algo como «Formulario de contacto» y elige el canal de destino (un canal específico de
#contactfunciona bien). - Haz clic en Copy Webhook URL.
La URL tiene este formato: https://discord.com/api/webhooks/1234…/AbCd…. Trátalo como una contraseña: cualquiera que lo tenga puede publicar en ese canal.
Paso 2, a mano: código entre formulario y webhook
Pero hay un detalle: un webhook de Discord no es un endpoint de formulario. Espera un POST con Content-Type: application/json y un cuerpo con el formato de Discord, al menos {"content": "your message"}. Un formulario HTML envía datos codificados como URL o multipart, por lo que dirigir su action directamente al webhook falla. Además publicaría su URL en el código para que cualquiera la copie e inunde tu canal.
La solución clásica intercala una función serverless: el formulario envía a la función, esta reformatea y reenvía a Discord:
// api/contact.js: a serverless function (Vercel, Netlify, etc.)
export default async function handler(req, res) {
const { name, email, message } = req.body;
if (!email || !message) {
return res.status(400).json({ error: "email and message are required" });
}
await fetch(process.env.DISCORD_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
content: `**${name || "Someone"}** <${email}>\n${message.slice(0, 1800)}`,
}),
});
res.redirect(303, "/thanks.html");
}Funciona y sirve como proyecto de fin de semana. Pero mantienes validación, antispam, límites de Discord y errores. Sus mensajes se limitan a 2000 caracteres; de ahí el slice: los mensajes más largos se cortan. La mayor limitación es que Discord se convierte en tu única copia. Si falla la petición o el mensaje pasa desapercibido durante el fin de semana, el envío se pierde. No hay archivo, botón de respuesta ni estado para saber si ya has contestado.
Paso 3, sin código adicional: un endpoint que habla con Discord
Con mailcontact, desaparece el código de enlace. Tu formulario envía los datos al endpoint del proyecto (HTML sencillo, sin necesidad de JavaScript):
<form action="https://mailcontact.app/api/forms/your-form-id" method="POST">
<input type="text" name="name" placeholder="Your name" />
<input type="email" name="email" placeholder="[email protected]" required />
<textarea name="message" placeholder="Your message" required></textarea>
<button type="submit">Send</button>
<input name="company_website" type="text" tabindex="-1" autocomplete="off"
style="position:absolute;left:-10000px" aria-hidden="true" />
</form>En las notificaciones del proyecto añade Discord y pega la URL del paso 1. Cada envío llega a la bandeja y avisa al canal. El documentación de notificaciones explican los detalles.
Con Pro o Plus, el webhook queda en el servidor, no en el código público. Gestionamos validación y límites. La bandeja conserva mensajes aunque superen el tamaño de Discord. Cada proyecto también tiene un email real como [email protected], los emails activan el mismo canal: formulario y email en un solo lugar. Las notificaciones de Discord están incluidas en Pro y Plus.
El endpoint responde con JSON, sin redirección. Para mantener al visitante en la página, envía los mismos campos con unas líneas de fetch. El documentación del endpoint incluyen un ejemplo listo para pegar. Los formularios nativos devuelven JSON.
El código es igual con cualquier herramienta, pero cambia dónde pegarlo. Hay versiones específicas para Formularios para Next.js, Formularios de contacto para Astro, y Cloudflare Pages, que no dispone de gestión de formularios propia.
Qué incluye una buena alerta
La alerta de Discord debe permitir decidir desde el móvil sin abrir más. Necesita cuatro cosas:
- Nombre: quién escribe, para saber a quién responder.
- Email: cómo responder. Es el campo que más suelen olvidar las soluciones caseras y convierte una alerta en un callejón sin salida.
- Mensaje: las primeras líneas bastan para decidir entre «ahora», «esta noche» e «ignorar».
- Origen: por qué formulario o dirección llegó, para identificar cada aviso cuando gestionas varios proyectos.
Una buena alerta sería algo así:
acme-site: new message
Ada Lovelace <[email protected]>
"Hey, the checkout button 404s on mobile. Happy to
send a screen recording if that helps."
via: contact formLa alerta debe ser fácil de leer y el registro completo debe guardarse. Por eso un canal más una bandeja supera a cualquiera por separado. Versión rápida: crea un proyecto, pega el formulario y pega la URL del webhook. Elige Pro o Plus para conectar Discord. Si tu sitio es estático, la guía sobre añadir un formulario a un sitio estático cubre esa parte.