Building & Shipping

The 20 Emails I Sent Myself Before My First Customer Could

Brett Ridenour Brett Ridenour · Published July 2026

There is a very specific kind of SaaS failure I am afraid of. It’s the one where the code path succeeds, the API returns 200, the job runs green in the queue, the dashboard shows a happy checkmark — and no email actually leaves the building. The customer never hears from you. The trigger fired. The message never arrived.

Freebo’s first live tour operator was going to start booking customers the next morning. Real customers, real charge cards, real emails. Before that happened I wanted to know, with evidence, that every notification our platform sends could actually reach the person it was meant for. So I did the only reasonable thing: I flooded my own inbox with the entire lifecycle.

Twenty-plus emails. Booking confirmed, booking pending, waiver requested, waiver signed, payment received, payment failed, reminder 24 hours out, reminder 3 hours out, reminder 1 hour out, refund issued, reservation modified, reservation cancelled, staff alert on new booking, staff alert on modification, staff alert on cancellation. Customer audience and staff audience. Different templates, different senders, different reply-tos. All of it, at me, on staging, in about ninety minutes.

Why triggering is not the same as delivering

Most notification systems I’ve inherited fail the same way. A booking happens. The queue picks it up. The workflow fires. The activity log says “sent.” The customer never gets a thing. Somewhere between the trigger and the SMTP handoff, the sender identity was empty, or the domain wasn’t verified, or the subscriber record had no email attached, or the provider integration was configured in dev and never wired in prod.

The tell is the same every time — the system thinks it worked. It’s the inbox that doesn’t.

Freebo runs on Novu Cloud for orchestration, Resend for delivery, and React Email for rendering. Around 20 registered workflows across two audiences. Reminders that depend on an absolute remindAt timestamp and a step.delay inside the workflow. That’s a lot of surface area to hand-verify, and hand-verifying is exactly what nobody does before their first customer arrives.

The prompt is the audit

I didn’t write a QA checklist. I wrote a prompt and handed it to Claude Fable 5 at the repo root, with staging credentials and permission to send tests to my own inbox only. The prompt doesn’t tell it what to check. It tells it what “working” means and lets it design its own test plan.

Four questions, in order:

  1. What address is it sending from?
  2. Where is it going?
  3. What do they say?
  4. Is Novu set up right?

Everything else is a consequence. If you can answer those four with evidence from a live Novu activity feed and a real delivered email in a real inbox, you have proof. If you can’t, you have a launch-blocking gap.

The four questions the audit had to answer

The rest of the prompt is guardrails, not steps.

  • All hands-on testing happens on staging. Production is read-only.
  • Send only to addresses I control. Never touch a real customer or operator inbox.
  • Don’t print secret values. Reference env var names, not their contents.
  • Delivery over triggering. Every finding gets tied to file:line and a real, observable delivered message in the Novu Cloud activity feed.
  • Be adversarial. Try to make it send from the wrong address, to the wrong person, with broken content, at the wrong time, or not at all.

The last one is the important one. The default failure mode of an AI running QA is to confirm what the docs say. That is not QA. That is stenography.

Delivery over triggering. A workflow that fires successfully but delivers nothing is a failure.

— The one line that changed the audit

The definition of “working”

The prompt spends most of its length on this, because if you leave the definition to the auditor you get an auditor’s definition, which is always narrower than a customer’s definition. So I wrote out what “working” means, in blunt bullets:

  • Delivery is real, not just triggered. The proof is a delivered message in the provider’s activity feed, not a green trigger call.
  • Right sender. Every email comes from an intentional, verified From address with a sensible reply-to, on a domain with valid SPF/DKIM/DMARC so mail lands in the inbox and not in spam.
  • Right recipient, no leakage. Customer messages go to the customer. Staff messages go to the correct location’s staff and only that location’s staff.
  • Audience separation. Customers and staff get appropriately different messages — a branded guest email versus an operational staff alert — not the same template with a different subject line.
  • Right content. Subjects and bodies are correct, branded, free of undefined, NaN, raw ISO timestamps, or placeholder strings.
  • Correct timing. Reminders fire before the event, not immediately at booking. Scheduled notifications stay in sync when a reservation is rescheduled or cancelled.
  • Settings honored. If the operator toggles email off, email is off. If they toggle it on, email is on.
  • Non-blocking. A notification failure never fails or delays the underlying booking, payment, or waiver operation.

Any auditor reading that has a job. There is no wiggle room to declare success by ignoring one of the bullets.

What ninety minutes of self-inflicted email looks like

The output was two things: a signed go/no-go verdict at the top of a report, and a table of every workflow with its audience, recipient resolution, subject, and delivery status from the staging tests. Plus GitHub issues for anything that came back CONFIRMED broken.

  1. T+0
    Sender identity check
    Novu Cloud Resend integration inspected. From address, from name, verified domain, DNS records for SPF/DKIM/DMARC. Recorded as evidence, not as a screenshot.
  2. T+10m
    Real booking on staging
    Create reservation via the customer checkout flow. Confirm two deliveries land at my inbox — the customer confirmation, the staff alert — with the right templates and the right recipients.
  3. T+25m
    Payment path
    Stripe test card. Payment received. Payment failed. Refund. Three separate deliveries, one at each state.
  4. T+40m
    Waiver path
    Waiver requested. Waiver signed. Confirm the request goes to the customer and the signed notice goes to staff.
  5. T+55m
    Reminder proof
    This is the one that used to fail. Reminders that should fire 24h / 3h / 1h before the event, not now. Verified against the delay step in the workflow and the activity feed.
  6. T+70m
    Modification and cancellation
    Reschedule the reservation. Cancel it. Confirm the scheduled reminders got cancelled too, and that both customer and staff got the right message.
  7. T+85m
    Settings gate
    Toggle location-level email off. Trigger a booking. Confirm nothing sends. Toggle it back on. Confirm it does.

By the end my inbox had every state a customer could ever put a reservation in, and every staff alert that should follow. Nothing was left to imagination. Every claim in the audit report pointed to a delivered message with a Novu event ID and a rendered body I could open in Gmail.

The framing that actually helps

Two things I would say to my past self.

Don’t ship a “notifications work” claim on typecheck evidence. Typechecks prove the code compiles. Unit tests prove the render function doesn’t throw. Neither proves an email reached an inbox from a verified sender with a rendered body a human would understand. The only thing that proves delivery is a delivered message. Anything else is faith.

Write the definition of “working” before you hire the auditor. If the definition lives in your head, the audit will find whatever the auditor thinks is important. If the definition is in the prompt — every bullet, every failure mode you’re afraid of, every gate you want honored — the audit is scoped to your fear, not the auditor’s imagination. That’s the difference between a report you can act on and a report that reads like a book review of your codebase.

The first live customer booked the next morning. The confirmation email arrived. The reminder arrived 24 hours before their trip. That is not luck. That is 20 emails I sent myself the night before, in the right order, from the right sender, at the right person, with the right words. In production, no one applauds when notifications work. They only ever notice when they don’t.