Why my AI never sends emails
People hear "AI writes my follow-up emails" and assume the next sentence is "β¦and it sends them." It isn't. Nothing in my lead pipeline has permission to hit send, and that constraint is the most valuable design decision in the entire system.
This is the story behind dead-lead-followup: how it works, the guardrails that make its drafts worth reading, and the production scars that taught me why the draft step is non-negotiable.
The slow death of a lead
Dormant leads rarely die because someone said no. They die because nobody followed up. Manual follow-up is slow, inconsistent, and the first thing that falls off the plate during a busy week. Fully automated outreach fixes the consistency problem but introduces a worse one: robotic messages that burn relationships you spent months building.
So both extremes fail. Pure manual dies of neglect. Pure automated dies of cringe.
The middle path: machine speed, human judgment
The workflow takes a deliberately boring shape β five linear nodes:
- Every morning at 10:00, a schedule trigger fires.
- A ClickUp node fetches leads still marked
TO DOβ filtered server-side, inside the API query, not in post-processing. - An LLM agent writes a short, warm, three-sentence check-in for each lead.
- The email lands as a Gmail draft with an HTML call-to-action button. Never sent. Never.
- The task flips to
Draft Done, waiting for a human to review and press send.
TO DO ββ(AI draft created)βββΊ Draft Done ββ(human sends)βββΊ Follow-up Sent
The board is the database. Nothing gets sent without a draft existing first, and every state transition reflects back onto the task itself. That single invariant powers duplicate protection for free: tomorrow's run skips anything that already advanced.
Why drafts, specifically
Do the worst-case analysis. Ask not "will the automation work?" but "what happens on the worst day of its life?"
- A runaway loop fills your drafts folder. Annoying, not catastrophic. Nobody outside your inbox knows it happened.
- A hallucination gets caught by a human eyeball at review time instead of by an angry recipient.
- You remain the sender of record. Every email carries your judgment, even when the typing was done by a machine.
- Even a leaked credential can't email anyone. The draft-only design means the blast radius of total system compromise is⦠a tidier to-do list.
Show me a fully-autonomous outreach bot whose failure modes are that gentle.
Guardrails that make drafts worth reading
Drafts only save time if they're actually sendable. Four constraints do the heavy lifting:
- Personalization comes from real fields, not vibes. The prompt receives the lead's name, company, and original interest notes from ClickUp custom fields. Task titles are a last-resort fallback only.
- The model may not invent URLs. Prompt-level ban. The only clickable link in any draft is my booking button β which kills the classic "AI confidently linked to a similar-looking company" failure.
- Fields resolve by name, not position. Custom fields are regex-matched by name, so someone reordering columns on Tuesday doesn't break greetings on Wednesday.
- Status updates are atomic with drafting. The
Draft Doneflip happens in the same run, so a retried or partially-failed execution can't double-contact anyone.
What production taught me
These aren't hypotheticals. Every one of these cost me a debugging session:
- Omitted parameters fall back to dangerous defaults. n8n's ClickUp node defaults its operation to create. A node missing an explicit
operation: getAlldidn't fail β it tried to write new tasks. Always declare resource and operation, even when the panel looks right. - Status names match word-exactly. Case is forgiven (
IN PROGRESSequalsin progress); words are not. Updating withCOMPLETEDwhen the board sayscompletereturns a 400. Check the board's own slugs first. - Positional field access is a time bomb.
custom_fields[1].valueworks beautifully until the day it doesn't. Name-match everything. - Task title β person name. Boards collect descriptive titles like "Leads Pipelines" while the human's actual name hides in a custom field. Greeting someone as "Leads Pipelines" is a great way to be ignored forever.
- Stale editor tabs revert API edits silently. Automation platforms cache canvas state per tab. If the workflow changed via API while an old tab held it, saving that tab rolls everything back. One writer at a time, and keep JSON backups in git.
So would I ever let it send?
Honestly β parts of this are heading that way, carefully. The roadmap includes sweeping Draft Done tasks against the Gmail sent folder to auto-mark Follow-up Sent, reply detection so follow-ups stop on answered threads, and calendar events created straight from booking submissions. Those are mechanical steps with verifiable outcomes, exactly where autonomy belongs.
But first-touch outreach stays human-approved. The rule I've settled on: automation should delete drudgery, not judgment. Remembering, drafting, filing β that's machine work. Deciding β that stays mine.
The potatoes get mashed. The emails get approved. π₯
Built this pattern into something you want running on your own leads? The sanitized workflow and full setup guide live in the repo, and I'm always up for talking shop on Telegram.