The sender itself is a modest program: import leads, send a few timed steps from your own mailboxes, thread the follow-ups, stop on reply or bounce, and honour opt-outs. An agent writes that in an evening on SMTP and IMAP. The weekend goes on what keeps mail out of spam: per-mailbox caps with random gaps, bounce parsing, SPF, DKIM and DMARC for every sending domain, and a reply inbox you can trust. Smartlead's warm-up pool, placement tests and lead credits are services built on other people's mailboxes and data, so they stay out of a personal build.
Before you buildSmartlead has no free plan, only a trial. Run the trial on a real list before you build, so you know which parts you use.
Build me a self-hosted cold-email sender to replace Smartlead for one small list. Requirements:
- Node.js 22 + TypeScript: a Fastify server with server-rendered pages (Eta) and htmx. `npm start`
serves http://localhost:4900 behind one admin password from .env (signed cookie).
- Storage: better-sqlite3 in ./data/outreach.db: mailboxes, leads (email, name, company, custom
fields as JSON), campaigns, sequence steps (delay in days, subject, body), sends, replies,
bounces and a global suppression list.
- Mailboxes: any number of SMTP and IMAP accounts added in the UI, passwords encrypted with
APP_SECRET from .env (AES-256-GCM). Each has a daily cap, a sending window and a minimum gap
in seconds plus random jitter. A "send test" button mails me from the chosen mailbox.
- Import: CSV upload with column mapping; reject malformed addresses with `validator`, skip
anything on the suppression list, dedupe on the lowercase address.
- Sending: a worker (`croner`, every minute) picks the next due step per lead, rotates across the
campaign's mailboxes within their caps, fills {{first_name|there}} and {a|b} spintax, adds
List-Unsubscribe and List-Unsubscribe-Post headers, and keeps follow-ups in one thread with
In-Reply-To and References.
- Replies: poll IMAP with `imapflow` every 2 minutes and match on References. Stop the sequence
on a reply, on a bounce (parse the DSN with `mailparser`) or on an unsubscribe click at /u/<token>.
- Inbox and reports: one list of replies, labelled by hand as interested, not interested or out
of office, answered from the mailbox that sent the original; sent, replied, bounced and
unsubscribed per campaign and mailbox; pause a mailbox when its bounce rate passes 3% over
its last 100 sends.
- Single user. No accounts, no telemetry, local-first. Outbound calls: your SMTP and IMAP servers.
- Out of scope: warm-up networks, lead databases, email verification, LinkedIn steps, open and
click tracking pixels, client workspaces.
- README: SPF, DKIM and DMARC per sending domain, a reminder that many countries require a
postal address and a working unsubscribe in commercial email (CAN-SPAM, GDPR and PECR), and
a warning that Gmail and Outlook can throttle a new mailbox whatever this code does.Opens your agent with the prompt filled in, you press enter. Or copy it and paste it into an empty folder.
The first prompt builds the core. Run these one at a time in the same folder to grow it into your own Smartlead.
Add a ramp-up schedule to the cold-email sender in this folder. Requirements: - Each mailbox gets a start date and a ramp plan: a daily cap that grows by a fixed step every few days (default 5 on day 1, +3 every 3 days) up to its configured maximum. - The worker uses min(ramp cap, configured cap) and shows today's cap and a progress bar on the mailbox page. - If bounces exceed 3% over the last 50 sends, hold the cap where it is for 7 days and show a warning in the dashboard. - Add tests for the cap calculation across the first 30 days. - Update the README with how ramping works and what it cannot guarantee.
Add address checking to the cold-email sender in this folder. Requirements: - Before a lead's first send, check syntax, then MX records with node:dns, and drop role addresses (info@, sales@) unless the lead is marked "keep". - If REACHER_URL is set in .env, call a Reacher backend for the mailbox check and store the result (safe, risky, invalid, unknown) with a timestamp; otherwise skip that step. - Skip invalid leads, hold risky and unknown ones in a review list, and cache results for 30 days. - Show a per-list summary of how many addresses fell in each bucket. - Update the README with the note that SMTP checks need outbound port 25, which many hosts block.
Add reply classification to the cold-email sender in this folder. Requirements: - When a reply arrives, send its text (not the quoted thread) to an OpenAI-compatible endpoint from .env and ask for one label: interested, not interested, out of office, wrong person or unsubscribe request, plus a one-line reason. - Show the label as a suggestion next to the reply; I confirm it with one click. Never act on a suggestion automatically, except that an "unsubscribe request" label adds the sender to the suppression list only after I confirm. - Store label, reason and the model name; keep the prompt in a file I can edit. - Update the README with what text leaves the machine when this is enabled.
Cold email lives or dies on deliverability, and Smartlead sells one price for unlimited mailboxes, a rotation engine and a warm-up pool, so growing from two inboxes to twenty does not raise the bill. Agencies add client workspaces and white-labelling. Public threads are mixed: some users praise the reply labelling, others report deliverability swings, a warm-up pool they cannot control and add-ons that make the bill climb.
Estimate · Mailboxes and sending domains are the real cost and you pay them with Smartlead too: its own list prices a Google or Outlook mailbox at about $4.50 a month and a domain at about $13 a year. The build is token usage on your agent plan.
Checked 2026-10-19 against Smartlead's docs: 1, 2, 3, 4, 5, 6, 7
| Plan | Monthly | Annual, per month | What you get |
|---|---|---|---|
| Base | $39 | $32.50 | 2,000 contacts and 6,000 sends a month, unlimited connected mailboxes, the Foundation tier of the warm-up pool; no CRM access, API or webhooks. |
| Pro | $94 | $78.30 | 30,000 contacts and 90,000 sends a month, CRM access, API and webhooks, the Growth tier of the warm-up pool; client workspaces and dedicated servers as paid add-ons. |
| Unlimited Smart | $174 | $144.50 | Unlimited contact storage, 150,000 sends and 50,000 verified prospect emails a month, the Premium warm-up pool, CSM call access. |
| Unlimited Prime | $379 | $314.60 | Unlimited contacts, 500,000 sends and 170,000 verified prospect emails a month, 3 SmartServers, 3 or more client workspaces, a dedicated manager and a private Slack channel. |
| SmartServices (managed) | custom | — | Done-for-you outbound at 50,000 or 100,000 emails a month: list building, copy, pre-warmed mailboxes and a GTM engineer. |
No free plan: every plan starts with a free trial and no card, but the pricing page does not say how long it lasts.
Kinda. The core is a weekend build with the prompt on this page, but real gaps remain: The warm-up pool that trades mail between mailboxes owned by other customers, Inbox placement tests and sender scoring through SmartDelivery.
About $39 a month on the Base plan, $468 a year (checked 2026-10-19).
The warm-up pool that trades mail between mailboxes owned by other customers; Inbox placement tests and sender scoring through SmartDelivery; Verified lead credits and the SmartProspect database; Client workspaces, white-labelling and dedicated sending servers; AI labelling of replies, a team master inbox and the API. If any of those matter to you, keep paying.
Yes: Warmbly (open source), Mautic (open source), lightreach (open source).