Serverless Email Marketing
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:
- List all 5,000 files in the bucket (Class A operations $$$).
- Download each file individually to check if they are "active" (Class B operations).
- 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
- Use the right tool for the job. R2 is great for blobs (images, markdown), but D1 is king for structured data.
- Double Opt-In is non-negotiable. Using Resend to verify emails before adding them to the database keeps your list clean/secure.
- Listen to your AI. Sometimes the best code it produces is the advice to not write the code you planned.