a09ba27b0c
feat: confirm a missing SPF or DMARC record with the sending domain's own authoritative nameservers before reporting it, look names up fully qualified so a resolver failure is never retried under the host's search domains and read as not found, look up internationalized domains in ASCII, record the verdict when a mailbox manager presses Check in the drawer, and show an unanswered lookup as unverified rather than missing
Matthew Meszaros2026-10-02 06:13:37 -07:00
0c60be4d88
Merge pull request #782 from warmbly/fix/deploy-railway-single-deployment
Matthew Meszaros2026-10-02 06:21:55 +00:00
39285173f1
feat: never move the follow-up changed-thread watermark past a page it failed to read, step past a failing page, thread or unreadable mailbox only after three failures spanning at least an hour, fence sweep state saves on the lease owner alone and log a takeover, clear a stale failure count once the walk moves on, and note that imported unibox rows keep their source ingested_at
Matthew Meszaros2026-10-01 23:20:45 -07:00
0bcbab91ac
Merge remote-tracking branch 'origin/main' into fix/inbox-follow-up-sweep-paging
Matthew Meszaros2026-10-01 23:20:32 -07:00
b2310f5d4b
feat: renumber the inbox follow-up sweep migrations from 000243-000247 to 000245-000249 so they follow 000243_campaign_task_subject and 000244_unibox_rail_layout on main instead of colliding with them
Matthew Meszaros2026-10-02 08:15:42 +02:00
a869099fc8
feat: track the one new deployment a Railway roll starts by id in scripts/deploy-railway.sh, recording existing deployment ids before connecting the image so a rollback never mistakes an older deployment of the same image for the new one, checking once more at the 30-second deadline, and stopping the roll when a deployment list query fails instead of reading it as no deployment and redeploying
Matthew Meszaros2026-10-02 08:09:56 +02:00
39f780122e
Merge pull request #794 from warmbly/feat/unibox-rail-layout-per-member
Matthew Meszaros2026-10-02 06:04:59 +00:00
e79551867f
feat: have a worker learn from its own dials when its network blocks outbound 465, dial 587 at once there, tell a mailbox whose server only takes 465 that the block is on the sending side instead of blaming its server, report the block on every heartbeat as the node's last error, rename the admin Workers filter to Has node error, and document the outbound ports a worker needs
Matthew Meszaros2026-10-02 08:02:36 +02:00
244b2e6613
feat: renumber the unibox rail layout migration to 000244 after main took 000243
Matthew Meszaros2026-10-01 22:59:25 -07:00
b8a8ec4743
Merge remote-tracking branch 'origin/main' into feat/unibox-rail-layout-per-member
Matthew Meszaros2026-10-01 22:58:31 -07:00
1aeb45773b
feat: check threads changed since each workspace's last follow-up pass by when the message was stored (new unibox_emails.ingested_at) or its verdict written, behind a persisted watermark, give each workspace's sweep a single leased walker whose saves are conditional on the lease, stop the cursor at the last thread whose label was written and step past a page or thread after three consecutive failures, keep the cycle running when the changed-thread check fails, and accept warmblyctl inbox-tag follow-ups --limit as a deprecated no-op
Matthew Meszaros2026-10-01 22:52:43 -07:00
945fadb260
Merge pull request #788 from warmbly/fix/ab-variant-thread-subject
Matthew Meszaros2026-10-02 05:46:33 +00:00
d12b8090c8
Merge origin/main into fix/ab-variant-thread-subject
Matthew Meszaros2026-10-01 22:41:11 -07:00
bce968646f
feat: thread campaign follow-ups on the A/B arm each contact was actually sent by recording every send's rendered subject on campaign_tasks.subject (migration 000243) and reusing it verbatim in ThreadParentForLead, and list the opening step's variant subjects in the follow-up composer
Matthew Meszaros2026-10-01 22:41:11 -07:00
8f89c36756
feat: refresh the open conversation for inbox events that name only a message id, give unibox refresh keys added just before a max-wait flush a trailing flush, cancel a shared unibox overview computation once its last caller leaves and bound it and GET /unibox/overview at 30s, include scheduled sends in the coalesced inbox refresh, and word the slow pgxpool acquire log as acquire time rather than saturation
Matthew Meszaros2026-10-01 22:41:00 -07:00
596c395cd0
Merge pull request #792 from warmbly/fix/menus-close-on-email-body-tap
Matthew Meszaros2026-10-02 05:37:50 +00:00
478d3ecc7b
Merge remote-tracking branch 'origin/main' into fix/unibox-refresh-load
Matthew Meszaros2026-10-01 22:37:48 -07:00
7707f6fb02
Merge pull request #789 from warmbly/fix/unibox-unread-latest-received
Matthew Meszaros2026-10-02 05:37:48 +00:00
54a05027cc
feat: save the unibox scope rail's favorites, row and section order and hidden rows to the member's account per workspace through a unibox_rail view with a validated layout on /me/views, synced from the dashboard store so every device shows the same rail while folds and widths stay per browser
Matthew Meszaros2026-10-01 22:37:23 -07:00
4183929b29
feat: note in AGENTS.md that useClickOutside also closes on a tap landing in a same-origin iframe
Matthew Meszaros2026-10-01 22:32:51 -07:00
b2eba2b566
Merge pull request #786 from warmbly/fix/jobrun-persisted-schedule
Matthew Meszaros2026-10-02 05:32:37 +00:00
6758bc8035
feat: page the hourly inbox follow-up sweep through each mailbox newest first in bounded keyset pages that resolve thread state only for the threads on the page, resume each workspace's cycle from a cursor persisted in inbox_follow_up_sweeps under a per-pass time budget, check recently active threads first every pass, and add the unibox_emails (email_id, internal_date, id) index the walk reads
Matthew Meszaros2026-10-01 22:29:41 -07:00
e137530895
feat: run the jobrun scheduler tests on the testing/synctest fake clock and cover a claim that errors with or without its write landing, so each slot still runs exactly once
Matthew Meszaros2026-10-01 22:29:39 -07:00
f01016c64f
feat: close every dashboard dropdown on a tap inside a same-origin iframe such as the unibox email body by listening on the frame's own document in useClickOutside, re-attaching when the frame reloads, since a tap on a phone never moves focus into the frame
Matthew Meszaros2026-10-01 22:27:45 -07:00
dc2cffd786
feat: coalesce and dedupe unibox realtime refreshes in useRealtimeEvents, forward TanStack Query abort signals through every unibox client and the shared Request helper with cancellations kept out of error handling, share one organization-scoped unibox overview computation per second with in-flight dedup and write-time invalidation, bound interactive unibox reads at 30s including pool wait, and log slow pgxpool connection acquisitions
Matthew Meszaros2026-10-01 22:25:53 -07:00
839235069e
feat: add a Cancel selection button next to the All box in the unibox list header so Select mode can be left on a phone without ticking a row or switching folders
Matthew Meszaros2026-10-01 22:25:06 -07:00
72b332b944
Merge pull request #787 from warmbly/fix/unibox-mark-unread-sticks
Matthew Meszaros2026-10-02 05:23:09 +00:00
a84b3bbbf3
feat: mark only a conversation's newest received message unread on Mark as unread, never a sent or draft copy, from the reader, the row menu, the selection bar, PATCH /unibox/seen and the mark_thread_seen AI tool, with the guide and API docs updated
Matthew Meszaros2026-10-01 22:22:56 -07:00
7841e34119
feat: keep a unibox conversation unread after Mark as unread by skipping the reader's auto-read once the store has moved off its thread, and close the reader when the selection bar marks the open conversation unread
Matthew Meszaros2026-10-01 22:16:59 -07:00
7c8ed01775
feat: resume every scheduled job from its stored next_run_at after a restart instead of starting a fresh interval, run a job that came due while the process was down right after its phase offset, and claim each slot with a compare-and-swap on next_run_at so a job hosted by several processes runs once per slot
Matthew Meszaros2026-10-01 22:16:16 -07:00
b488d57534
feat: roll each Railway service with exactly one deployment in scripts/deploy-railway.sh by waiting for the deployment that connecting the image starts, redeploying only when none appears within 30 seconds, and waiting on an already-starting deployment of the target image instead of starting another, so a second deployment can no longer replace a booting backend mid-migration
Matthew Meszaros2026-10-01 19:55:56 +02:00
8faefb88be
feat: leave Escape to a confirm or modal opened above an open dropdown in useClickOutside, drop ImageMenu's duplicate Escape guard, and restore the useDismissAdvisorFinding and useDismissMailboxImport mutation names the hook rename caught
Matthew Meszaros2026-10-01 10:14:55 -07:00
76f43b9796
feat: close every dashboard dropdown through one useClickOutside(open, onClose, refs) hook that the shared PopoverMenu, the old useClickOutside callers and the hand-rolled pickers now all use, so a press outside (including inside a floating dialog card or an email iframe) closes it, Escape closes only the innermost one and returns focus to its trigger, and opening one closes the others
Matthew Meszaros2026-10-01 08:38:57 -07:00
e920b61371
feat: clear a reported warmup send failure only on a confirmed delivery, word the not-loaded send failure as a possible cause, leave placement seeds out of the adopted-mailbox warmup repair, and describe send_failure as a failure reason in the API schema
Matthew Meszaros2026-10-01 03:20:41 -07:00
a844c506a0
feat: make Warmbly Cloud warmup start and explain itself for linked mailboxes: apply the instance's warmup settings, start warmup on adopted mailboxes, read the warmup day mask Monday-first, report the last refused warmup send and the partner cap to the instance and dashboard, hand changed SMTP credentials to the cloud, refuse cleartext mailboxes at enrollment, and show cloud warmup with the warming animation and a clear Cloud marker
Matthew Meszaros2026-10-01 03:01:36 -07:00
e20efd2544
feat: let a portaled popover inside the unibox composers close itself on Escape instead of the composer closing around it
Matthew Meszaros2026-09-30 21:17:28 -07:00
2a78dc1a25
Merge remote-tracking branch 'origin/main' into fix/unibox-template-html-body
Matthew Meszaros2026-09-30 21:15:35 -07:00
cfdc0c3d01
feat: keep the signature editor's own plain-text rendering, reuse the campaign HTML-to-text helper in the composers, leave a synced text part to the server, cap HTML bodies in bytes, refuse a send whose HTML was emptied, and keep Escape and AI drafts from discarding HTML composer work
Matthew Meszaros2026-09-30 21:15:29 -07:00
91130a7102
Merge pull request #773 from warmbly/test/unibox-row-menu-one-open
Matthew Meszaros2026-10-01 04:04:50 +00:00
f41b377f0c
feat: offer the Advisor's campaign hold only while a mailbox is still sending cold, reseed warmup when an AI tool switches a mailbox on or starts warmup, and fix the mailbox switch's bulk selection, double clicks and revoked-mailbox hints
Matthew Meszaros2026-09-30 21:02:00 -07:00
ba6c5aa614
feat: test that unibox conversation row menus stay one at a time across right-clicks and close on a press outside them
Matthew Meszaros2026-09-30 21:00:55 -07:00
85abe0c0ef
Merge pull request #769 from warmbly/fix/popover-menu-outside-close
Matthew Meszaros2026-10-01 03:49:55 +00:00
588591684b
feat: send a unibox template's HTML body as written by giving the compose and reply composers an HTML mode, keep that HTML in compose and reply drafts, and render the text part server-side for HTML-only sends
Matthew Meszaros2026-09-30 20:46:21 -07:00
7e204ee745
Merge pull request #770 from warmbly/feature/unibox-conversation-context-menu
Matthew Meszaros2026-10-01 03:46:07 +00:00
4e81213557
feat: close every PopoverMenu on a press outside it (pointerdown, capture phase, so taps count) and on Escape innermost first, keep one menu open at a time across the dashboard while nested menus stay open, give scope rail row counts room beside the always-visible phone "…" and line section header menus up with the row menus, and say in the unibox guide how the rail menus close
Matthew Meszaros2026-09-30 20:35:18 -07:00
7ea17c0150
feat: let a switched-off mailbox be switched back on from its row menu, warmup menu, drawer, settings and the selection bar, and make the Advisor's stop-cold-sending fixes hold the mailbox from campaigns instead of switching it off
Matthew Meszaros2026-09-30 20:45:42 -07:00
a4b85ebcf9
feat: add a right-click menu to unibox conversation rows (open in new tab, read state, snooze, labels, archive or move to inbox, delete) that acts on the whole selection from a ticked row, closes the open conversation when it files or marks it unread, and share useAnchoredMenu and the label panel with the scope rail and reader
Matthew Meszaros2026-09-30 20:39:10 -07:00
6e40290798
Merge pull request #766 from Skylinerffm97/feat/unibox-scope-rail-resize
Matthew Meszaros2026-10-01 03:35:26 +00:00
f3e9505457
feat: pass each warmup retention prune statement only the arguments it references, so the mailbox_owner_activity delete no longer fails PruneWarmupEventsBefore and the warmup_received and warmup_tokens prunes after it run, with the live retention test covering the owner activity window
Matthew Meszaros2026-09-30 20:32:28 -07:00
3ec2ff7d95
web(unibox): let the scope rail be resized like the conversation list
Skylinerffm972026-09-30 12:30:19 +02:00
fbadb837b8
feat: put a linked instance's existing Cloud redirect back when its update is refused, and say in the sending domains guide which unconfirmed checks still show Live
Matthew Meszaros2026-09-30 07:40:22 -07:00
371eafd9da
feat: renumber the domain redirect serving migration to 000238 after main released 000237
Matthew Meszaros2026-09-30 07:19:59 -07:00
d64adcc191
Merge remote-tracking branch 'origin/main' into feat/cloud-domain-redirects
Matthew Meszaros2026-09-30 07:18:51 -07:00
89c0550046
Merge pull request #762 from warmbly/fix/auth-and-permission-hardening
Matthew Meszaros2026-09-30 14:05:05 +00:00
e9b802e99c
feat: insert the received-mail CSP into the parsed document's real head, tie remote-image consent to the message it was given for, check every RevokeOnRefreshReuse error in the live test, and name the signing-key length refusal in the OpenAPI 400
Matthew Meszaros2026-09-30 07:01:13 -07:00
7b526be901
feat: write a Cloud-served root redirect here before asking Warmbly Cloud (one workspace per domain, enforced by a unique index), roll it back on Cloud's refusal and keep it pending through an outage, release Cloud redirects no workspace here has any more from the sweep, resend a target Cloud holds stale, stop a mirrored redirect only on Cloud's definite refusals, read a proxy gateway error as transient and order the certificate and port verdicts correctly, validate linked domains with the shared hostname check, share one proxy name map, and trim comments
Matthew Meszaros2026-09-30 06:59:55 -07:00
75f764dc67
feat: require a verified Cloud Tasks token with a pinned audience on task webhooks, manage_settings on integration OAuth and a fresh membership check at every mailbox and integration OAuth finish, user verification for passkey sign-in, ended sessions before a password reset or ban reports success, and a revoked session when a rotated refresh token is replayed; remove the internal DEK delete route, log credential path parameters by name, hold remote images in received mail until the reader loads them, add Calendly and Cal.com signing keys with inbound URL rotation, keep automation signing secrets out of connection responses, and apply the password rules to the bootstrap password
Matthew Meszaros2026-09-30 06:46:20 -07:00
ef83f10a7e
feat: refuse a root redirect upsert that meets the domain's row held by another owner (a linked instance or the workspace) instead of rewriting it, keep the Warmbly Cloud option closed for a Cloud-served redirect once the link or offer is gone, and say in the sending domains guide that the dashboard preselects Cloud while the API keeps this instance
Matthew Meszaros2026-09-30 06:29:53 -07:00
d457ad86e3
feat: keep Warmbly Cloud's link-token answers from ever reaching the dashboard as a 401, stop a Cloud-served redirect Cloud refuses to take back, drop a new Cloud row its own check refused, store only reach values this schema knows when mirroring a newer Cloud, read an offer-less Cloud as not serving redirects, confirm bulk moves against the server actually sent, poll the Cloud offer once a minute, and probe without keep-alive connections
Matthew Meszaros2026-09-30 06:21:29 -07:00
41d43f64be
feat: check that a verified root redirect actually reaches visitors by opening the domain over http and https and naming what answered instead (Traefik, nginx, Caddy, a rewritten Host header, a missing certificate, a closed port) with per-proxy fix steps in the sending domain drawer, and let a self-hosted instance linked to Warmbly Cloud have Cloud serve and certify its redirects (connect in place from the redirect tab, the bulk dialog or a page banner), with Cloud-side linked-instance redirect endpoints under a per-instance limit, migration 000237, labelled tracking answers and a 503 when the redirect lookup is unavailable, and the sending domains, Warmbly Cloud, data control, install, OpenAPI, API and error code docs updated
Matthew Meszaros2026-09-30 06:04:00 -07:00
282280c596
Merge pull request #759 from warmbly/feature/common-reply-inbox-sender-tracking
Matthew Meszaros2026-09-30 12:41:21 +00:00
1f0c6ca6d6
feat: send each mailbox's reply-to as a Reply-To header on campaign, unibox, test and placement mail (never warmup), record it on every campaign send attempt (tasks.reply_to, migration 000236) and credit a reply landing in that shared reply inbox to the campaign and its sending mailbox across reply attribution, the sync priority lane and copied-contact replies, show the sending mailbox on thread messages, recent activity and the reply webhook, start unibox and inbox-agent replies from the mailbox that emailed the contact, flag an untracked reply-to in mailbox settings, let the sandbox simulator answer Reply-To, and document the shared reply inbox (#756)
Matthew Meszaros2026-09-30 05:33:34 -07:00
4bfebe8538
feat: write a relayed folder answer straight to the unibox row without reading it first, since the unibox GetByID marks an unread message seen and archiving unread mail must leave it unread, with a consumer test that fails on any read
Matthew Meszaros2026-09-30 05:11:17 -07:00
d06829e7c3
Merge pull request #758 from warmbly/feature/unibox-rail-favorites
Matthew Meszaros2026-09-30 12:00:48 +00:00
b4312d7ec1
feat: keep favorites starred during a Favorites edit, re-highlight in Favorites after a scope is reached by shortcut or Back, name the target of a renamed view on hover, word the hide toast by where the highlight is, route the edit-mode star through the menu's add, cap favorite names by code point, and memoize the mailbox, label and tag rail rows
Matthew Meszaros2026-09-30 04:57:00 -07:00
e3c9ddde01
feat: add an optional Favorites section to the top of the unibox scope rail that gathers starred Mail, Views, Mailboxes, Labels and Tags rows with live counts, starred from any row's menu or the Mail and Views edit mode, folding, moving, reordering and renaming like the other sections, removable with undo, remembered per browser, with tests and the unibox guide updated (closes#743)
Matthew Meszaros2026-09-30 04:43:27 -07:00
b2d6d100dd
feat: relay unibox Archive, Delete and Move to inbox to the mailbox itself through a new MESSAGE_FOLDER worker command (Gmail label batchModify, Outlook well-known folder moves with the message map re-keyed around each Graph id change, IMAP MOVE after locating each message by Message-ID), answered by relayed UPDATE_FOLDER events that write only provider_folder and the moved handles, relaying every row a filing moved so an Undo right after Archive still reaches the mailbox, with a per-mailbox Mirror Archive and Delete switch (email_accounts.relay_folder_moves, migration 000235, on by default), warmup receipts, drafts and non-Gmail sent copies left in place, and the unibox, mailboxes, API, events and OpenAPI docs updated
Matthew Meszaros2026-09-30 04:41:03 -07:00
77f38fad1a
feat: keep dashboard sidebar tooltips shut on collapse for rows hovered while expanded by letting only the collapsed rail open a NavTip and dropping any stale open state when the mode flips, with a unibox layout test for the collapse and round trip (fixes#742)
Skylinerffm972026-09-29 19:34:23 +00:00
a34e1634fc
feat: merge main into the placement comparison branch, keeping both the rendered-copy and the placement-batch sentences in the workspace export guide's placement row
Matthew Meszaros2026-09-30 08:20:40 +02:00
d3fc3133da
feat: renumber the placement_renders migration from 000230 to 000234 so it follows 000233 on main instead of colliding with the released 000230_campaign_lead_cc
Matthew Meszaros2026-09-30 08:20:39 +02:00
e6fc0ffc64
Merge pull request #755 from warmbly/fix/warmup-single-spam-flag-pause
Matthew Meszaros2026-09-30 05:14:54 +00:00
0ce8a6ee79
feat: claim each held warmup spam move with a lease, fix its verdict before applying any effect and complete it only after every sender and recipient write succeeds, so consumer replicas never charge a strike that disagrees with the recorded verdict and a failed write re-applies the same verdict
Matthew Meszaros2026-09-30 07:08:40 +02:00
d3c0f76002
Merge remote-tracking branch 'origin/main' into calm-marlin-jks7
Matthew Meszaros2026-09-30 06:52:32 +02:00
57a26c4ee6
feat: attribute a received warmup email moved to spam on the evidence around it before charging anyone, never for mail that arrived in spam (warmup_received.landed_spam), holding each move 30 minutes in warmup_spam_moves and deciding provider on a cross-workspace correlation or a move straight after arrival with nobody there, owner on provider-reported read, unread or star activity in mailbox_owner_activity or a repeated uncorrelated pattern in a used mailbox, nobody otherwise, weighting a spam move as one strike, withdrawing owner verdicts a later correlation explains, clearing the strikes behind a hold an admin lifts or an appeal approves, migration 000233, docs and guide
Matthew Meszaros2026-09-30 06:52:32 +02:00
feafc8ea0d
Merge pull request #754 from warmbly/fix/contact-bulk-request-limit
Matthew Meszaros2026-09-30 04:28:32 +00:00
184e26a427
feat: call contact categories and inbox labels one name, Labels, across the dashboard (contacts tab moved to /app/contacts/labels with a redirect, pickers, filters, import, export, forms, segment field, timeline, and the Add label, Remove label and Label conversation automation actions), backend messages, AI tool descriptions and docs, keeping every API field name unchanged
Matthew Meszaros2026-09-30 06:17:57 +02:00
045d13d281
feat: let segment membership writes take the same contact selection limits as every other bulk action, raise select-all to 250,000 contacts and explicit id batches to 10,000, check the research batch cap in the dashboard before confirming, and document the new limits in the guides, error codes and OpenAPI spec
Matthew Meszaros2026-09-30 06:13:14 +02:00
792b0506bc
feat: return the passkey button to ready after an aborted explicit sign-in so it can be retried, and document that a new worker command type must be safe to lose while the fleet is still on the previous release
Matthew Meszaros2026-09-29 20:27:26 +02:00
17a0ebfac0
feat: record the jobs.worker-events schema snapshot with the UPDATE_FOLDER event and the fields main added since the snapshot was taken
Matthew Meszaros2026-09-29 20:15:17 +02:00
e76cdc6f3a
Merge remote-tracking branch 'origin/main' into fix/recent-posthog-errors-2
Matthew Meszaros2026-09-29 20:13:29 +02:00
4b0446042a
Merge pull request #750 from warmbly/feature/batch-inbox-placement-tests
Matthew Meszaros2026-09-29 17:59:48 +00:00
d162f0aaf6
Merge pull request #748 from warmbly/fix/gmail-archive-unibox-inbox-sync
Matthew Meszaros2026-09-29 17:57:41 +00:00
d998619455
feat: renumber the placement batch migration to 000232 after main took 000230 and 000231 for lead CC, and require that version in the batch live tests
Matthew Meszaros2026-09-29 10:53:12 -07:00
974c68cd92
feat: bound the Gmail folder reconciliation's inbox listing by the oldest stored row in any reconciled folder, so an archived, spam or trash row older than every inbox row that Gmail moved back to the inbox is still found
Matthew Meszaros2026-09-29 10:51:54 -07:00
80ecadb1e6
Merge remote-tracking branch 'origin/main' into feature/batch-inbox-placement-tests
Matthew Meszaros2026-09-29 10:51:41 -07:00