I wanted to set up a newsletter because that’s apparently what you’re supposed to do when you have a blog.
I looked at the standard ways to handle this and they all felt like a lot of overhead for a small personal project. I wanted something that felt like it belonged here, without the extra baggage of a typical marketing platform or a complex setup.
The Problem
I wanted a simple flow. I write a blog post in Markdown, push to GitHub, let Cloudflare Pages build the site, and my subscribers get an email.
I already use Resend for other projects, and so I wanted to stick with that instead of adding another vendor to my stack. I didn’t want to hook up to more services, mess with new APIs, or deal with heavy SDKs just to bridge my content to my subscribers.
I know there are turnkey tools built for this kind of thing, and many of them are practically frictionless. But they are often paid or require you to duplicate your content into their own dashboards. Even then, there was still the issue of how to actually trigger an email campaign from a Git push. I looked at several solutions ranging from basic automation hooks to full on marketing platforms that do it all for you, but I thought…
The Stack
So I DIYed an automated email notification pipeline. Here are the moving parts:
- Astro: Generates the RSS feed (
rss.xml) from my existing content collections. - Resend: Actually sends the emails (their free tier is generous).
- RSS Parser: Reads my own feed.
- Cloudflare Pages: runs a simple script and then builds the site.
The Logic
Instead of hooking into a database or a complex CMS or mailing platform, I realized my production RSS feed is basically the “single source of truth” for what is currently live.
I wrote a script that runs before the build completes. It grabs the live RSS feed (what’s currently on the site) and compares it to the local file system (what I’m about to deploy).
If "Local Post" exists AND "Local Post" is NOT in "Live RSS" => Send Email.
It’s stupid simple. It listens to the “diff” between deployments.
The Script
I added a build:prod command to my package.json:
"build:prod": "tsx scripts/send-newsletter.ts && astro build"
The script (send-newsletter.ts) does the heavy lifting:
- Fetches
https://sun-envidiado.com/rss.xml. - Scans
src/content/blog(where my content lives). - Checks for new slugs.
- Fires off an email via Resend to a specific contact segment.
It’s essentially a CI/CD pipeline step that acts as my marketing team!
The “Gotchas”
Of course, it wasn’t seamless.
- Double Builds: If I run this locally without checks, I casually spam everyone with “Hello World” test posts. So I added a check to only send emails if in production.
- Timing: The email sends before the build finishes. Technically, for a few minutes, the link in the email 404s until Cloudflare swaps the deployment. I call this “building anticipation” (Update: I fixed this by scheduling the email to send 30 minutes later, so the blog is definitely live by then).
- Edits: If I fix a typo in an old post, I have to make sure the script doesn’t think it’s “new.” The RSS comparison handles this nicely; it only cares about slugs, not content timestamps.
Conclusion
Is this over-engineered? Probably. Is there a better way to do this? Most likely. Is it satisfying? Absolutely.
It works for me, costs me nothing, and gives me an excuse to write more TypeScript. If you’re reading this after clicking the link in the email, it worked!
If you’re reading this on the site, maybe subscribe below and test my code for me? 🥹🙏🏼