# The 300-Email Wall: How a Marketing Blast Became a Backend System

> A 1,000+ user announcement, a 300/day API ceiling, and a marketing brief that quietly turned into a stateful, resumable engineering project. This is how a "simple email blast" became one of the most interesting puzzles I've shipped at Fixme.

Canonical URL: https://francisj2nd.cv/cs/300-email-wall/
Category: Marketing / Engineering
Date: July 12, 2025
Read time: 11 min read

## TL;DR

Brevo capped us at 300 emails a day. Our user base was over 1,000. So I built a stateful, resumable Spring Boot mailer that filters out anyone already messaged, sends in safe daily batches, and logs every send to disk — surviving crashes, restarts, and my own forgetfulness. Five mornings, zero duplicates, zero misses.

Key metrics:
- Users Reached: 1,000+
- Daily Cap: 300
- Failures: 0

---

When I was handed the brief for our latest marketing campaign, it felt like a home run waiting to happen. Our engineering team had just launched a transformative update to the Fixme app — a new "Order Assistant" that automated tedious back-and-forth for vendors and gave customers a silky-smooth checkout. This wasn't just an update; it was a leveling up of our entire user experience.

The mission was clear: **tell everyone**. Not with a small in-app notification, but with a beautiful, compelling email announcement. One tailored for our hard-working vendors, and another for our growing customer base.

This is where the excitement met reality. Our email service provider, Brevo, gave us a generous but firm daily sending limit of 300 emails. Our user base? Over a thousand, and climbing.

We couldn't just email the first 300 people and call it a day. Every user deserved to know. The project's scope immediately changed. It was no longer just a marketing campaign — it was a technical challenge that required me to become a one-person machine: part designer, part marketer, part backend developer.

> A 300-email cap turned a marketing brief into an engineering brief.

## The First Hurdle: Designing an Email That Survives the Inbox

My goal was an email that felt premium, modern, and worthy of a major tech update. I crafted two emails — one for vendors, one for customers. Clean, on-brand, dynamic.

I exported the HTML and set up a quick test send. The result was crushing.

Blank. Utterly, completely blank, save for a single line of footer text. All that design work, vanished.

I had just run headfirst into a brutal lesson every web developer learns eventually: **email is not the web**. My beautiful design was built on modern web technologies — a `<script>` tag to run Tailwind CSS and `<link>` tags to pull in custom fonts. Email clients, for very good security and performance reasons, see that code and throw it straight in the trash.

## Rebuilding the Engine: From Modern Code to Bulletproof HTML

The only way forward was to retreat into the past: **inlining CSS**. Instead of a central stylesheet, every single style had to be manually written into a `style=""` attribute on each individual HTML element.

This modern, clean code:

```html
<div class="bg-white rounded-xl shadow-xl">Hello World</div>
```

Had to become this verbose, but indestructible, code:

```html
<div style="background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">Hello World</div>
```

I used an AI code assistant to do the heavy lifting of converting thousands of lines into an email-safe format. The final HTML template — now a self-contained beast — was embedded directly into our Java Spring Boot application as a multi-line String.

With the email itself finally fixed, I could now tackle the real beast: sending over 1,000 of them with a daily limit of 300.

## Engineering a Campaign That Couldn't Fail

A simple `for` loop was out of the question. It would send 300 emails, then on the 301st the Brevo API would slam the door shut. The application would crash, and I'd be left sifting through logs to figure out who got the email and who didn't.

I needed a system that was **stateful, resumable, and idiot-proof**. The solution was a **batched sending engine with a persistent log**. Every time I ran the program, it would know what it had already done and what was left to do.

### The sending engine flow

1. **Read master list** — load all 1,000+ users from `users.json`
2. **Read sent log** — open `sent_promo_emails.txt` and load every email already messaged
3. **Diff** — take the master list and remove anyone in the sent log
4. **Check** — if pending is empty, the campaign is complete; stop
5. **Today's batch** — take the first 300 from pending
6. **Process** — for each user: send the personalized email, immediately append their address to the sent log, pause 0.5s, repeat
7. **Stop** — print a daily summary and exit

The immediate logging (`appendEmailToSentFile`) is what makes the process resilient. If the program crashed after sending email #157, the log would have 157 names in it, and on the next run it would just pick up with #158.

## The Campaign in Action

With this system in place, my job became beautifully simple. Each morning, I would run the program from the command line.

- **Day 1:** 300 emails
- **Day 2:** 600 emails total
- **Day 3:** 900 emails total
- **Day 4:** 1,000+ emails total
- **Day 5:** ✓ DONE

On day 5 the program checked the log, saw every user from the master list was accounted for, and printed a single line: *All users have already received the promotional email. Nothing to do.*

It worked. Perfectly. We had messaged our entire user base without a single crash, duplicate, or API error.

> Beautiful code means nothing if it doesn't survive the inbox.

## What I Took From It

Every startup hits that point where big ambition meets tiny constraint. You either stall — or you get scrappy.

This campaign taught me that even small limitations (like an email cap) can unlock smarter systems if you treat them as design prompts instead of blockers. I also learned — again — that beautiful code means nothing if it doesn't survive the inbox. And that the best tools are the ones that quietly do their job while everyone else moves on.

This system is still running. Quietly. Reliably. That's the kind of win I'm most proud of.

## Skills Demonstrated

Java, Spring Boot, stateful job processing, persistent log design, idempotent send tracking, email HTML/CSS inlining, Brevo API, resumable batch processing

## Author

Francis Jeremiah Sharon  
https://francisj2nd.cv  
me@francisj2nd.cv  
https://www.linkedin.com/in/francisj2nd/
