Formulario de contacto y correo
Cómo funciona el flujo de contacto con Astro Actions, y las variables de entorno de Resend o SMTP que lo hacen entregar correo en producción.
La starter entrega un formulario de contacto funcional — validado, filtrado contra spam y conectado a un proveedor de correo. En desarrollo registra en la consola; en producción envía correo real una vez que estableces unas pocas variables de entorno. Nada está simulado.
El flujo
El formulario es una Astro Action, definida en src/actions/index.ts:
export const server = {
contact: defineAction({
accept: 'form',
input: z.object({
name: z.string().min(1).max(100),
email: z.email().max(254),
message: z.string().min(10).max(5000),
_website: z.string().max(0).optional(), // honeypot
}),
handler: async (input) => {
if (input._website) return { ok: true }; // bot — silently drop
await sendContactEmail(input);
return { ok: true };
},
}),
}; Qué ocurre al enviar:
- La página publica directamente a la acción:
<form method="post" action={actions.contact}>. Astro maneja la mejora progresiva. - Zod valida nombre / correo / mensaje; una entrada inválida devuelve un error tipado que la página renderiza en línea.
- El campo honeypot
_website(oculto para humanos, irresistible para bots) cortocircuita con un éxito silencioso. - La entrada válida se pasa a
sendContactEmail— la costura del proveedor ensrc/lib/email/. - La página lee el resultado con
Astro.getActionResult(actions.contact)y muestra éxito o error.
La costura de correo
src/lib/email/index.ts reexporta el sendContactEmail de un proveedor. La CLI
escribe el import correcto según el proveedor que elijas en el momento de
generar el proyecto:
- Resend (por defecto) →
./resend.ts - SMTP →
./smtp.ts - Ninguno → un registrador de consola que imprime los envíos con una advertencia de “configura tu proveedor”
Cambia de proveedor en cualquier momento editando ese único import. Como la acción solo conoce la costura, nada aguas abajo cambia.
Variables de entorno
Copia .env.example a .env y rellena lo que tu proveedor necesite. El
desarrollo local funciona sin ninguna de estas establecidas — los envíos se
registran en la consola.
Resend
RESEND_API_KEY=re_xxxxxxxx # from resend.com
[email protected] SMTP
SMTP_HOST=smtp.example.com
SMTP_PORT=587
[email protected]
SMTP_PASS=••••••••
SMTP_FROM="Acme <[email protected]>"
[email protected] CONTACT_TO_EMAIL es donde se entregan los envíos, sin importar el proveedor.
Personalización
- Añadir un campo → extiende el esquema
inputde Zod y añade el<input>correspondiente asrc/pages/contact.astro. El tipo fluye automáticamente. - La protección anti-spam más fuerte se deja fuera a propósito — el honeypot cubre lo básico; añade Turnstile o hCaptcha si necesitas más.
- Cambiar el cuerpo del correo → edita
src/lib/email/resend.ts(osmtp.ts).