Build Your Own Newsletter with Firebase & SES

By Lz on 2026-02-25 · 3 min read

Read on MediumBuild Your Own Newsletter with Firebase & SES

Adding a newsletter to your site sounds simple until you look at the price tags. Mailchimp, Beehiiv, ConvertKit—they all want $20–$50/month before you've even sent a single email. For a personal site or small project, that's a hard ask. So I did what most developers eventually do... I built it myself, and it turned out to be simpler than I expected.

Here's how I set it up, why I made the decisions I did, and what it actually costs to run.

1. The Problem with "Just Use a SaaS"

The big newsletter platforms are great if you're running a media company. But for a personal brand or side project, you're paying for a ton of features you'll never touch: automation sequences, A/B testing, landing page builders, etc. None of that matters when you just need a clean subscribe form and the ability to send an occasional update or two.

What I actually needed was simple:

  • Let people subscribe from my site
  • Store their emails somewhere reliable
  • Send them a welcome email automatically
  • Be able to send a newsletter blast whenever I want

That's it! No complex flows, no CRM, no segments. Just email in, email out.

2. Why Not a Full Server?

The first instinct for a lot of developers is to spin up a backend. But for something like this, a dedicated server is overkill and expensive in a different way.

A server runs 24/7... Even if nobody subscribes for a week, you're still paying for it to sit there. You're also on the hook for keeping it running, handling uptime, and managing deployments. For something that handles maybe a few events per day at most, that's a lot of overhead for not a lot of value.

Serverless functions are the right tool here. They only run when something actually happens: someone hits the subscribe endpoint, someone clicks unsubscribe, or you trigger a newsletter send. You pay per invocation, not per hour of uptime.

Firebase Cloud Functions specifically fit well because I was already using Firebase for other parts of the project. But the principle applies anywhere with Vercel Functions, AWS Lambda, Cloudflare Workers, etc. The idea is the same: don't run a server when an event-driven function does the job.

3. The Stack

Three pieces make this work together:

Firebase Cloud Functions handles the logic. Three endpoints cover everything:

// subscribeUser — saves email to Firestore, sends welcome email
// unsubscribeUser — updates status to UNSUBSCRIBED
// sendNewsletter — bulk sends to all active subscribers or add custom filters by specific tags

Firestore stores subscriber data. Each document is keyed by email address and tracks subscription status, when they subscribed, and which app they came from.

{
  email: "user@example.com",
  status: "SUBSCRIBED" | "UNSUBSCRIBED",
  marketingOptIn: true,
  source: "website",
  createdAt: Timestamp,
  updatedAt: Timestamp
}

AWS SES (Simple Email Service) is what actually sends the emails. It's barebones compared to the big newsletter platforms with no drag-and-drop builder, no analytics dashboard, and it's reliable and dirt cheap. I write the HTML templates in code, which means full control over exactly how they look.

4. The Flow

When someone subscribes on the site, here's what happens end to end:

  1. The form sends a POST request to the subscribeUser Cloud Function with the email address
  2. The function checks a honeypot field first (more on that in a second), then validates and rate-limits the request
  3. The email gets saved to Firestore with status SUBSCRIBED
  4. AWS SES fires off a welcome email automatically
  5. I get a quick admin notification so I know someone joined

The unsubscribe flow is just as clean. Every email includes an unsubscribe link with the email encoded in the query string. Clicking it hits the unsubscribeUser function, which flips the status in Firestore. No forms, no confirmation hoops.

Sending a newsletter is a separate callable function I trigger manually. It pulls all SUBSCRIBED users from Firestore, batches the sends to stay within SES's rate limits, and delivers each one.

5. The Small Details That Matter

A few things I added that weren't in the original plan but turned out to be worth it:

Honeypot spam protection. The subscribe form includes a hidden field called website_field. Real users never see it and never fill it out. Bots that auto-fill forms will populate it. If the function receives a request with that field filled in, it silently returns success without doing anything. Simple and effective.

if (website_field) {
  // looks like a bot — return success without saving anything
  return res.status(200).json({ success: true });
}

IP-based rate limiting. Each IP address is capped at a certain amount of subscription attempts per hour, tracked in a subscribe-rate-limits Firestore collection. This blocks anyone trying to spam the endpoint.

Admin notifications. Whenever someone subscribes, re-subscribes, or unsubscribes, I get a quick email with the event type and their details. It's a small thing but it's nice to know your system is working in real time.

6. What It Actually Costs

This is the part that makes the whole thing worthwhile.

  • Firebase Cloud Functions: Free tier covers 2 million invocations per month. A newsletter list under ~100,000 active subscribers won't come close to that.
  • Firestore: Free tier includes 1GB storage and 50,000 reads/20,000 writes per day. More than enough.
  • AWS SES: $0.10 per 1,000 emails sent. Sending to 1,000 subscribers costs ten cents. Sending to 10,000 costs a dollar.

Compare that to $50+/month for a SaaS platform at the same scale. The only real cost is the time to build it which if you already know Firebase and have a few hours, isn't that much.

Final Thoughts

Not every project needs a custom-built newsletter system. If you want analytics, automation sequences, and a visual editor, paying for a platform makes sense. But if you want full control, low cost, and a system that does exactly what you need and nothing more, building it with Cloud Functions and SES is genuinely the move.

The biggest lesson for me was that "serverless" isn't just a buzzword, it's the right architectural decision for workloads that are infrequent and event-driven. A newsletter is exactly that. Nothing is running when nothing is happening. You pay for what you use, and for a newsletter at any reasonable scale, what you use is almost nothing.

If you're already using Firebase on your project, the barrier to entry is even lower. The pieces fit together naturally, and you end up with something you actually understand end to end which is always better than being dependent on a black box you're paying monthly for.