Skip to content
VyoumPublic

About

A cold mailing agent that will completely change the way we used to outreach before

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

23 Commits

Folders and files

Repository files navigation

Anvil

Sheets-driven cold mailing agent: pull leads from Google Sheets → write personalized emails → rotate across multiple SMTP inboxes → send on a cron schedule → track opens/clicks/unsubscribes.

What you need

  1. A Google Sheet of leads
  2. A Google Cloud service account with access to that sheet
  3. One or more SMTP mailboxes (Gmail app passwords, etc.)
  4. Optional: OpenAI API key for AI-written emails

Sheet format

First row = headers. Only Email is required. Flexible header names are accepted:

Column Aliases Required
Email email, e-mail yes
First Name firstName, name no
Company organization, org no
Industry vertical, sector no
Context notes, personalization, hook no
Class Link link, url, cta link no
Status outreach status no (written back if present)
Last Step step no (written back if present)

Share the sheet with your service account email (Editor).

Setup

cp .env.example .env
# fill in GOOGLE_*, SMTP_* (or SMTP_INBOXES), and optionally OPENAI_API_KEY
npm install

Multi-inbox

Either use a single mailbox (SMTP_USER / SMTP_PASS) or set SMTP_INBOXES to a JSON array (see config/inboxes.example.json):

# minify the example JSON into one line for .env
SMTP_INBOXES='[{"id":"alex","fromName":"Alex","smtpHost":"smtp.gmail.com","smtpPort":587,"smtpUser":"...","smtpPass":"...","dailyLimit":40,"hourlyLimit":8}]'

Behavior:

  • Round-robins across healthy inboxes, preferring the least-used today
  • Each inbox has its own daily/hourly cap
  • Follow-ups stick to the same inbox that sent the first email (so threads stay clean)
  • Usage is persisted in data/inboxUsage.json

Run once

npm run dry-run
npm start
npm start -- --name "SaaS founders Q2" --limit 20

Cron (hands-off daily sends)

# Keep this process running — fires on CRON_SCHEDULE (default: weekdays 9am Asia/Kolkata)
# Also starts the tracking server when CRON_WITH_SERVER=true
npm run cron

# Fire one scheduled tick now (useful to test)
npm run cron:once

# Fire immediately on worker boot, then keep schedule
CRON_RUN_ON_START=true npm run cron

Re-runs of the same CAMPAIGN_NAME resume paused campaigns and only send the next follow-up when the day offset is due (day 0 → 3 → 7 → 14).

Tracking server only

npm run server

Endpoints: /health, /track/open/:emailId, /track/click/:emailId, /unsubscribe, /webhooks/email, /analytics/:campaignId, /inboxes

Docker

docker build -t anvil .
# Recommended: cron worker + tracking server together
docker run --env-file .env -p 3000:3000 anvil
# One-shot campaign
docker run --env-file .env anvil node src/workflows/coldMailWorkflow.js

Project layout

src/
  agents/          # lead extract, write, send, campaign orchestration
  services/        # Google Sheets, SMTP, inbox pool, OpenAI
  jobs/cronRunner.js
  workflows/       # one-shot CLI entrypoint
  app.js           # tracking + unsub HTTP server
config/inboxes.example.json
data/              # local JSON logs (campaigns, sends, inbox usage, unsubs)

About

A cold mailing agent that will completely change the way we used to outreach before

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages