- Problem
- Networking for internships means finding the right alumni, their work emails, writing personal notes, and following up weekly. Almost nobody keeps it up past the first few emails.
- My role
- Designed and built the entire product: search, enrichment, three mail transports, AI personalization, scheduling, billing. Co-founders own the business side.
- Stack
- Next.js · TypeScript · Tailwind · Prisma 6 on Neon Postgres · Auth.js v5 · Gmail API, Microsoft Graph, SMTP/IMAP · Claude · Stripe
- Outcome
- Live working beta on chirpmail.io with Free, Pro and Pro+ plans. Currently raising investment capital.

Problem
Cold outreach works for students because a real person ends up vouching for you. The loop itself is miserable: find the alum at the right firm, guess their work email, write something that doesn't read like a template, remember to follow up a week later, and keep a spreadsheet of who replied. Most people send five emails and stop.
Existing tools are built for sales teams. They send from shared domains that land in spam, cost more than a student spends on food, and treat a student looking for a coffee chat like an SDR running a sequence.
What I built
Chirp runs the whole loop. You describe who you want to meet — “IB analysts who went to my school” — and an assistant builds a boolean query, runs it against Google's public index of LinkedIn profiles, matches each person to a company domain and work email with a confidence score, writes a note that draws on your own profile and the affinity you searched for, and sends it from your own Gmail, Outlook, Yahoo or iCloud inbox in small batches inside your working hours.
Then it follows up in the same thread once a week with a new reason to reply, watches your inbox, and stops the moment someone answers. Reply rate by round, weekday and campaign tells you whether the second follow-up is doing the work.
- Next.js App Router on Vercel
- UI, API routes, and scheduled jobs for send windows and follow-ups
- Neon serverless Postgres via Prisma 6
- Campaigns, contacts, threads, send log, suppression list
- Auth.js v5
- Google OAuth scoped to gmail.send + gmail.readonly; Microsoft Entra ID scoped to Mail.Send + Mail.Read
- Mailbox interface
- One contract, three implementations: Gmail REST API, Microsoft Graph (Outlook / 365), and SMTP send + IMAP reply detection (nodemailer, imapflow) for Yahoo, iCloud, AOL, Zoho and custom servers
- Search
- Serper (Google Search API) with site:linkedin.com/in — reads only what Google already shows publicly
- Email discovery chain
- Chirp's shared address directory → Hunter.io → first.last@domain pattern guess, each result carrying a confidence score
- Claude (Anthropic)
- Personalized emails through the Message Batches API, reply sentiment, resume parsing, and a tool-using assistant that builds and runs searches
- Guardrails
- Per-plan daily caps, send windows, bounce handling, suppression list, reply check before every follow-up
- Stripe
- Checkout, Billing Portal and webhooks for Free, Pro and Pro+
Technical decisions
- 01
Send from the user's own inbox instead of a shared sending domain.
A note from a student's own address lands in the inbox and reads as a person; the same note from a SaaS domain reads as a sequence and often lands in spam. It also means Chirp never holds a sending reputation that one bad user could burn.
Trade-offThree mail transports to build and keep working — Gmail, Graph and raw SMTP/IMAP — instead of one API call to a sending service.
- 02
Put every provider behind one Mailbox interface.
Send, list replies and detect bounces are the only operations the rest of the app needs. Campaign logic, scheduling and analytics never know which provider they are talking to, so adding another provider is a new adapter, not a new code path, and Zoho or a custom server is just configuration on the SMTP/IMAP one.
- 03
Search Google's public index instead of scraping LinkedIn.
Scraping LinkedIn violates its terms and gets user accounts banned. Serper's Google Search API with site:linkedin.com/in returns the same public profile snippets Google shows anyone, so Chirp never signs into LinkedIn and never touches a user's account.
Trade-offResults are limited to what Google indexes and snippets are shorter than a full profile, so the assistant works harder to build precise boolean queries.
- 04
Generate personalized emails through Claude's Message Batches API.
Sends are scheduled into working-hour windows anyway, so nothing about personalization needs to be interactive. Batching halves the per-token cost, which is what makes 1,500 AI-personalized emails a month workable at $19.99.
Trade-offA batch can take up to 24 hours (usually far less), so the scheduler queues notes well ahead of each send window instead of writing them at send time.
- 05
Find emails cheapest-first, with a confidence score on every result.
Hunter.io charges a credit per address. Chirp checks its own shared directory first (free), then Hunter, then falls back to a first.last@domain guess — and tells the user which tier the address came from so a pattern guess is never mistaken for a confirmed one.
- 06
Make the limits product features, not fine print.
Daily caps, send windows, a suppression list and stop-on-reply are what keep a student's inbox from getting flagged and keep recipients from hearing from you twice after saying no. They ship on every plan, including Free.
- 07
Encrypt app passwords with AES-256-GCM and request the minimum OAuth scopes.
SMTP/IMAP providers need a stored credential; AES-256-GCM gives confidentiality and tamper detection with one key. OAuth providers get only gmail.send/gmail.readonly and Mail.Send/Mail.Read, so Chirp can never do more with an inbox than send and read replies.
Outcome
- Live working beta at chirpmail.io with the full loop end to end: search, enrichment, personalized sends, threaded follow-ups and per-round analytics.
- Three plans in production through Stripe: Free (10 emails a day, templated), Pro at $19.99 (100 a day, 1,500 AI-personalized a month) and Pro+ at $49.99 (500 a day, 4,000 a month).
- Currently raising investment capital with co-founders handling the business side; I own the product and the codebase.
Stack
- TypeScript
- End to end, including the Mailbox contract every provider implements
- React
- Dashboard, campaign builder and analytics UI
- Next.js
- App Router UI, API routes and scheduled jobs on Vercel
- Tailwind CSS
- Styling for the dashboard and marketing site
- Node.js
- Runtime for API routes and the mail adapters
- Prisma
- Prisma 6 for typed data access and migrations
- PostgreSQL
- Campaigns, contacts, threads, send log and suppression list
- REST API design
- Internal API routes consumed by the dashboard
- OAuth 2.0
- Auth.js v5 with Google and Microsoft Entra ID, minimum mail scopes
- Stripe
- Checkout, Billing Portal and webhooks for three plans
- Vercel
- Hosting, preview deployments and cron
- Neon
- Serverless Postgres
- Gmail API
- Send and reply detection for Google accounts
- Microsoft Graph
- Send and reply detection for Outlook and Microsoft 365
- Claude API
- Personalized emails via Message Batches, reply sentiment, resume parsing, tool-using assistant
- Agentic workflow design
- An assistant that builds a boolean query, runs it and pulls emails
- AES-256-GCM encryption
- At-rest encryption for stored app passwords
- Rate limiting & send windows
- Per-plan daily caps and working-hour send windows
- Webhook handling
- Stripe subscription lifecycle events
- IMAP / SMTP
- nodemailer + imapflow adapter for Yahoo, iCloud, AOL, Zoho and custom servers