Skip to content

pypesdev/inbox-warmer

Repository files navigation

inbox-warmer

Self-hosted inbox warm-up for cold-email senders. Bring your own seed pool of inboxes you already own, and let them quietly exchange real-looking emails so your sending domains build a clean reputation before your first cold campaign.

License: MIT Status: v0.1 alpha

Part of the pypesdev open-source stack. Pairs naturally with coldflow: warm your domains here, then send your real campaigns there.


Why this exists

The single biggest deliverability blocker for new cold-email senders is cold-domain reputation. Mailbox providers (Gmail, Outlook, Yahoo) have no engagement history for your domain, so even legitimate first sends drop straight into spam.

Inbox-warmer fixes this the boring, durable way: it sends small numbers of conversational, plain-text emails between Google Workspace inboxes that you own, on a jittered schedule, so providers see your domain participating in normal-looking back-and-forth before any real outreach happens.

Positioning: BYO seed pool (v1)

Most commercial warm-up tools work by joining all their users into one giant shared peer pool — your domain trades emails with strangers' domains. That's an abuse vector and a reputational risk: one bad actor in the pool can drag everyone down with them.

v1 is intentionally BYO seed pool. You connect 3–10 inboxes that you already own (different mailbox accounts on different domains, ideally on different providers). The worker only ever exchanges emails between inboxes in your own pool. We will never silently pair your domain with someone else's.

If you want the shared-pool model, this is not the tool for you (yet — see roadmap).

Status: v0.1 alpha (very early)

What works in v0.1:

  • ✅ Connect Google Workspace inboxes via full OAuth (Gmail API, refresh tokens stored encrypted at rest).
  • ✅ Heartbeat-style scheduled send: a cron tick picks one eligible (sender, recipient) pair from your pool and sends one short, plain-text, conversation-flavoured email.
  • ✅ Per-inbox daily send target with simple pacing.
  • ✅ Single-page dashboard: connected inboxes, today's send count, status badges.
  • ✅ AES-256-GCM token encryption. Refresh tokens never sit in the DB in plaintext.

Not in v0.1 (planned for v0.2 — see Roadmap below):

  • ❌ Reply-and-mark-as-important loop (receiver auto-replies and stars / archives).
  • ❌ DMARC pass-rate / reputation signals on the dashboard.
  • ❌ Per-pair scheduling (currently one send per cron tick).
  • ❌ Outlook / Microsoft 365.
  • ❌ AI-generated email bodies.

Quick start

Prerequisites

  • Node.js 20+
  • A Postgres 14+ instance (local Docker is fine)
  • Google Cloud project with the Gmail API enabled
  • 3–10 Google Workspace inboxes you own and can sign into

1. Clone + install

git clone git@github.com:pypesdev/inbox-warmer.git
cd inbox-warmer
pnpm install   # or npm install / yarn install

2. Postgres

docker run --name inbox-warmer-pg -d \
  -e POSTGRES_PASSWORD=warmer \
  -e POSTGRES_DB=inbox_warmer \
  -p 5432:5432 postgres:16

3. Google Cloud OAuth client

  1. Go to https://console.cloud.google.com → enable the Gmail API.
  2. OAuth consent screen → External, add yourself as a test user.
  3. CredentialsCreate credentialsOAuth client ID → Web application.
  4. Authorized redirect URI: http://localhost:3000/api/inboxes/oauth/callback
  5. Save the client ID and client secret.

4. Environment

Copy .env.example to .env and fill in:

cp .env.example .env
# Generate the encryption key:
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# Generate any random CRON_SECRET (openssl rand -hex 32 works).

5. Migrate + run

pnpm db:generate   # generates SQL migration in ./drizzle
pnpm db:migrate    # applies it to the local Postgres
pnpm dev           # http://localhost:3000

Click + connect Google inbox on the dashboard, authorize, and repeat for every inbox in your seed pool (minimum 2; recommended 3–10).

6. Schedule the worker tick

Locally, you can fire the tick manually to verify pairing works:

curl -X POST http://localhost:3000/api/cron/tick \
  -H "Authorization: Bearer $CRON_SECRET"

In production, point any scheduler at this endpoint every few minutes:

  • Vercel: add vercel.json with a cron entry on /api/cron/tick (recommended interval: every 5–15 minutes).
  • GitHub Actions: a cron schedule: workflow that curls the endpoint.
  • Anything else that can issue an authenticated HTTP request.

How it works

                ┌──────────────────────────────────────┐
                │         Your seed pool (DB)          │
                │  inbox A · inbox B · inbox C · …     │
                └──────────────────────────────────────┘
                                 │
                                 ▼
                ┌──────────────────────────────────────┐
   cron tick → │  pick eligible sender (under target)  │
                │  pick a different inbox as recipient │
                │  pick a short, conversational body   │
                │  send via Gmail API, log it          │
                └──────────────────────────────────────┘
                                 │
                                 ▼
                ┌──────────────────────────────────────┐
                │  send_log row → dashboard counters   │
                └──────────────────────────────────────┘

Per-inbox daily target defaults to 10 sends (DAILY_SENDS_PER_INBOX). Every cron tick performs one send. Run the cron every 5–15 minutes to spread sends across the day.

Security

  • Refresh tokens are encrypted with AES-256-GCM before they touch the database. Without GMAIL_ENCRYPTION_KEY they cannot be read, even with full DB access.
  • OAuth state is a random 16-byte value stored in a 10-minute, HttpOnly, SameSite=Lax cookie and verified on the callback to prevent CSRF.
  • Cron endpoint requires a Bearer token from CRON_SECRET.
  • The app never stores email bodies or the recipient address book — only the inbox metadata you connected and a log of which-pair-sent-which-subject-when (for pacing and the dashboard).

Roadmap

  • v0.2 — Reply loop (receiver auto-replies, marks important, archives) + per-pair scheduling.
  • v0.3 — DMARC / SPF / DKIM signal panel (consumes the dmarc-doctor library).
  • v0.4 — Outlook / Microsoft 365 support.
  • No timeline — Shared cross-user peer pool. We may never ship this; the abuse and legal model is hard, and BYO is the safer story.

Contributing

Bug reports and PRs are welcome — please open an issue first for anything beyond a small fix so we can align on scope.

License

MIT © Pypes LLC

About

Self-hosted inbox warm-up for cold-email senders. BYO seed pool — your domains exchange real-looking emails to build sender reputation before your first cold campaign.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors