Changelog Everything we shipped, dated and tagged

The actual history
of what we ship.

New features, behavioural changes, and fixes, in the order they reached production. No marketing language, no rewrites of older entries, no quiet deletions.

Latest releases

The latest production work.

The 3 most recent merged pull requests. Each entry links straight to the PR it shipped in.

3 / 24 total
2026-08-25
fixed

Release notes render as one crammed paragraph with a duplicate What's Changed section

Organization data export and import for moving a workspace between instances (#132). Seal Gmail and Outlook OAuth access and refresh tokens at rest in emailaccountsoauth… (#115). Resolve campaign senders by organization, not by the campaign owner (#167) (#177). A campaign email can be sent twice when the progress…

#183
2026-08-25
shipped

Stop the IMAP live pass once a lane is denied, so unfreezing a mailbox cannot deactivate it

ImapConn (imapconn.go) — the methods the worker drives on one IMAP connection. No call site changed; only the field type.. SyncBudget (governor.go) — Policy / SetPolicy / Admit / ObserveLive / RecordThrottledDay.. TestImapSyncStopsFetchingOnceTheLiveLaneIsDenied — 600 changed UIDs (3 batches), budget 0. Asserts…

#182
2026-08-25
fixed

Release the selected IMAP mailbox before the LIST-STATUS poll so live sync keeps detecting new mail on Dovecot

Fixes #165.

#180
All releases

Every entry, in order.

New features, behavioural changes, and fixes, in the order they reached production. No marketing language, no quiet deletions.

Shipped 11 Changed 0 Fixed 13
2026-08-24
fixed

Resolve campaign senders by organization, not by the campaign owner (#167)

#177

Repository.AccountScope is the tenant key: ea.organizationid = $1. Nil is not a wildcard, it resolves to no mailboxes rather than widening to the owner, matching how the campaign task halts an orgless campaign instead of sending it unchecked. GetByTags, GetAllActiveByUser (renamed GetAllActiveInScope) and…

2026-08-24
fixed

One waiting lead no longer parks the whole campaign (#171)

#174

FindNextRoutedPair loads waitafter/kind/action per step, computes each candidate's due time, returns the first due contact in list order, and when nothing is due returns the soonest due moment (merged with condition-window rechecks) so the scheduler defers exactly until then.. Scheduler: new-lead-cap deferral is…

2026-08-22
shipped

Enforce the SPF/DKIM/DMARC gate for cold send and warmup pool entry

#160

Cold send gates in the campaign scheduler, before the daily-count query. An all-gated pool returns ErrDomainAuthFailing rather than the existing message about sending windows and daily caps, which would have sent people to check timezones for a DNS problem.. Warmup gates in the task and demotes the mailbox to…

2026-08-21
shipped

Fix truncated, unformatted and mis-encoded email content in the unibox

#137

Thread reader loads each expanded message's real body and renders it in a sandboxed iframe. Newest message and anything unread open by default, the rest collapse to their preview.. API sanitizes bodyhtml before returning it, keeps table and inline-style layout, drops scripts and style content. A missing body blob…

2026-08-20
shipped

Give warmblyctl an API-key half so agents and scripts can operate any Warmbly instance, ship in-repo agent skills that teach it, and cut the README quick start and self-hosting sections down to commands plus docs links

#135

Raw passthrough: warmblyctl api get|post|patch|put|delete <path> with --data taking a literal, - or @file, and --idempotency-key. Nothing the API can do is out of the CLI's reach.. Typed families: me, campaign, contact, mailbox, inbox, analytics, settings, webhook, apikey, template, crm. One spec table drives…

2026-08-18
shipped

Organization data export and import for moving a workspace between instances

#132

Export walks every org-owned relation into a zip of newline-delimited JSON, one file per table, plus attachment bytes.. Import reads it back into a destination workspace, remapping people and clearing the fields that only meant something on the instance the archive came from.. Surfaces: Settings → Data in the…

2026-08-18
shipped

Rebuild the new-campaign wizard, fix dropdown click-away inside dialogs, add a From contacts leads picker, and stop self-hosted deployments presenting as free-trial or plan-metered

#131

Rebuilt the new-campaign wizard: directional step transitions, numbered stepper with filling connectors, the shared sky Toggle instead of a hand-rolled switch whose knob translated out of its own track, shared WeekdayBitmask, per-step validation that explains itself instead of a silently disabled button, no skipping…

2026-08-16
fixed

Re-place mailboxes stranded on a worker that no longer exists

#127

WorkerRepository.IsWorkerLive uses the same predicate as selection: active = true AND lastseenat > now() - WorkerLivenessWindow.. ReleaseDeadWorker in the loader releases a mailbox held by a dead worker through the existing UnassignWorkerFromEmail, which also corrects that worker's accountcount and load score, then…

Want the full detail? Merged pull requests on GitHub Each entry links to the pull request that shipped it.

Ship faster. Tell the world.

Connect a mailbox, warm it up, and put your first campaign in the next changelog entry.