Formulario en Astro con base de datos y envío de correo
Blog

Cómo crear un formulario en Astro que guarda en Turso y envía notificaciones por email

Por Ramon Nuila jueves, 28 de marzo de 2024 · 9 min de lectura

Guía paso a paso para implementar un formulario profesional en Astro con base de datos en Turso y notificaciones automáticas usando Resend. Ideal para sitios modernos y rápidos.

Crear un Formulario en Astro con Turso y Notificaciones por Email usando Resend

En esta guía te muestro paso a paso cómo crear un formulario de contacto usando Astro, almacenar los datos en Turso y enviar una notificación por email a una cuenta Gmail usando Resend. Esta solución es ideal si querés tener un sitio profesional, sin depender de herramientas externas como Netlify Forms o Google Forms.


🧩 Stack utilizado

  • Astro (con SSR)
  • Turso (SQLite distribuido)
  • Netlify (hosting + serverless functions)
  • Resend (envío de emails transaccionales)
  • TypeScript (opcional)

1. Configurar Astro para manejar formularios con SSR

En astro.config.mjs, asegurate de tener el modo server activado:

import { defineConfig } from "astro/config";
import netlify from "@astrojs/netlify";

export default defineConfig({
  output: "server",
  adapter: netlify(),
});

Instalá el adaptador si aún no lo tenés:

npm install @astrojs/netlify

Esto permite que Astro ejecute lógica del lado del servidor (como manejar formularios) en Netlify.


2. Crear tabla en Turso con verificación de email único

CREATE TABLE contacts (
  id INTEGER PRIMARY KEY,
  name TEXT,
  email TEXT UNIQUE,
  subject TEXT,
  message TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Obtén las variables:

  • TURSO_DATABASE_URL
  • TURSO_AUTH_TOKEN

Guardalas en .env:

TURSO_DATABASE_URL="libsql://..."
TURSO_AUTH_TOKEN="..."

Instalá el cliente:

npm install @libsql/client

Y creá src/turso.ts:

import { createClient } from "@libsql/client";

export const turso = createClient({
  url: import.meta.env.TURSO_DATABASE_URL,
  authToken: import.meta.env.TURSO_AUTH_TOKEN,
});

3. Crear el componente ContactForm.astro

Este componente contiene solo la estructura visual del formulario:

<form method="POST" class="...">
  <input type="text" name="name" required />
  <input type="email" name="email" required />
  <input type="text" name="subject" required />
  <textarea name="message" required></textarea>
  <button type="submit">Enviar</button>
</form>

No debe tener ninguna lógica del lado del servidor. Solo HTML + Tailwind CSS.


4. Manejar el formulario en src/pages/contact/index.astro

Dentro del frontmatter ---, colocamos toda la lógica:

---
import ContactForm from "../../components/ContactForm.astro";
import { turso } from "../../turso";
import { Resend } from "resend";

const resend = new Resend(import.meta.env.RESEND_API_KEY);

if (Astro.request.method === "POST") {
  try {
    const data = await Astro.request.formData();
    const name = data.get("name")?.toString();
    const email = data.get("email")?.toString();
    const subject = data.get("subject")?.toString();
    const message = data.get("message")?.toString();

    if (name && email && subject && message) {
      const { rows } = await turso.execute({
        sql: "SELECT id FROM contacts WHERE email = ?",
        args: [email],
      });

      const exists = rows.length > 0;

      if (!exists) {
        await turso.execute({
          sql: "INSERT INTO contacts (name, email, subject, message) VALUES (?, ?, ?, ?)",
          args: [name, email, subject, message],
        });

        const htmlContent = `
          <h2>Nuevo mensaje de contacto</h2>
          <p><strong>Nombre:</strong> ${name}</p>
          <p><strong>Email:</strong> ${email}</p>
          <p><strong>Asunto:</strong> ${subject}</p>
          <p><strong>Mensaje:</strong> ${message}</p>
        `;

        await resend.emails.send({
          from: "Tu Sitio <contacto@tudominio.com>",
          to: ["tu-cuenta@gmail.com"],
          subject: `Contacto: ${subject}`,
          html: htmlContent,
        });
      } else {
        console.log("Email duplicado:", email);
      }
    }
  } catch (error) {
    console.error("Error en el formulario:", error);
  }
}
---

<ContactForm />

5. Configurar Resend

  1. Crear cuenta en resend.com
  2. Verificar un dominio o usar el temporal onboarding@resend.dev
  3. Crear una API Key y guardarla como RESEND_API_KEY en .env
npm install resend
RESEND_API_KEY="re_xxxxxxxxxxxxxx"

6. Variables de entorno en Netlify

Desde el panel de Netlify:

  • TURSO_DATABASE_URL
  • TURSO_AUTH_TOKEN
  • RESEND_API_KEY

Netlify inyectará esas variables correctamente en funciones serverless.


7. Alternativas para envío de correo

SMTP con Nodemailer

Funciona, pero es menos confiable y Gmail suele bloquearlo si detecta comportamiento automatizado.

API de Gmail

Compleja de integrar. Necesita OAuth2. No es la mejor opción para casos simples.

Servicios como Resend / Postmark / SendGrid

✅ Simples, confiables y con mejor entregabilidad. Ideales para producción.


8. Buenas prácticas

  • Validar también en el servidor.
  • No guardar credenciales en el cliente.
  • Usar try/catch para manejar errores.
  • Evitar duplicados desde la lógica y desde la base de datos.
  • Mostrar feedback al usuario (mensaje de éxito/error).

🚀 Conclusión

Con este stack podés tener un formulario profesional, seguro y moderno:

  • 🌐 Totalmente integrado a tu sitio
  • 🧠 Sin dependencias innecesarias
  • 🛠️ Con base de datos real y notificaciones automatizadas

Ideal para freelancers, agencias, SaaS y cualquier proyecto serio en producción.

¿Te sirvió esta guía? Compartila con otros desarrolladores o añadila a tus recursos favoritos 💛

¿Te gustó este artículo?

Explorá más publicaciones en nuestro blog o compartilo con alguien.

Ver más artículos