Commit Graph
127 Commits
Author SHA1 Message Date
Matthew MeszarosandDevin AI 691280cdef feat: give premium warmup senders all qualified recipients and balance host coverage without paid-receiver bias
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-08 11:31:05 +00:00
Matthew MeszarosandDevin AI b4ef37fe82 feat: restore existing self-host realtime connections through normalized legacy gateway URLs and an authenticated API-origin WebSocket proxy, preserve ticket-bound client IP limits and direct retry fallback, and remember workspace mailbox tag filters across navigation with deterministic default account grouping
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-08 06:57:48 +00:00
Matthew MeszarosandDevin AI 3acfe64109 feat: preserve self-host upgrades with exact realtime CSP discovery, consumer migration readiness and backend-compatible fleet targets
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-07 06:53:14 +00:00
Matthew MeszarosandDevin AI 9d0f43780b feat: provision onboarding-complete reviewer workspaces with expiring Test access, bounded credits and Test header labels
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-05 16:15:56 +00:00
Matthew MeszarosandDevin AI 849cf18f55 feat: bind password recovery, invitations, mailbox and integration OAuth, referral and billing returns to trusted initiating dashboards
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-05 12:51:37 +00:00
Matthew MeszarosandDevin AI caa1633dac feat: verify main and TAC assessment dashboard origins share configurable backend CORS and OAuth routing
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-05 12:24:11 +00:00
Matthew MeszarosandDevin AI f58a6c1ff9 feat: control Gmail mailbox OAuth per frontend deployment and bind callbacks to allowlisted dashboard origins
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-05 12:16:34 +00:00
Matthew Meszaros e852a106a9 feat: serve every node-only internal route (data keys, message map, sync lookups, worker config, fleet heartbeat) on NODE_BROKER_TOKEN and leave only tracked links, domain redirects, page hits and forms on INTERNAL_API_TOKEN, render nodes only the node token when one is set, and have the installer generate a distinct NODE_BROKER_TOKEN for new installs and its own UPDATER_TOKEN 2026-10-04 03:21:58 -07:00
Matthew Meszaros 9f7d45a1fb feat: charge every password, emailed-code and TOTP attempt atomically before comparing it (Redis INCR+expire script) with a per-account TOTP budget across challenges, put the signed-in password change on the reauth budget, set the per-account login limit to 50 per hour, give tester passwords an expiry (users.password_expires_at, migration 000257) and clear them plus every session on revoke, mint warmblyctl reset links with the password-reset purpose, expire fleet join tokens (7 days default, 30 max, reusable inside the window), derive captcha from the resolved Turnstile secret, refuse weak bootstrap argon2id hashes, make registration codes single-use, rate-limit the v1 invitation lookup, and draw RIDs and user codes without modulo bias 2026-10-04 02:52:22 -07:00
Matthew Meszaros bc9caba267 feat: validate OAuth app names through displayname and websites as http(s), clean dynamically registered client names and stop storing their logo_uri, refuse edits and logo uploads on suspended apps or blocked developers, scope logo deletion to the app's own images, keep hidden listings from being unpublished, count only installs from other aged workspaces toward the directory threshold, refresh integration popularity outside the lock, and count only live connections in the Integrations store 2026-10-04 01:10:39 -07:00
Matthew Meszaros 7555f641a5 feat: turn Integrations into an app store with sidebar views, search, sorting and filters, list community apps by link until featured or widely installed, redesign the OAuth app registration dialog, store app logos re-encoded per app like the workspace logo, and add admin suspension, token revocation and developer blocks for OAuth apps 2026-10-04 00:31:52 -07:00
Matthew Meszaros 61d16dfe9a feat: add Warmbly for Slack with the AI assistant in DMs, mentions and the assistant pane, unified inbox threads with reply, AI draft and lead actions, per-category notification routing and DMs, account linking, dashboard Slack settings, manifest and docs 2026-10-03 15:35:11 +02:00
Matthew Meszaros 77ec1df58b Merge pull request #810 from warmbly/claude/fix-801-scheduler-keyset-paging
feat: bound campaign recipient selection with a two-phase ordered-candidate scan
2026-10-03 06:59:33 +00:00
Claude 3288238cc0 feat: paginate and batch GET /analytics/accounts so account status reads are bounded per page and the overflow past 1000 mailboxes is reachable via cursor 2026-10-03 06:46:20 +00:00
Claude a77f25ce4f feat: bound campaign recipient selection via a cheap ordered-candidate enumeration plus chunked routedLeadsQuery hydration in FindRoutedPairs, with a campaign_leads(campaign_id,position,contact_id) index 2026-10-03 06:40:38 +00:00
Matthew Meszaros 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 2026-09-30 06:04:00 -07:00
Matthew Meszaros 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 2026-09-30 06:52:32 +02:00
Matthew Meszaros 4b0446042a Merge pull request #750 from warmbly/feature/batch-inbox-placement-tests
feat: run one inbox placement test across many sending mailboxes as a placement batch, with server-side sender scopes, sampling, bounded concurrent execution, fleet grouping and coverage
2026-09-29 17:59:48 +00:00
Matthew Meszaros d162f0aaf6 Merge pull request #748 from warmbly/fix/gmail-archive-unibox-inbox-sync
feat: file Gmail mail where Gmail moves it (archive, delete, spam, back to inbox) via an UPDATE_FOLDER event resolved against provider_folder, repair rows already stranded in the unibox Inbox with a six-hourly Gmail folder reconciliation, and close the open unibox conversation on a scope change with a close button in the reader header
2026-09-29 17:57:41 +00:00
Matthew Meszaros 80ecadb1e6 Merge remote-tracking branch 'origin/main' into feature/batch-inbox-placement-tests 2026-09-29 10:51:41 -07:00
Matthew Meszaros 3290360333 feat: keep the Gmail folder reconciliation going past a message Gmail refuses, list the inbox by label, remove rows Gmail no longer has, retry a failed pass after 15 minutes, report each Gmail move once per tick, answer the internal listing with a fixed error, and keep the conversation open when widening to All mail 2026-09-29 10:40:34 -07:00
Matthew Meszaros d99a09825f feat: run one inbox placement test across many sending mailboxes as a placement batch (issue #736): server-side sender scopes (a campaign's senders or the whole workspace, filtered by provider, domain, tag and untested days) and sampling (random, percent stratified by provider or domain, per domain, per provider) snapshotted at creation, a runner that starts senders under per-workspace and instance-wide concurrency and a start rate with defer or skip for unavailable mailboxes, aggregate placement by sending domain, sending provider and recipient provider, fleet coverage, cancel, credits agreed per batch, org transfer, operator settings in the admin panel, dashboard pages and dialog, CLI commands, agent tools, OpenAPI and docs 2026-09-29 10:19:46 -07:00
Matthew Meszaros 0ed98a8c55 feat: copy up to two colleagues on every email a campaign sends one lead (campaign_lead_cc, migrations 000230-000231) with a drawer CC editor that suggests same-company contacts, hold a copied contact's own lead so nobody gets two threads, count a copy's reply as the lead's, opt out every copy on a link unsubscribe, drop a bounced or refused copy without bouncing the lead, skip suppressed campaign CC and BCC addresses, and document the endpoints, CLI, skills and OpenAPI 2026-09-29 09:53:27 -07:00
Matthew Meszaros e2f319cfd8 feat: file Gmail mail where Gmail moves it (archive, delete, spam, back to inbox) via an UPDATE_FOLDER event resolved against provider_folder, repair rows already stranded in the unibox Inbox with a six-hourly Gmail folder reconciliation, and close the open unibox conversation on a scope change with a close button in the reader header 2026-09-29 09:43:13 -07:00
Matthew Meszaros ad4104c57a feat: never add a warmup strike from a recheck (confirm it, or withdraw it when the message is still in the mailbox or retention removed it since), revise a tampering hold before its strike is deleted so a retry completes it, compare-and-swap the revision on the hold's term, scope the ledger revision to the whole address, keep tampering events 37 days so a live hold's strikes survive pruning, answer an inconclusive search as unknown so IMAP rechecks stop, and return an IMAP transport failure as an error 2026-09-29 05:12:36 -07:00
Matthew Meszaros f4f219b7c5 feat: run contact file imports as background jobs (upload once, a whole-file check of new, existing, repeated and invalid rows, a chunked leased runner with live CONTACT_IMPORT_PROGRESS, history, cancel, a draft that autosaves and survives a reload, remembered mappings, and a failed-rows CSV under the file's own headers), match existing contacts across the workspace, batch updates and fail a bad row alone, keep imported verdicts on update, scope every import write to the importing workspace, rebuild the import wizard with icons and inline segment creation, show company logos and the inbox provider on the contact avatar, and hide contact columns the list has no data for 2026-09-27 21:50:10 -07:00
Matthew Meszaros 4924d2c88d feat: let a placement test target chosen seed inboxes or providers, add a quick pace that sends copies seconds apart, charge credits with explicit consent for tests past the monthly free allowance with automatic refunds for tests that deliver nothing, and add a Seeds picker to the compose window 2026-09-27 21:16:12 -07:00
Matthew Meszaros 8812cba439 feat: detect each contact's inbox provider from its domain's MX and SPF in a backend sweep, show it as a sortable Email provider column with the provider logo, filter and segment on it across contacts, campaign leads and segments, and use it for campaign ESP matching including Workspace and Microsoft 365 custom domains and the coverage panel's per-provider lead counts 2026-09-26 06:33:44 -07:00
Matthew Meszaros c6027fecde Merge pull request #694 from warmbly/fix/premium-warmup-pool-partners
feat: borrow the best proven free warmup mailboxes whenever a premium mailbox has too few outside-workspace partners, reserve a quarter of every inbox's daily warmup capacity for premium senders, and show the pool and partner cap in the mailbox drawer
2026-09-26 05:07:38 +00:00
Matthew Meszaros 6e62c500c3 feat: borrow the best proven free warmup mailboxes whenever a premium mailbox has fewer outside-workspace partners than max(25, its warmup ceiling) so siblings no longer block borrowing, keep a quarter of every inbox's daily warmup capacity for premium senders, and show the pool and any partner cap on today's target in the mailbox drawer 2026-09-25 21:47:36 -07:00
Matthew Meszaros caf1852217 feat: keep placement seeds out of warmup pools as recipients too, store a probe's Message-ID before the send, hold queued probes against the sender's day and size a test to what is left, claim due monitors so one replica runs each, write comparison halves in one transaction, scan each seed's mail once per tick, keep test history when a mailbox is deleted, default to 20 seeds a minute apart, and render cloud-panel tests without a real lead by default 2026-09-25 21:46:09 -07:00
Matthew Meszaros 7f324a38ac feat: open inbox placement tests to workspaces with probes rendered like the campaign send and paced as placement tasks, Message-ID matching instead of a subject token and warmup header, instance, workspace and Warmbly Cloud seed panels, a tracking comparison, scheduled campaign monitors with alerts and optional auto-pause, monthly allowances, realtime updates and org transfer registration 2026-09-25 20:48:15 -07:00
Matthew Meszaros 0fedc7abe6 feat: default tracking hosts to link.<domain>, set one tracking subdomain and redirect website for every domain in mailbox imports and on Sending domains with a per-domain dropdown to override each, add POST /emails/domains/bulk that goes through the inbox vendor's API where it can, add multi-select with check DNS, copy records, CSV export, clear tracking and remove redirect to Sending domains, and fix the sandbox seed's deliverability conflict target 2026-09-25 09:30:36 -07:00
Matthew Meszaros a54e9a3a2f feat: keep a campaign's pass chain running through every failure (a pass whose hand-off to a worker fails or that errors is followed by another a minute later instead of waiting on the reconciler, retries move their slot, dead-lettered passes replay through the campaign lock), pass over mailboxes no heartbeating worker holds (worker_id now loaded with the sender pool, shown as Reconnecting in the send plan), count a hand-off failure against the lead only when it is the lead's, and try up to 200 due leads per pass with a daily activity line when all are waiting 2026-09-24 19:56:14 -07:00
Matthew Meszaros 256010725b feat: count only email steps in every sent total (contact drawer, Leads view and statuses, campaign progress, guardrails, org conduct, verification evidence, segments, admin, advisor), keep line breaks in synced body text and strip quoted history in any shape, classify delivery failures before out-of-office and tag them as bounces, record statusless failure notices from X-Failed-Recipients as permanent bounces, limit reply and inbox-tag opt-outs to people answering our outreach (never bounces, auto-replies or list mail), and recheck earlier reply opt-outs, lifting with an audit entry only those the message that wrote them no longer supports 2026-09-24 09:44:17 -07:00
Matthew Meszaros ce5eb4fd25 feat: let a Unibox reply or forward choose its sending mailbox in From (the shared MailboxPicker without Auto, kept in the draft and the undo-send), send the provider thread handle only from a mailbox that holds the thread so a switched reply threads on In-Reply-To alone, and scope scheduled sends, their cancel, count and cap to the organization whose mailboxes send them (#670) 2026-09-23 21:18:20 -07:00
Matthew Meszaros 0eb4e30fec feat: record a Microsoft 365 grant only when the consenting sign-in holds the Global Administrator or Privileged Role Administrator role, validate a tracking host before any vendor DNS write, clear Graph delta cursors when an Outlook mailbox moves onto a grant, keep a switched-off mailbox off when it moves unless its sign-in stopped it, treat pool-link mailboxes as managed, park a delegated mailbox without a grant as inactive, honour MAILVENDOR_SANDBOX_URL only when APP_ENV is dev, drop a vendor's cached domains with its key, retry a failed import redirect setup, keep address:password pastes whose password has a comma, and move the vendor import components to import/vendors so the Go vendor ignore rule no longer drops them 2026-09-23 09:03:25 -07:00
Matthew Meszaros e58921484d feat: rebuild mailbox import around column mapping and automatic host and sign-in detection (CSV, XLSX, pasted lists, saved mappings, retryable rows with fixes, migrations 000205-000206), connect whole Google Workspace domains and Microsoft 365 organizations through a proved administrator grant, import from inbox vendors (InboxKit, Zapmail, Mailforge, Infraforge, Maildoso, Cheap Inboxes, ScaledMail) with vendor-managed forwarding and DNS, add a sending domains page with per-domain tracking and verified root redirects, unify Add account into one Google and one Microsoft entry with per-method choices, mark per-mailbox Google sign-in as retiring with in-place moves to the admin grant or an app password, allow the loopback security mode in the credential columns (migration 000207), read semicolon-separated CSVs, and add a mock vendor API to the sandbox 2026-09-23 08:41:01 -07:00
Matthew Meszaros 5a967cc3ce feat: let an IMAP mailbox exclude folders from sync (email_accounts.sync_skip_folders, migration 000196) so a folder another tool fills never reaches the unified inbox: the worker drops skipped folders and their subfolders before the walk, retires an already-synced one with its stored mail, and removes mail that later moves into one only when its Message-ID is found there; PUT /emails/:id/sync and the drawer's Sync card set the list, GET reports it with the server's folder list, warmbly mailbox skip-folders mirrors it, with docs, OpenAPI and error-code invalid_sync_folder 2026-09-22 05:15:49 -07:00
Matthew Meszaros 1513419a2a feat: delete warmup mail from each mailbox once past a per-mailbox retention window (email_accounts.warmup_retention_days, else retention.warmup_mail_days, default 30) via a consumer sweep that retires the receipt and sender copy and a worker delete action that trashes on Gmail, deletes on Graph, expunges on IMAP and drops the stored body, prune per-message warmup records after retention.warmup_event_days, and count a warmup deletion as tampering only within 24 hours of arrival and never for a retired message, judging Gmail's Trash label on the same rule 2026-09-21 00:52:02 -07:00
Matthew Meszaros d6384d3c0e feat: make cross-tier warmup an exchange so a proven free mailbox writes back to the paying mailboxes that wrote to it, favour the inbox owed the most on every draw, cap what any inbox receives per day inside WarmupPartnerCandidates so a thin tier is neither starved nor flooded, and surface received counts in the mailbox drawer, warmup analytics and the API (#633) 2026-09-20 09:42:53 -07:00
Matthew Meszaros b09ec39907 Merge pull request #599 from warmbly/chore/casa-al1-security-assessment
feat: complete the ADA CASA AL1 control set and ship the assessment evidence pack
2026-09-19 06:39:12 +00:00
Matthew Meszaros e668a2a36b feat: complete the ADA CASA v2.1.1 AL1 control set across authentication, sessions, access control, cryptography, input validation and configuration, adding a breached-password denylist and per-account login throttling, enforced multi-factor authentication on the admin panel, step-up confirmation before an action that mints a lasting credential, purpose-scoped session tokens, single-use TOTP steps, tenant verification on every cross-referenced identifier, security headers on every surface, encrypted webhook signing secrets, per-organization idempotency, PKCE and a minimal two-scope Gmail consent on the mailbox OAuth flow, bounded spreadsheet and archive decoding, a patched Go toolchain with govulncheck in CI, and the evidence pack under compliance/casa 2026-09-19 08:18:35 +02:00
Matthew Meszaros ee46cb49e8 feat: route new Gmail and Google Workspace mailboxes through a guided three-step app-password connect over smtp.gmail.com and imap.gmail.com instead of Google sign-in, behind BOX_GOOGLE_OAUTH_CONNECT (off by default) and announced to clients as gmail_oauth_connect on /auth/config, refusing a new gmail OAuth start with 403 mailbox_gmail_oauth_disabled in both the direct and Warmbly Cloud broker paths while leaving mailboxes already connected that way sending, syncing and re-authorizable 2026-09-18 22:06:09 -07:00
Matthew Meszaros 68c3676717 feat: keep warmup out of the customer's own mailbox and off their deliverability record: Gmail foldering now removes INBOX and SENT instead of only labelling, sent copies and reply-backs are filed in both directions, filing is configurable per mailbox (folder/inbox/archive via warmup_placement + warmup_folder, migration 000177), IMAP relocates a moved message by Message-ID so read/important stop no-opping, and a warmup send's bounce notice no longer lands in the unibox or suppresses a pool partner 2026-09-17 20:46:03 -07:00
Matthew Meszaros dcf26a2361 feat: make automatic inbox tagging atomic live and reviewable in production 2026-09-17 04:57:24 -07:00
SUMAN JANA 260898bf20 feat(inbox): automatic tagging and relevance scoring for inbound mail, optional and off by default 2026-09-17 04:57:24 -07:00
Matthew Meszaros 4784ee7d39 feat: fetch the MaxMind databases instead of requiring a mounted file (#529)
* feat: let the backend, consumer and tracking service fetch their own MaxMind databases from GEODB_URL and TRACKING_SCANNER_ASN_DB_URL, reading the archive shape from the content so a permalink tar.gz, a gzipped mmdb and a bare mmdb all work, never replacing a file already at the path, opening the bytes before installing them so a licence-key error page cannot become the database forever, skipping the AppleDouble sidecars a macOS tar writes ahead of the real file, and treating both URLs as secrets because the permalink carries the licence key

* feat: drop the trailing blank line cargo fmt --check rejects at the end of tracking/src/asndb.rs

* feat: stream the downloaded ASN archive instead of decompressing it whole, sizing each buffer from the gzip footer and the tar header so the member is allocated exactly once, which drops the peak of unwrapping a permalink tar.gz from 38 MB to 11.9 MB, essentially the database itself

* feat: stop the MaxMind licence key reaching the logs through net/http's and reqwest's own error text, which both print the URL they were given and so defeated the redaction beside them, drop userinfo as well as the query when redacting, refuse plain http for a URL carrying a credential and refuse an https-to-http redirect, and apply the size cap to the decoded database rather than the compressed transfer so a gzip bomb cannot fill the disk

* feat: strip basic-auth userinfo as well as the query when the tracking service redacts its database URL, parsing it rather than cutting at the first question mark so where a credential sits is the URL library's problem and not a guess
2026-09-15 03:06:34 -07:00
Matthew Meszaros 0a1ed6f04e feat: resolve scanner ASNs from a GeoLite2-ASN database so the catalogue's asn: entries match without a Cloudflare transform rule, ship the Proofpoint, Mimecast and Cisco ASNs enabled behind a new probable certainty that widens the consumer's machine window instead of deciding the verdict, make the tracking event dedupe claim one coalesced operation, and report an ASN database that opened cleanly but resolves nothing (#440) 2026-09-15 01:48:45 -07:00
Matthew Meszaros 8d790ede6c feat: send from any address Google has verified a Gmail mailbox to send as and import the signature its owner already wrote in Gmail, reading both through gmail.settings.basic at connect and on demand via GET/POST /emails/:id/identity, validating the choice against the provider's own list in the service and again inside the UPDATE, clearing it when the provider stops verifying it, and never applying it to warmup (#514) 2026-09-14 10:13:36 -07:00