← Back to all posts
2026-08-27 · MailAnvil Team

Send Welcome Emails from Astro with MailAnvil

A visitor signs up for your waitlist, the form submits, and then... nothing. No welcome email, no confirmation, and a lead that goes cold in minutes.

For AI-SaaS founders, the welcome email is the first impression after the signup — it either onboards the user or loses them. This tutorial wires it up in an Astro app using MailAnvil.

Why Astro + MailAnvil?

Astro ships zero JavaScript to the browser by default, but its API routes (/src/pages/api/*) still run server-side — exactly where an email send belongs. Deploy on the Cloudflare adapter and the whole stack sits on the edge: Astro pages and the MailAnvil send call run from the closest point of presence, not a us-east datacenter half a world away.

MailAnvil Resend SendGrid
10K emails/mo Rp 149rb ~Rp 320rb ~Rp 319rb
Payment QRIS, GoPay Credit card Credit card
Docs Bahasa + English English English
Latency Edge (Jakarta PoP) us-east us-east

What We Build

POST /api/welcome  →  Astro API route  →  create user  →  MailAnvil /v1/send  →  user inbox

Step 1: Scaffold Astro with the Cloudflare Adapter

npm create astro@latest foundersai -- --template minimal --install --git
cd foundersai
npx astro add cloudflare

npx astro add cloudflare wires up @astrojs/cloudflare as the SSR adapter.

Step 2: Store Secrets

Never hardcode keys. Use a .env file (or wrangler secret put on Cloudflare):

MAILANVIL_API_KEY=mk_live_xxxxxxxx
[email protected]

Step 3: The Welcome API Route

src/pages/api/welcome.ts:

import type { APIRoute } from "astro";

const BASE = "https://api.mailanvil.com/v1";

export const POST: APIRoute = async ({ request }) => {
  const body = await request.json();
  const email = String(body.email ?? "");
  const name = String(body.name ?? "there");

  if (!email || !email.includes("@")) {
    return new Response(JSON.stringify({ error: "valid email required" }), {
      status: 400,
      headers: { "Content-Type": "application/json" },
    });
  }

  const idempotencyKey = crypto.randomUUID();

  const res = await fetch(`${BASE}/send`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${import.meta.env.MAILANVIL_API_KEY}`,
      "Idempotency-Key": idempotencyKey,
    },
    body: JSON.stringify({
      from: import.meta.env.MAILANVIL_FROM,
      to: [email],
      subject: `Welcome to FoundersAI, ${name}! 🎉`,
      html: buildWelcomeHtml({ name }),
      text: `Hi ${name}, welcome to FoundersAI. Confirm your email to join the waitlist.`,
    }),
  });

  if (res.status !== 202) {
    const err = await res.json();
    return new Response(
      JSON.stringify({ error: err.error?.message || "send failed" }),
      { status: 502, headers: { "Content-Type": "application/json" } },
    );
  }

  return new Response(JSON.stringify({ queued: true }), { status: 202 });
};

import.meta.env works because Astro exposes MAILANVIL_* (any PUBLIC_-prefixed var is client-safe; keep secrets unprefixed so they stay server-only). On Cloudflare, add them via wrangler secret put MAILANVIL_API_KEY.

Step 4: The Welcome Template

src/lib/email.ts:

export function buildWelcomeHtml(d: { name: string }) {
  return `
    <div style="font-family:sans-serif;max-width:480px;margin:0 auto">
      <h1 style="color:#ff801f">Welcome, ${d.name}!</h1>
      <p>You're on the FoundersAI waitlist. Confirm your email to claim your spot.</p>
      <a href="https://foundersai.id/confirm"
         style="display:inline-block;background:#ff801f;color:#fff;padding:12px 24px;border-radius:9999px;text-decoration:none">
        Confirm email
      </a>
    </div>`;
}

Step 5: Test

npm run dev
curl -X POST http://localhost:4321/api/welcome \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","name":"Sari"}'

Response {"queued":true} and the welcome email lands in under a second.

Real Use Cases in Indonesia

The same POST /v1/send endpoint covers the three most common transactional messages for an AI-SaaS launch:

Best Practices

  1. Idempotency-Key is mandatory — key on the signup event so a retry or double submit can't send two welcomes.
  2. Verify your domain first — DKIM is required to stay out of spam. MailAnvil auto-configures DKIM for domains on Cloudflare DNS.
  3. Watch bounces — MailAnvil's kill switch pauses sending if hard-bounce exceeds 5%, protecting your domain reputation automatically.
  4. Keep keys in secrets — unprefixed import.meta.env vars stay server-only; use wrangler secret put in production.

Start Free

Free plan: 500 emails/month, no credit card. Pay with QRIS/GoPay. Full Bahasa Indonesia docs.

➡️ Try MailAnvil Free — mailanvil.com