High-scale email outreach system: CSV import, enrichment, verification, AI personalization, and email sending.
- Database: Supabase (PostgreSQL)
- Background Jobs: Trigger.dev (batch processing)
- Email Sending: Instantly
- Email Enrichment: Prospeo (bulk API), Icypeas (fallback)
- Email Validation: Icypeas (bulk API)
- AI Personalization: OpenAI (gpt-4o-mini)
- Node.js 18+
- npm or pnpm
- Accounts for: Supabase, Trigger.dev, Prospeo, Icypeas, OpenAI, Instantly
npm installcp .env.example .envEdit .env and fill in your API keys:
| Variable | Description |
|---|---|
SUPABASE_URL |
Your Supabase project URL |
SUPABASE_SERVICE_KEY |
Supabase service role key |
PROSPEO_API_KEY |
Prospeo API key for email enrichment |
ICYPEAS_API_KEY |
Icypeas API key for email validation |
OPENAI_API_KEY |
OpenAI API key for icebreaker generation |
INSTANTLY_API_KEY |
Instantly API key |
INSTANTLY_CAMPAIGN_ID |
Your Instantly campaign ID |
TRIGGER_SECRET_KEY |
Trigger.dev secret key |
ICEBREAKER_PROMPT |
AI prompt template for personalization |
Run the migrations in your Supabase SQL editor in order:
supabase/migrations/001_initial_schema.sqlsupabase/migrations/002_remove_campaigns.sqlsupabase/migrations/003_add_enrichment_tracking.sql
Insert a mapping in Supabase that matches your CSV format:
INSERT INTO csv_mappings (name, field_mappings) VALUES (
'Apollo Export',
'{"Email": "email", "First Name": "first_name", "Last Name": "last_name", "Company": "company_name", "Title": "job_title", "Website": "website", "LinkedIn URL": "linkedin_url"}'
);node --loader ts-node/esm scripts/import.ts --file leads.csv --mapping "Apollo Export"Start the Trigger.dev dev server:
npm run trigger:devThen trigger the pipeline:
# Full pipeline (enrich + verify)
npx trigger.dev run pipeline-orchestrator --payload '{"mode":"both"}'
# Enrichment only
npx trigger.dev run pipeline-orchestrator --payload '{"mode":"enrich"}'
# Verification only
npx trigger.dev run pipeline-orchestrator --payload '{"mode":"verify"}'
# Test with limited leads
npx trigger.dev run pipeline-orchestrator --payload '{"mode":"both","maxLeads":250}'After enrichment completes:
node --loader ts-node/esm scripts/process.ts --steps personalize,pushPreview icebreakers with 3 sample leads:
node --loader ts-node/esm scripts/process.ts --test-icebreaker/
├── trigger/ # Trigger.dev tasks
│ ├── enrich.ts # Batch enrichment (50 leads)
│ ├── verify.ts # Batch verification
│ └── orchestrator.ts # Pipeline orchestrator
├── lib/ # API clients
│ ├── supabase.ts # Database
│ ├── prospeo.ts # Email enrichment
│ ├── icypeas.ts # Email validation
│ ├── openai.ts # AI personalization
│ └── instantly.ts # Email sending
├── scripts/ # CLI tools
│ ├── import.ts # CSV import
│ └── process.ts # Personalize + push
└── supabase/
└── migrations/ # Database schema
Deploy Trigger.dev tasks to production:
npm run trigger:deployPrivate - All rights reserved