Serverless Email Marketing

• By Rich Martinez

The Problem

When I started building Astro3, my philosophy was simple: Files are King. I wanted "Zero-Touch" architecture where everything—blog posts, configurations, and yes, even subscribers—lived as individual files in Cloudflare R2.

The plan was to store every subscriber as emails/john@example.com.json.

It felt "hacker-ish" and cool. But then I did the math.

If I wanted to send a newsletter to 5,000 people, I'd have to:

  1. List all 5,000 files in the bucket (Class A operations $$$).
  2. Download each file individually to check if they are "active" (Class B operations).
  3. Aggregate them in memory.

It was slow, expensive, and frankly, a bad design for structured data.

The Solution

I pivoted to Cloudflare D1, their serverless SQLite database.

Instead of thousands of JSON files, I have one table: subscribers.

CREATE TABLE subscribers (
    email TEXT UNIQUE,
    status TEXT DEFAULT 'pending', 
    verification_token TEXT
);

Now, getting my active list is one query:

SELECT email FROM subscribers WHERE status = 'active';

It costs basically nothing, runs instantly at the edge, and scales infinitely.

To handle the actual emails, I integrated Resend. It’s the "Stripe for Email"—clean API, great TypeScript SDK, and it works natively in Cloudflare Workers.

The AI Angle

I didn't write the SQL or the API routes by hand. I asked my AI agent:

"Compare my plan of using R2 files for subscribers vs using D1. Which is more production-ready?"

The AI didn't just code; it pushed back. It told me using R2 for this was a "hacky" idea and recommended D1 for queryability and data integrity. It then generated the full schema.sql, the Zod validation schema, and the Astro API routes.

Key Takeaways

  1. Use the right tool for the job. R2 is great for blobs (images, markdown), but D1 is king for structured data.
  2. Double Opt-In is non-negotiable. Using Resend to verify emails before adding them to the database keeps your list clean/secure.
  3. Listen to your AI. Sometimes the best code it produces is the advice to not write the code you planned.