Matthew Meszaros 1e37fb6aa3 feat: capture and score a signup's origin instead of discarding it (#234)
* feat: give an organization one fused abuse posture, because every existing control watches a single subject and an actor slightly wrong on several axes sits under all of them: organizations gains risk_state, risk_score, risk_reason and an append-only risk_signals evidence blob, modelled on the warmup participant health machine that already works rather than a second vocabulary for the same idea; restricted cuts per-mailbox cold volume to a quarter and forces the free warmup pool so a risky tenant cannot spend the paid pool's shared reputation, suspended stops sending at the send gate, and watch deliberately changes nothing a customer can feel so evidence accumulates before anything is taken away; an operator's suspension outranks the derived band so a detector clearing cannot release a workspace a human suspended, transitions ride the audit spine to every teammate's dashboard, a banner says which limit is active and why rather than letting volume drop silently, and the posture never travels in a workspace archive since it is one platform's verdict reached from evidence the destination never saw

* feat: make the suspension actually stop sending, and emit the audit transitions the PR claimed: emailsend.SendEmail is only the manual and API path, so campaign and warmup sends went nowhere near the gate and a suspended workspace kept sending on its schedule, while the restricted multiplier floored every mailbox at one a day which quietly turned suspension into a trickle rather than a stop; the campaign scheduler now defers the whole campaign with a reason and the warmup task skips as org-suspended, since warmup is outbound mail from the same domains; separately the band change emitted no audit entry at all despite the entity type and the frontend spine entry both existing, so no banner moved for a teammate and there was no trail of who was restricted when, and only a real transition is logged so a detector re-recording the same finding cannot fill the feed; one of my own live tests also asserted how far out a slot lands, which depends on the hour the suite runs, and now asserts the property it was about

* feat: capture and score a signup's origin instead of discarding it

* feat: document what a signup records, and prove the origin write is on the account path with a seam test rather than only testing the scorer

* chore: drop the em dashes and trim the comments the review flagged
2026-08-28 11:26:44 -07:00
2026-08-16 07:54:45 +02:00
feat: make self-hosted onboarding survivable by fixing invite_only, which could not onboard anyone (the accept route is JWT-only, so redeeming the invitation that would create your account required already having one, making the self-host default silently identical to fully closed), threading the invitation token through registration so an invited person lands in the inviting organization instead of a stray workspace, gating SSO just-in-time provisioning behind DISABLE_REGISTRATION (it bypassed the gate entirely, so an instance set to true was still open to anyone the IdP would assert) with SSO_AUTO_PROVISION as the opt-out, correcting the OIDC redirect URL that pointed at /api/v1 against a route at /v1 and 404'd every SSO login, scoping the first-launch exemption so it no longer overrides an explicit lockdown, preserving the remaining TTL when restoring a losing setup token so a public endpoint cannot hold the claim window open forever, replacing a generic 403 with typed registration_invite_only, registration_closed, invitation_invalid, setup_token_invalid and setup_already_complete codes that name the next step, logging why no claim link was issued on an already-claimed instance instead of staying silent, adding a warmblyctl operator CLI (status with health checks and a non-zero exit, reissuable setup-link, user create/list/reset-password/grant-admin/revoke-admin/disable-2fa, hash-password) so a locked-out operator no longer needs hand-written psql, adding read-only instance configuration over 104 environment variables with structural secret redaction and fingerprints, 35 health checks, a database-backed settings tier for the three keys no environment variable owns, hiding the signup form when the config already says invite_only rather than failing the whole form with a toast, and documenting first run, accounts and access, configuration, instance health and troubleshooting alongside the root .env.example the README told operators to write but never shipped (#114)
2026-08-16 05:58:11 +02:00
2026-01-17 09:19:43 +00:00

Warmbly

The open-source agentic cold email and warmup platform.

Discord Follow @WarmblyHQ on X Docs CI status Latest release License

Features · How it works · Quick start · Self-hosting · Docs · Community · Support

Help us reach more senders and grow the Warmbly community. Star this repo!

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

Campaigns Unified inbox

How it works

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.

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"]

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.

Quick start

You need Docker, Go 1.25, and pnpm.

git clone https://github.com/warmbly/warmbly && cd warmbly
make dev

Open http://localhost:5173 and log in with dev@warmbly.com / password123; the login code lands in Mailpit at http://localhost:18025. Every make target, the native services, and how seeding works are in the local development guide.

Warning

make dev and make up share one database, and seeded fixture accounts claim the instance. Planning to self-host from the same machine? Read first run first.

Self-hosting

Runs on Docker Compose

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:

git clone https://github.com/warmbly/warmbly && cd warmbly
make up

That is the whole install: make up waits for the backend and prints a one-time link that claims the instance and makes you its admin. You need Docker with Compose v2 and about 10 GB of free disk. If anything looks wrong, make doctor prints the instance state and every failing check.

From here the self-hosting guide covers the rest: your own secrets, production hardening, mail and single sign-on, HTTPS, connecting Gmail and Microsoft mailboxes, scaling workers, and backups. Account recovery and every operator command live in warmblyctl, the CLI baked into the backend image; it talks to the database directly, so it works when signing in does not.

Documentation

The full docs live at docs.warmbly.com.

Read this To learn
Self-hosting guide Step-by-step install, then production, backups, and scaling the worker fleet
First run Claiming the instance, reissuing the setup link, and what to do when accounts already exist
Accounts and access Registration modes, inviting people with or without a mail relay, SSO, and recovering access
warmblyctl The operator CLI: creating accounts, setting passwords, granting admin, and instance status
Configuration reference Every environment variable, its default, and whether changing it needs a restart
Instance health The checks the admin panel runs against your deployment, and make doctor
Troubleshooting The errors self-hosters actually hit, and the command that fixes each one
Local development Every make target, the native services, and how seeding works
Architecture How the control plane and workers split the job, plus the encryption model
API reference Endpoints, auth, permissions, and webhooks

Community

Have a question, found a bug, or want to shape where Warmbly goes next?

  • Discord - chat with the team and other senders
  • GitHub Issues - report bugs and request features
  • X / @WarmblyHQ - follow along for updates and releases
  • Email - reach us at team@warmbly.com

Support and enterprise

Note

Need a hand? We are happy to help. Ask in Discord, open a GitHub issue, or email team@warmbly.com, and someone on the team will get back to you.

Running Warmbly at scale, or would you rather we run it for you? We offer enterprise support and managed infrastructure: we can host and operate the whole platform for your organization, help you deploy and scale the worker fleet, tune deliverability, migrate your sending onto Warmbly, and stand behind it with a support agreement built around your team. Tell us what you need at team@warmbly.com or reach out on X.

Follow @WarmblyHQ on X Join the Discord Email the team

Star the repository

warmbly-star

Contributing

Pull requests are welcome. Keep each one to a single logical change, and open an issue first for larger design or product changes. Before you open a PR, run the checks for the tree you touched (make fmt and make lint for Go, pnpm typecheck and pnpm lint for the frontends). See CONTRIBUTING.md.

Security

Found a vulnerability? Email team@warmbly.com instead of opening a public issue. We prefer responsible disclosure and credit reporters in the release notes.

License

Apache License 2.0. Copyright 2026 Mindroot Ltd. See LICENSE.

Languages
Go 45.2%
TypeScript 35.5%
Astro 7.8%
Swift 7.6%
Shell 1.2%
Other 2.6%