- White-label · built with Matteo Caruso
- 2026
- Handover
Find them. Email them. Catch every reply.
A marketing team was running outreach from spreadsheets. I replaced it with one app: a lead finder, campaigns sent from the team’s own Microsoft 365 mailboxes, and a CRM where no reply gets lost.
Spring outreach
Sequence progress
Latest replies
- DWDana WhitfieldSounds interesting, can you send times?New reply
- LOLuis OrtegaWhat does this cost for a team of 5?Asked a question
- TBTom BeckerYes, let’s talk next week.✦ Ready for a call
Recreated in HTML with demo data. The real app stays private.
Built with Matteo Caruso. Matteo runs the client relationship. I designed and built the system under his name, so the client stays private.
The problem
Outreach lived in a spreadsheet.
Leads were found by hand, emails were copy-pasted one at a time, and replies got lost across inboxes. Matteo brought me in to build one system for all of it, under his name.
01 · Find
Leads, without the copy-paste.
Filters, one search bar, saved searches or the team’s own CSV. One search runs every chosen source, merges what it finds, drops anyone already in the CRM and ranks the rest. Every address is verified before anything is sent.
- 09:41:02 · Sources started · 3 running
- 09:41:20 · Directory search · 18 people so far
- 09:41:37 · Website emails · 11 found
- 09:41:52 · Duplicates removed · 3 already in the CRM
- 09:42:05 · Ranked by relevance · 29 new leads
| Name | Email check | |
|---|---|---|
| Dana WhitfieldHead of Marketing | Valid | |
| Luis OrtegaFounder | Valid | |
| Priya RamanOperations Lead | Catch-all | |
| Tom BeckerCEO | Valid | |
| Ana CostaEvents Manager | Invalid | |
| Kenji MoriOffice Manager | Valid |
02 · Send
Campaigns that send themselves, carefully.
A campaign is a lead list, a sequence of emails and a schedule. It sends from the team’s own Microsoft 365 mailboxes, follow-ups land in the same thread, and a reply stops the sequence for that person.
Daily limit per mailbox
First week: 20 a dayThen +5 a day, up to 50
Template
Quick question, {{first_name}}
Hi {{first_name}}, I came across {{company}} and loved what your team is building. Would a short call next week be useful?
{{sender_name}}
Live preview for Dana · Northwind
FromSam Taylor
Todana@northwind.co
SubjectQuick question, Dana
Sam
A lead missing a variable is skipped with a note. Nothing goes out half-filled.
03 · Catch
Every reply, in one inbox.
The engine reads every mailbox each minute. A real reply stops the sequence and lands in the Unibox as New reply. An out-of-office is logged and the sequence carries on. A bounce goes straight to do-not-contact.
- New replysequence stops
- Out of officesequence carries on
- Bounceddo-not-contact
Sounds interesting, can you send a couple of times for next week?
04 · Close
A pipeline the team moves by hand.
Everyone who replied sits on a drag-and-drop board, with search, filters and a detail panel for each lead. The app only ever sets New reply. Every other status is a person’s call.
New reply2
Asked a question1
Interested1
How I built it
The schedule lives in the database.
A schedule inside Supabase (pg_cron) runs the engine every minute, so nothing depends on someone keeping a laptop open. Mailbox credentials sit in an encrypted vault, and row-level security decides who sees what. About ten days from scope to a working app.
- Failures that aren’t the lead’s fault never cost the lead its email.A full mailbox or a wrong secret pauses sending with Microsoft’s reason, and throttling just waits. The lead keeps its place.
- An email Microsoft didn’t confirm is never retried.If a send can’t be confirmed, it is skipped, not repeated. Nobody gets the same email twice.
- No open tracking. People set the status.The app only marks New reply when an answer arrives. Interested, Ready for a call and the rest are a person’s call.
- Catch-all addresses are capped at 20%.Addresses that can’t be fully verified still go out, but never more than a fifth of a mailbox’s sends.
$ vitest run
- ✓sends inside the window on a weekday, never outside it
- ✓follows the ramp: 20 a day for the first week, then +5 a day
- ✓sends at most one email per mailbox per round and spaces them out
- ✓sends follow-ups after their delay, from the same mailbox, in the same thread
- ✓never sends a half-filled email: a lead missing {{company}} is skipped once, with a note
- ✓a reply in the thread stops the sequence and shows as New reply
- ✓an out-of-office answer is logged and the sequence carries on
- ✓a bounce marks the email bounced, puts the address on do-not-contact and stops the sequence
- ✓a timeout after Microsoft accepted the email counts as sent (no second send)
- ✓a database error after a successful send never sends the same step twice
- ✓an outage spreads its failures over different leads instead of using up one lead
- ✓a wrong app secret pauses every mailbox and uses up no lead; after Resume the email goes out
- ✓daylight saving day (25 hours): the limit holds and the window follows local time
- ✓never verify the same address twice (each check costs a credit)
- ✓HTML and header injection in lead data is escaped / flattened
- ✓only the owner sets or removes a key, and nobody signed in can read it back
- ✓the team always keeps an owner
Tests130 passed (130)
- Next.js 16
- React 19
- Tailwind 4
- Supabase
- Postgres + RLS
- Vault
- pg_cron
- Microsoft Graph
- Vercel
- Vitest
Where it is now
Handover.
The app is being handed over through Matteo, with a step-by-step Microsoft 365 setup guide and a plain-English running-costs sheet. Zero spreadsheets left.