Full-Stack AI Outreach SaaS
Upload your prospect list and get a personalized, deliverability-safe cold-email sequence running in minutes — no templates, no copy-paste. Per-contact AI personalization grounded in real scraped signals; crash-safe pipeline with idempotent state.
heads-up: the live demo auto-logs you into a pre-seeded sandbox workspace. Click through real campaigns, AI-written emails, the funnel dashboard, and the reply inbox — sending and account changes are disabled by a backend guard, so nothing real fires.
The system, in one frame.
Frontend talks to FastAPI. FastAPI owns all state. n8n does the work. External services handle the heavy lifting.
- · Owns ALL state — single source of truth
- · Idempotent mutating endpoints
- · Auth · CSV ingest · AI orchestration · tracking pixel
- · Per-workspace RLS (multi-tenant boundary)
- · jobs table = work queue
- · Realtime publications → live UI
- · Enrichment · Send Sequencer
- · Reply Poller · Follow-up Scheduler
- · Validate + A/B + CRM sync
n8n workers are stateless and only call back through idempotent endpoints — retries never double-send.
Any worker can crash and resume exactly where it stopped. No Celery, no broker, no extra infra.
Every row is workspace-scoped at the database layer. Backend forgets a check, the DB refuses the operation.
Real-time UI + deliverability-aware sending, all on free tiers. Scales by upgrading tiers, not rewriting.
Ten stages, CSV in to analytics out.
Every stage is a retryable database job. Worker crashes mid-stage? Pipeline resumes from the next attempt.
CSV upload
FastAPI validates the file, inserts prospects, and creates one "enrich" job per row — all in one transaction.
Enrich
Playwright scrapes the prospect domain · Groq Llama 3.1 8B extracts structured signals (industry, tech stack, news, hiring).
Generate email
Groq Llama 3.3 70B writes a ≤120-word personalized email grounded in the scrape. No "I"-openers, no banned phrases, one CTA.
A/B variant
Optional subject-line variant assigned when A/B testing is on for the campaign.
Review & approve
Every draft lands in the Email Review screen. Human approval is required before anything sends.
Send
n8n picks a warmed-up sending account under its daily cap, injects the open pixel, and sends via Resend.
Track
Unique opens via 1×1 pixel · bounces & complaints via Resend webhook (Svix-signed) auto-dock reputation.
Detect replies
Reply Poller reads each sending account's inbox via the Gmail REST API · LLM classifies sentiment.
Follow-up / CRM
Auto follow-ups for non-repliers past the cadence window · positive replies sync to HubSpot.
Analytics
Nightly pg_cron snapshots + live denormalized counters keep the dashboard sub-second on free-tier Postgres.
Most cold-outreach tools mail-merge {{first_name}}into a static template — every prospect gets obviously-automated spam. The handoff between "send" and "reply came back" is broken too — reps lose replies in a shared inbox. Real personalization requires per-company research no one has time to do at scale.
A SaaS that scrapes each prospect's site, extracts real business signals, and writes a genuinely specific email per contact with an LLM. Routes it through an approval step, sends on a warmed-up schedule, tracks opens, and detects + classifies replies so nothing falls through.
From CSV to live sequence.
What a real customer actually does. Seven steps from sign-up to active outreach with replies routed back.
Sign up / log in
Supabase Auth — email + password with full forgot/reset flow. Each user belongs to a workspace.
Upload prospect CSV
Required columns: company, domain. Optional: first_name, last_name, email, title, linkedin_url. The parser strips BOM, lowercases headers, skips invalid rows, and reports how many were inserted.
Configure the campaign
Pick a system template (e.g. "SaaS to SMB"), write a brand context (what you sell + value prop), choose a tone (Professional / Friendly / Direct / Casual), set follow-up cadence, optional custom AI instructions, toggle A/B subject testing.
AI personalizes each contact
Per prospect, a Playwright scrape feeds an extraction model, then a quality model writes a ≤120-word email using industry, product, tech stack, recent news, hiring signals, and a unique angle.
Review & approve
Every draft lands in the Email Review screen. The user reads, optionally edits inline, then approves individually or with one Approve-all click. Approval queues a send.
Sequences execute
n8n picks up send jobs, selects a warmed-up sending account under its daily limit, injects a tracking pixel, and sends via Resend. A scheduled poller checks for replies; a follow-up scheduler queues next steps for non-repliers.
Dashboard + replies
Live dashboard shows the funnel (prospects → enriched → approved → sent → opened → replied). Replies hit an Inbox with AI sentiment (positive/neutral/negative/unsubscribe) and a one-line summary. A reply auto-cancels pending follow-ups; unsubscribes are honored automatically.
Real personalization. Real signals.
Two sanitized examples — what the AI sees, and what the prospect receives. Every opening line is grounded in a real scraped signal.
{
"industry": "freight & logistics",
"main_product": "regional LTL shipping",
"recent_news": "launched real-time tracking portal v2 last month",
"job_listings": ["Operations Analyst", "RevOps Manager"],
"intent_signals": ["ops_maturity"],
"unique_angle": "real-time visibility focus"
}Launching the v2 tracking portal last month says Northwind is doubling down on operational visibility — usually the same moment manual ops work starts eating the team alive.
We automate the repetitive ops layer (lead enrichment, outreach, CRM updates) so your analysts spend time on logistics, not spreadsheets — most teams claw back 10+ hours a week.
Worth a 15-minute look at where it'd save Northwind the most time?
Best, Kedrich — Kedrich Automation
{
"industry": "DTC skincare",
"main_product": "clean-ingredient skincare bundles",
"team_size_signal": "small",
"recent_news": "expanded into subscription bundles",
"unique_angle": "founder-led, lean team"
}Moving Brightwave into subscription bundles is a smart retention play — and a brutal amount of manual follow-up for a lean founder-led team.
We automate the outreach and follow-up busywork (personalized emails, replies routed for you) so you stay focused on product, not your inbox.
Open to a quick 15-minute walkthrough of how it'd fit Brightwave?
Best, Kedrich — Kedrich Automation
Tenancy at the database.
Every tenant boundary is enforced by Supabase RLS. Even if the backend forgets a workspace check, the database refuses the read or write.
workspaces ──< workspace_members >── auth.users │ ├──< campaigns ──< prospects ──< emails ──< replies │ │ │ └──< events │ └──< ab_variants ├──< sending_accounts jobs (work-queue, entity_id → prospect/email) ├──< integrations analytics_snapshots └──< unsubscribes
workspace → campaigns → prospects → emails → replies / events
users ↔ workspaces via workspace_members
Supabase RLS + backend membership check on every request. Every row carries workspace_id.
Each tool, its job.
The non-obvious calls.
Seven trade-offs that shaped the system more than the spec did.
Every unit of work is a retryable DB row. Crashed n8n workers resume exactly where they stopped, and the free stack needs no broker (Redis/RabbitMQ). The cost of operating Celery on a portfolio-scale system isn't justified.
n8n never writes Supabase directly. Every status change goes through an idempotent FastAPI endpoint, so retries can't double-send or double-create. n8n is workflow logic; FastAPI is the source of truth.
Cheap 8B model handles structured extraction from messy scraped HTML; 70B writes the copy. One AI_PROVIDER env var swaps Groq→GPT-4o for demos. Prompt strategy bans generic phrases and forces one company-specific opener.
IMAP hangs from datacenter IPs (Render). Direct REST over httpx (no discovery-doc fetch) is reliable, async-native, and handles the dot/+tag address-equivalence problem cleanly.
5 → 90 sends/day over 10 days, with per-account limits and reputation scoring. Bounces auto-dock reputation and can auto-pause an account. Protects deliverability — most AI-email demos ignore this and burn their domains.
A unique idempotency_key prevents n8n retries from double-creating or double-sending. Combined with the FastAPI-owned-state rule, the pipeline is exactly-once even with at-least-once delivery upstream.
Nightly pg_cron rollups + denormalized counters keep the dashboard sub-second on free-tier Postgres. Running heavy aggregates on every dashboard load would have killed it at any real scale.
What broke. How I fixed it.
Gmail throttles datacenter IMAP. Reply detection silently failed in production but worked locally. Rewrote the entire reply-detection layer on the Gmail REST API — async, no throttling, no discovery-doc fetch.
The model would invent plausible "v1.1 releases" when the scrape returned thin data. Fixed by constraining the prompt to ONLY reference scraped signals, with a safe fallback to generic-but-true angles when the scrape is empty.
Replies arrive from kedrichdev@ while the prospect is stored as kedrich.dev@. Matching now normalizes Gmail addresses (strip dots, strip +tag) before attribution.
A sending account in a different workspace than its prospects made reply-matching return nothing — no errors, just zero matches. Now enforced and aligned at the DB layer. Cost hours to find.
A real DB error surfaced in the browser as a CORS failure, because the 500 response skipped CORS middleware entirely. Fixed the underlying query; added explicit CORS headers to error responses.
Gmail's image proxy prefetches the tracking pixel server-side, inflating open counts. Now counting unique opens (first load per email only).
The automation + the database.
Supplementary technical material — the 5 n8n workflows that do the work, plus the Supabase schema and the RLS policies that enforce multi-tenancy at the database layer. Click any to expand.










Things worth pointing out.
Banned-phrase list, mandatory company-specific opener, ≤120 words, dual HTML/text output, and strict grounding in real scraped signals (not hallucinated specifics). The prompt is a contract, not a suggestion.
DB-as-queue means any worker can die mid-run and the pipeline self-heals. FastAPI is the single source of truth with idempotency on every mutation — retries are safe, no double-sends.
Warmup ramp, per-account daily caps, reputation scoring, bounce auto-pause, Reoon pre-validation, honored unsubscribes. Most "AI email" demos skip all of this and torch their sender domains in week one.
Supabase Realtime for live status with pre-computed analytics. Sub-second on a 100% free-tier stack. Heavy aggregates never run on the request path.
Built. Validated. Not yet public.
Full pipeline (enrich → generate → approve → send → open → reply → classify → analytics) confirmed end-to-end against real inboxes. No external users yet — the public read-only demo is the way to evaluate it today.
The roadmap to public self-serve.
What lands next — in rough order of impact.
The #1 blocker for true self-serve. Once Gmail OAuth is verified, users can connect their inbox in two clicks and the demo opens to the public.
Helper already exists (Fernet); rolling it out across all stored credentials is on the near-term roadmap.
LinkedIn + SMS steps in a sequence (today: email only). Same n8n + jobs architecture handles it.
Schema already supports owner / admin / member. The UI surfaces the seats layer next.
Pipedrive, native HubSpot two-way sync (currently one-way: replies → HubSpot).
Draft suggested responses from reply sentiment — let the user just review and send.
Want outreach that
actually gets read?
Try the live demo first — see real campaigns, the AI personalization, and the reply inbox. Then book a call to talk about your stack.