warmbox/README.md

314 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Warmbox
Self-hosted email warmup and deliverability engine for custom domains. Uses SMTP to send realistic B2B conversations and IMAP to rescue messages from spam folders, flag them as important, and reply — improving sender reputation over time.
## Tech Stack
- **Runtime:** Node.js + TypeScript + Express
- **Database:** SQLite via Prisma ORM
- **Email:** nodemailer (SMTP), imapflow (IMAP)
- **AI:** OpenRouter (free models) for conversation generation
- **Scheduler:** node-cron
## Quick Start
### 1. Install dependencies
```bash
npm install
```
### 2. Configure environment
```bash
cp .env.example .env
```
Generate an encryption key:
```bash
openssl rand -hex 32
```
Set these in `.env`:
| Variable | Description |
| ---------------- | --------------------------------------------------------------------------- |
| `DATABASE_URL` | SQLite path, e.g. `file:./prisma/dev.db` (configured in `prisma.config.ts`) |
| `ENCRYPTION_KEY` | 64-char hex string (32 bytes) for AES-256-GCM password encryption |
| `AI_API_KEY` | API key from [OpenRouter](https://openrouter.ai/keys) (free tier works) |
| `AI_BASE_URL` | Default `https://openrouter.ai/api/v1` |
| `AI_MODEL` | Default `openrouter/free` (auto-picks a free model) |
| `API_KEY` | Optional API key for REST auth (`x-api-key` header) |
| `PORT` | HTTP port (default `3000`) |
### Get a free AI API key (OpenRouter)
Email generation only needs a small, fast language model — not GPT-4 class reasoning.
1. Sign up at [openrouter.ai](https://openrouter.ai/)
2. Go to [openrouter.ai/keys](https://openrouter.ai/keys) and create an API key
3. Paste it into `.env` as `AI_API_KEY`
**Recommended free models** (set `AI_MODEL` in `.env`):
| Model | Notes |
| --------------------------------------- | ---------------------------------------------- |
| `openrouter/free` | Auto-selects an available free model (default) |
| `google/gemma-2-9b-it:free` | Good quality, reliable JSON |
| `meta-llama/llama-3.2-3b-instruct:free` | Fast, lightweight |
You do **not** need an OpenAI account.
### 3. Run database migrations
```bash
npm run db:migrate
```
### 4. Start the server
```bash
npm run dev
```
The API and cron jobs start together. Default schedules:
- **Dispatcher:** every 15 minutes — sends warmup emails
- **Rescuer:** every 10 minutes — rescues spam, replies to inbox
- **Ramp:** midnight daily — increases `currentRamp` per inbox
### 5. Add mailboxes
You need **at least 2 active inboxes** for warmup to work. Warmbox randomly pairs senders and receivers from your pool.
#### SMTP/IMAP settings by provider
Every inbox needs **4 connection fields** plus credentials:
| Field | What it is |
| ----------------------- | ---------------------------------------------- |
| `smtpHost` / `smtpPort` | Where to **send** mail |
| `imapHost` / `imapPort` | Where to **read** mail (spam rescue + replies) |
| `username` | Usually the full email address |
| `password` | **App password** (not your login password) |
##### Gmail (including Google Workspace custom domains)
If `hello@fillcareapp.com` is hosted on **Google Workspace**, use Gmail servers:
| Field | Value |
| ---------- | ---------------- |
| `smtpHost` | `smtp.gmail.com` |
| `smtpPort` | `587` |
| `imapHost` | `imap.gmail.com` |
| `imapPort` | `993` |
**App password setup:**
1. Enable 2-Step Verification on the Google account
2. Go to [myaccount.google.com/apppasswords](https://myaccount.google.com/apppasswords)
3. Create an app password for "Mail" → copy the 16-character code
4. Use that code as `password` in Warmbox
##### Yahoo Mail
| Field | Value |
| ---------- | --------------------- |
| `smtpHost` | `smtp.mail.yahoo.com` |
| `smtpPort` | `587` |
| `imapHost` | `imap.mail.yahoo.com` |
| `imapPort` | `993` |
App password: [Yahoo Account Security](https://login.yahoo.com/account/security) → Generate app password.
##### Outlook / Hotmail / Live.com (@live.com, @outlook.com, @hotmail.com)
| Field | Value |
| ---------- | ----------------------- |
| `smtpHost` | `smtp-mail.outlook.com` |
| `smtpPort` | `587` |
| `imapHost` | `outlook.office365.com` |
| `imapPort` | `993` |
App password: [Microsoft Account Security](https://account.microsoft.com/security) → Advanced security → App passwords. IMAP must be enabled in Outlook settings.
##### Custom domain (cPanel / generic hosting)
If `hello@fillcareapp.com` is on cPanel or similar (not Google/Microsoft), check your host's email docs. Common pattern:
| Field | Value |
| ---------- | ------------------------------------------------ |
| `smtpHost` | `mail.fillcareapp.com` or `smtp.fillcareapp.com` |
| `smtpPort` | `587` (or `465` for SSL) |
| `imapHost` | `mail.fillcareapp.com` or `imap.fillcareapp.com` |
| `imapPort` | `993` |
Ask your DNS/hosting provider if unsure — look for "IMAP/SMTP settings" in cPanel → Email Accounts.
#### Example: FillCare + personal accounts
Add `hello@fillcareapp.com` as your primary warmup domain (industry: `Childcare`), then add 45 Gmail/Yahoo/Live accounts as the reply pool.
**1. Primary domain (FillCare)**
```bash
curl -X POST http://localhost:3000/api/inboxes \
-H "Content-Type: application/json" \
-d '{
"email": "hello@fillcareapp.com",
"smtpHost": "smtp.gmail.com",
"smtpPort": 587,
"imapHost": "imap.gmail.com",
"imapPort": 993,
"username": "hello@fillcareapp.com",
"password": "hkem mfmi bkmg bqyw",
"industry": "Childcare",
"dailyLimit": 40,
"currentRamp": 5
}'
```
> If FillCare email is **not** on Google Workspace, swap `smtpHost`/`imapHost` to your host's values (see table above).
**2. Gmail account**
```bash
curl -X POST http://localhost:3000/api/inboxes \
-H "Content-Type: application/json" \
-d '{
"email": "you@gmail.com",
"smtpHost": "smtp.gmail.com",
"smtpPort": 587,
"imapHost": "imap.gmail.com",
"imapPort": 993,
"username": "you@gmail.com",
"password": "your-gmail-app-password",
"industry": "SaaS"
}'
```
**3. Yahoo account**
```bash
curl -X POST http://localhost:3000/api/inboxes \
-H "Content-Type: application/json" \
-d '{
"email": "you@yahoo.com",
"smtpHost": "smtp.mail.yahoo.com",
"smtpPort": 587,
"imapHost": "imap.mail.yahoo.com",
"imapPort": 993,
"username": "you@yahoo.com",
"password": "your-yahoo-app-password",
"industry": "Marketing"
}'
```
**4. Live.com / Outlook account**
```bash
curl -X POST http://localhost:3000/api/inboxes \
-H "Content-Type: application/json" \
-d '{
"email": "you@live.com",
"smtpHost": "smtp-mail.outlook.com",
"smtpPort": 587,
"imapHost": "outlook.office365.com",
"imapPort": 993,
"username": "you@live.com",
"password": "your-microsoft-app-password",
"industry": "Finance"
}'
```
Repeat for each additional Gmail/Yahoo/Live account. Mixing providers is fine — Warmbox only needs them all in the same pool.
### 6. Test connections
After adding each inbox, verify SMTP + IMAP:
```bash
curl -X POST http://localhost:3000/api/inboxes/{id}/test
```
A successful response looks like:
```json
{
"ok": true,
"smtp": { "ok": true },
"imap": { "ok": true }
}
```
If either fails, double-check the app password and that IMAP is enabled on the account.
### 7. Monitor logs
```bash
curl http://localhost:3000/api/logs
```
Watch for status progression: `sent``rescued_from_spam``replied``complete`.
## API Reference
All endpoints under `/api` accept optional `x-api-key` header when `API_KEY` is set.
| Method | Path | Description |
| -------- | ----------------------- | --------------------------------------------------- |
| `POST` | `/api/inboxes` | Create inbox |
| `GET` | `/api/inboxes` | List inboxes |
| `GET` | `/api/inboxes/:id` | Get inbox |
| `PATCH` | `/api/inboxes/:id` | Update inbox |
| `DELETE` | `/api/inboxes/:id` | Delete inbox |
| `POST` | `/api/inboxes/:id/test` | Test SMTP + IMAP |
| `GET` | `/api/logs` | List warmup logs (`?status=&inboxId=&page=&limit=`) |
| `GET` | `/api/settings` | Get settings |
| `PATCH` | `/api/settings` | Update settings |
| `GET` | `/health` | Health check |
## Project Structure
```
src/
├── config.ts # Environment validation
├── index.ts # Express + scheduler bootstrap
├── jobs/
│ ├── dispatcher.job.ts # Sends warmup emails
│ ├── rescuer.job.ts # Spam rescue + replies
│ └── scheduler.ts # Cron wiring
├── lib/ # Prisma, logger, inbox guard
├── middleware/ # Auth, error handling
├── models/ # Enums, types
├── routes/ # REST endpoints
└── services/
├── ai.service.ts # OpenRouter conversation generator
├── crypto.service.ts # AES-256-GCM encryption
├── email.service.ts # SMTP via nodemailer
├── imap.service.ts # IMAP via imapflow
└── settings.service.ts
prisma/
└── schema.prisma # Database schema
```
## How It Works
1. **Dispatcher** picks random sender/receiver pairs from active inboxes, generates a B2B email via AI, and sends via SMTP.
2. **Rescuer** scans spam folders (`[Gmail]/Spam`, `Junk`, `Spam`) for warmup emails, moves them to INBOX, flags them as read/starred/important.
3. **Rescuer** also processes unread warmup emails already in INBOX, generates contextual AI replies, and sends them back.
4. Failed IMAP/SMTP connections mark the inbox as `error` and skip it until credentials are fixed.
## Production
```bash
npm run build
npm start
```
Use a process manager (systemd, PM2) and back up the SQLite database file regularly.
## License
MIT