Merge pull request #80 from warmbly/docs/update-readme

docs: note automations AI steps in readme feature list
This commit is contained in:
Matthew Meszaros
2026-07-22 09:05:19 +02:00
committed by GitHub
5 changed files with 119 additions and 225 deletions
+98 -221
View File
@@ -1,122 +1,85 @@
<p align="center">
<img src="docs/assets/banner.jpg" alt="Warmbly" width="100%" />
</p>
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/logo-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="docs/assets/logo-light.svg">
<img src="docs/assets/logo-dark.svg" alt="Warmbly" width="540">
</picture>
<p>The open-source agentic cold email and warmup platform.</p>
<p>
<a href="https://dc.warmbly.com"><img src="https://img.shields.io/badge/Discord-5865F2?logo=discord&logoColor=white&style=flat-square" alt="Discord" /></a>
<a href="https://docs.warmbly.com"><img src="https://img.shields.io/badge/Docs-1f6feb?style=flat-square" alt="Docs" /></a>
<a href="https://github.com/warmbly/warmbly/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/warmbly/warmbly/ci.yml?branch=main&style=flat-square&label=CI" alt="CI status" /></a>
<a href="https://github.com/warmbly/warmbly/releases"><img src="https://img.shields.io/github/v/release/warmbly/warmbly?style=flat-square" alt="Latest release" /></a>
<a href="./LICENSE"><img src="https://img.shields.io/github/license/warmbly/warmbly?style=flat-square" alt="License" /></a>
</p>
<p>
<a href="#features">Features</a> ·
<a href="#how-it-works">How it works</a> ·
<a href="#quick-start">Quick start</a> ·
<a href="#self-hosting">Self-hosting</a> ·
<a href="#documentation">Docs</a> ·
<a href="#community">Community</a>
</p>
<p><i>⭐ Help us reach more senders and grow the Warmbly community. Star this repo!</i></p>
</div>
## Warmbly
Warmbly runs cold email campaigns from the mailboxes you already own and warms
them so they keep landing in the inbox. Opens, clicks, and replies land in a
shared dashboard the moment they happen, and it's AI-native, so your team and its
agents work in it together, live.
https://github.com/user-attachments/assets/378a510a-bb99-425f-925e-04300184938b
## Features
- **Campaigns** - multi-step sequences with per-mailbox caps and spacing
- **Unified inbox** - every mailbox and reply in one place
- **CRM** - contacts, pipelines, deals, tasks, meetings
- **Warmup** - a pool of monitored mailboxes, not throwaway accounts
- **Deliverability** - bounces, complaints, suppression, inbox placement
- **Automations** - visual reply playbooks with AI steps
- **Integrations** - HubSpot, Slack, Zapier, REST API, webhooks
- **Realtime** - live presence and edits across your team
<p align="center">
Open-source cold email and mailbox warmup you can self-host.<br />
Your sending IPs, your database, your servers.
<img src="docs/assets/dashboard-campaigns.png" alt="Campaigns" width="49%" />
<img src="docs/assets/dashboard-inbox.png" alt="Unified inbox" width="49%" />
</p>
<p align="center">
<a href="https://github.com/warmbly/warmbly/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/warmbly/warmbly/ci.yml?branch=main&style=flat-square&label=CI" alt="CI status" /></a>
<a href="https://github.com/warmbly/warmbly/releases"><img src="https://img.shields.io/github/v/release/warmbly/warmbly?style=flat-square" alt="Latest release" /></a>
<img src="https://img.shields.io/github/go-mod/go-version/warmbly/warmbly?style=flat-square&label=go" alt="Go version" />
<a href="./LICENSE"><img src="https://img.shields.io/github/license/warmbly/warmbly?style=flat-square" alt="License" /></a>
<a href="https://docs.warmbly.com"><img src="https://img.shields.io/badge/docs-docs.warmbly.com-1f6feb?style=flat-square" alt="Documentation" /></a>
</p>
## How it works
<p align="center">
<a href="#connect-your-mailboxes">Mailboxes</a> ·
<a href="#integrations">Integrations</a> ·
<a href="#quick-start">Quick start</a> ·
<a href="#warmup">Warmup</a> ·
<a href="#how-it-works">How it works</a> ·
<a href="#self-hosting">Self-hosting</a> ·
<a href="#documentation">Docs</a> ·
<a href="./CONTRIBUTING.md">Contributing</a>
</p>
Warmbly splits into a **control plane** (backend API, consumer, Postgres, Redis,
and the event bus) that owns all state, and an **execution plane** of
interchangeable Go workers that send and sync mail. Workers never touch Postgres,
and outbound mail leaves through each mailbox's own provider, not the worker's IP,
so you add throughput by running more workers.
<p align="center">
<img src="docs/assets/dashboard-campaigns.png" alt="Campaigns" width="100%" /><br />
<sub><b>Campaigns</b> · multi-step sequences with per-mailbox daily caps and spacing</sub>
</p>
```mermaid
flowchart LR
MB["Your mailboxes"] --> API
subgraph CP["Control plane"]
direction TB
API["Backend API"] --> DB[("Postgres")]
API --> BUS{{"Event bus"}}
end
BUS --> W1["Worker"]
BUS --> W2["Worker"]
BUS --> W3["Worker"]
W1 --> P["Gmail · Microsoft · SMTP"]
W2 --> P
W3 --> P
P --> R["Recipients"]
```
<p align="center">
<img src="docs/assets/dashboard-inbox.png" alt="Unified inbox" width="100%" /><br />
<sub><b>Unified inbox</b> · every connected mailbox and reply in one place</sub>
</p>
<p align="center">
<img src="docs/assets/dashboard-mailboxes.png" alt="Mailboxes" width="100%" /><br />
<sub><b>Mailboxes</b> · warmup state and health for every account</sub>
</p>
## What is Warmbly
Warmbly is a cold outreach platform. You connect your mailboxes, write sequenced
campaigns, and it sends the mail, tracks the replies, and keeps your sender
reputation healthy. The difference from hosted tools is where it runs: your
sending IPs, your Postgres, your servers. Nothing is tied to a vendor's database.
Everything a sending team needs sits in one dashboard:
- **Campaigns** send multi-step sequences with per-mailbox daily caps and spacing.
- **The unified inbox** pulls every connected mailbox and its replies into one view.
- **A built-in CRM** tracks contacts, pipelines, deals, tasks, and meetings.
- **Deliverability** surfaces bounces, complaints, suppression, and inbox placement.
- **Automations** run branching reply playbooks on a visual canvas.
- **Integrations** sync the CRM and automations out to HubSpot, Slack, and more.
- **Warmup** builds real sender reputation through our pool, covered next.
The dashboard is collaborative in real time: teammates see each other's live
cursors, presence, and edits across campaigns, the CRM, and the automation
canvas, with no refresh.
The same code runs on a single VPS or across a fleet of cheap servers with many
IPs per box, so you add capacity by adding machines.
## Connect your mailboxes
Warmbly sends and receives through the mailboxes you already own. There are three
ways to connect one, and you can mix them freely across a workspace:
- **Google / Gmail and Google Workspace.** Connect with one-click OAuth, no app
password to store or rotate. Sending goes through the Gmail API.
- **Microsoft 365 / Outlook.** Connect with one-click OAuth over authenticated
SMTP and IMAP.
- **Any other provider over SMTP + IMAP.** Zoho, Fastmail, a self-hosted mail
server, anything that speaks SMTP and IMAP. Add the host, port, and an app
password.
Each mailbox warms, sends, and syncs on its own, with its own daily cap, minimum
spacing between sends, and reputation tracked per IP. Replies stream into the
unified inbox in near real time. Credentials and OAuth tokens are sealed with
per-organization envelope encryption and are only decrypted on the worker that
owns the mailbox, never stored in plaintext.
## Integrations
Automations and the built-in CRM connect out to the tools you already run: ping
Slack on a positive reply, push a won deal to your CRM, book meetings straight
from replies, or fan events out to your own stack.
| Category | Providers |
|---------------|----------------------------------------|
| CRM | HubSpot, Salesforce, Pipedrive, Close |
| Automation | Zapier, Make, n8n |
| Notifications | Slack, Discord |
| Meetings | Calendly, Cal.com |
| Data | Google Sheets |
Everything is also reachable through a scoped REST API, HMAC-signed webhooks, and
a realtime WebSocket, so you can wire Warmbly into anything that is not on the
list. Open tracking, click tracking, and reply detection feed the same event
stream. See the [API reference](https://docs.warmbly.com/api/).
## Warmup
Warmup only produces meaningful results with a pool of real mailboxes warming
against each other. Warmbly maintains that pool, so the practical path to real
reputation is to run warmup through Warmbly: your mailboxes hold genuine
conversations with monitored inboxes instead of throwaway accounts, even if you
only have a few. If you operate enough mailboxes of your own to sustain a healthy
pool, you can host warmup yourself instead.
Either way the safeguards are the same. Volume starts low and ramps gradually per
mailbox, replies happen at a natural rate, and every warmup message carries a
verification token. Mailboxes that show spam patterns or forged tokens are scored
and auto-blocked from the pool, so it stays clean for everyone in it. Free and
premium pools are kept separate.
Secrets use envelope encryption, with a local AES master key by default or AWS KMS
if you prefer. Full write-up in the
[architecture docs](https://docs.warmbly.com/development/architecture/).
## Quick start
@@ -127,79 +90,22 @@ git clone https://github.com/warmbly/warmbly && cd warmbly
make dev
```
That one command brings up the backing services in Docker (Postgres, Redis,
NATS), waits for them, applies migrations, seeds demo data, and starts the
backend, consumer, worker, dashboard, and admin natively, with realtime and
tracking as containers (so you need no Elixir or Rust toolchain). Open
`http://localhost:5173` and log in with `dev@warmbly.com` / `password123`.
Ctrl-C stops the app; the Docker infra stays up so the next `make dev` is fast.
The Go services run natively (recompiling in a second or two on save), so the
same command is also the day-to-day loop. If you prefer separate terminals, the
stack splits into `make infra` + `make run` + `make web`. To run the whole
no-cloud stack in Docker instead, use `make up` (see [Self-hosting](#self-hosting)).
The first admin account cannot be created from the UI. Sign up through the
dashboard, then promote yourself from the host with
`make grant-admin EMAIL=you@example.com` and open the admin app with `make admin`.
Full local setup, seeding, and troubleshooting live in the
One command brings up the backing services in Docker, applies migrations, seeds
demo data, and starts the backend, worker, and dashboard natively. Open
`http://localhost:5173` and log in with `dev@warmbly.com` / `password123`. Full
setup lives in the
[local development guide](https://docs.warmbly.com/development/local-development/).
## How it works
Warmbly is split into a control plane and an execution plane.
The control plane is the backend API, the event consumer, Postgres, Redis, and
the event bus. It owns every piece of stateful data and decides what gets sent
and from where.
The execution plane is the worker fleet: one Go binary per machine. Workers take
commands off the event bus, fetch their encryption keys over HTTPS, send and sync
mail, and report telemetry back. **Workers never connect to Postgres.** They are
interchangeable executors, so you add throughput by running more of them; outbound
mail leaves through each mailbox's own provider (Gmail API, Graph, or SMTP relay),
not the worker's IP.
Secrets use envelope encryption: a per-organization data key, wrapped by a root
key, seals mailbox credentials and message content. The root key is a local AES
master key by default (no cloud), or AWS KMS if you prefer. The full write-up is
in the [architecture docs](https://docs.warmbly.com/development/architecture/).
## Self-hosting
Warmbly runs with **no cloud account of any kind**: no AWS, no GCP, no Stripe,
no Kafka. One command brings up the whole platform on local, open-source pieces:
Warmbly runs with **no cloud account of any kind**: no AWS, no GCP, no Stripe, no
Kafka. One command brings up the whole platform on local, open-source pieces:
```bash
git clone https://github.com/warmbly/warmbly && cd warmbly
make up # or: docker compose up --build
```
Dashboard on `:5173`, admin on `:5174`, API on `:8080`. The first build compiles
the images once (a couple of minutes; they are CGO-free), then it is up. Load
optional demo data with `make up` running via
`docker compose --profile seed run --rm seed`.
Before exposing it, set your own secrets in a `.env` next to `docker-compose.yml`.
At minimum: `AUTH_SECRET`, `CREDENTIALS_ENCRYPTION_KEY`, `INTERNAL_API_TOKEN`,
and `KMS_LOCAL_MASTER_KEY` (run `make gen-key`). The full list is in
[`deploy/config/env.example`](deploy/config/env.example).
**Reaching it from another machine.** Every service already binds to `0.0.0.0`
(the Docker port mappings), so it listens on all interfaces. To make the app
usable from a LAN IP or a domain instead of `localhost`, set one variable in
`.env`, and everything (API URL, CORS, websocket, tracking, blob URLs) derives
from it:
```bash
PUBLIC_HOST=192.168.1.50 # your machine's LAN IP, or your domain
```
Then open `http://192.168.1.50:5173`. For a public domain over HTTPS, put a
reverse proxy (Caddy or nginx) in front terminating TLS, set `PUBLIC_HOST` to the
domain, and build the frontends as static bundles rather than serving the Vite
dev server.
Every external dependency is picked by an environment variable, so you swap in a
cloud service only if you want one:
@@ -207,67 +113,38 @@ cloud service only if you want one:
|----------------|----------------------------|------------------------------|
| Database | PostgreSQL 16 | RDS / Cloud SQL, any Postgres |
| Cache | Redis (or Valkey) | ElastiCache |
| Event bus | **NATS JetStream** (~15 MB, one binary) | Kafka (`-tags kafka`) |
| Event bus | **NATS JetStream** | Kafka (`-tags kafka`) |
| Blob storage | **Filesystem** | S3, MinIO, R2, B2 |
| KMS / root key | **Local AES master key** | AWS KMS |
| Task scheduler | **In-process Postgres poller** | GCP Cloud Tasks |
| Codec | JSON | Avro + Schema Registry |
| Captcha | Off | Cloudflare Turnstile |
| Payments | **Off (everything unlocked)** | Stripe |
NATS is the default because it is one small binary versus Kafka's
JVM + Zookeeper + Schema Registry, and it keeps the image CGO-free so builds are
fast. Kafka is fully supported: build the images with `--build-arg GO_TAGS=kafka`
(and the tracking image with `CARGO_FEATURES=kafka`), set `EVENTBUS_PROVIDER=kafka`,
and point `KAFKA_BOOTSTRAP_SERVERS` at your cluster.
**Scaling is by mailboxes and workers, not IPs.** Outbound mail goes through each
mailbox's own provider (Gmail API, Microsoft Graph, or the mailbox's SMTP relay),
so the source IP is the provider's, never the worker's. Add throughput by
connecting more mailboxes and running more workers: `docker compose up --scale
worker=3`, or attach a machine you already own through the admin panel's SSH
enrollment. Workers are interchangeable executors.
**Connecting Gmail mailboxes** needs your own Google Cloud OAuth client: set
`BOX_GOOGLE_CLIENT_ID` / `BOX_GOOGLE_CLIENT_SECRET` (a Web application client with
the authorized redirect URI `<your-api-host>/addresses/google/callback`) on the
backend and every worker. Without it you can still connect any mailbox over
SMTP/IMAP with an app password, and Microsoft 365 over its own OAuth client.
Keep two secrets safe: `KMS_LOCAL_MASTER_KEY` (`make gen-key`) and
`CREDENTIALS_ENCRYPTION_KEY` seal every stored mailbox credential, and losing them
is unrecoverable. Full env reference and day-2 operations are in the
Scaling is by mailboxes and workers, not IPs. Reaching it from another machine,
connecting Gmail, and day-2 operations are all in the
[deployment guide](https://docs.warmbly.com/development/deployment-guide/).
## Tech stack
| Component | Tech |
|-------------|-----------------------------------|
| Backend API | Go 1.25 + Gin |
| Consumer | Go (event-bus driven) |
| Worker | Go (Kafka / NATS subscriber) |
| Tracking | Rust + Axum |
| Realtime | Elixir + Phoenix Channels |
| Dashboard | React 19 + Vite + Tailwind v4 |
| Admin UI | React 19 + Vite + Tailwind v4 |
| Database | PostgreSQL 16 |
| Cache | Redis 7 (or Valkey / KeyDB) |
| Event bus | NATS JetStream (default) or Kafka |
## Documentation
The full docs live at **[docs.warmbly.com](https://docs.warmbly.com)**: product
guides, the API reference, and the engineering docs. Start here:
The full docs live at **[docs.warmbly.com](https://docs.warmbly.com)**.
| Read this | To learn |
|-----------|----------|
| [Local development](https://docs.warmbly.com/development/local-development/) | Every make target, the native services, and how seeding works |
| [Sandbox](https://docs.warmbly.com/development/sandbox/) | One command spins up a full demo org that sends, replies, opens, clicks, and warms itself |
| [Architecture](https://docs.warmbly.com/development/architecture/) | How the control plane and the workers split the job, plus the encryption model |
| [Architecture](https://docs.warmbly.com/development/architecture/) | How the control plane and workers split the job, plus the encryption model |
| [Deployment guide](https://docs.warmbly.com/development/deployment-guide/) | Taking it to production and scaling the worker fleet |
| [Event system](https://docs.warmbly.com/development/events/) | The event bus and every topic that flows across it |
| [API reference](https://docs.warmbly.com/api/) | Endpoints, auth, permissions, and webhooks |
## Community
Have a question, found a bug, or want to shape where Warmbly goes next?
- **[Discord](https://dc.warmbly.com)** - chat with the team and other senders
- **[GitHub Issues](https://github.com/warmbly/warmbly/issues)** - report bugs and request features
- **Email** - reach us at `team@warmbly.com`
## Star the repository ⭐
<img width="1280" height="720" alt="warmbly-star" src="https://github.com/user-attachments/assets/c9bd34f7-c384-4f10-91e4-215fcea09986" />
## Contributing
Pull requests are welcome. Keep each one to a single logical change, and open an
+5 -4
View File
@@ -5,10 +5,11 @@ loads quickly on GitHub.
| File | Where it shows up |
|-----------------------------|--------------------------------------|
| `banner.jpg` | Hero banner at the top of the README |
| `dashboard-campaigns.png` | Gallery: campaigns list |
| `dashboard-inbox.png` | Gallery: unified inbox |
| `dashboard-mailboxes.png` | Gallery: mailboxes and warmup state |
| `logo-dark.svg` | Logo + wordmark, white, for dark GitHub theme |
| `logo-light.svg` | Logo + wordmark, dark ink, for light GitHub theme |
| `dashboard-campaigns.png` | Features: campaigns list |
| `dashboard-inbox.png` | Features: unified inbox |
| `dashboard-mailboxes.png` | Spare product screenshot (mailboxes) |
The dashboard images are exports of the product design. When real, anonymized
screenshots of the running app are available, swap them in at the same paths and
Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB