Commit Graph
2655 Commits
Author SHA1 Message Date
Matthew Meszaros e562e09354 Merge pull request #593 from warmbly/fix/mailbox-disconnect-workspace-scope
Scope mailbox disconnect to the workspace and surface the API's reason
2026-09-19 04:15:40 +00:00
Matthew Meszaros 4b2b641f92 feat: pass the workspace id to the mailbox delete in the database-backed removal and erasure tests, which compiled with the owner's id but would answer not found now that Delete is scoped to the organization, and rename the cloud link stub's parameter to say what it carries 2026-09-19 06:10:32 +02:00
Matthew Meszaros f99ee57484 feat: scope mailbox disconnect to the workspace instead of the connecting member, so a teammate with manage_emails no longer gets 404 on a mailbox the list shows them, delete by id in the repository on the strength of that check while the worker removal still names the owner the consumer's unibox cleanup is keyed on, and read the API's own reason off the normalised AppError in the accounts page so a refused disconnect says why instead of "The mailbox couldn't be disconnected" on every failure 2026-09-19 06:01:03 +02:00
Matthew Meszaros b31c5d521b Merge pull request #591 from warmbly/fix/reply-attribution-and-human-opens
Count thread replies from any address as replied, and count only a person's opens
v0.4.25
2026-09-18 12:56:39 +00:00
Matthew Meszaros ffe3159256 feat: order the repair sweep's fake inbox by id so the cursor assertion is deterministic like the query it stands in for 2026-09-18 14:51:18 +02:00
Matthew Meszaros bd092dcf04 Merge remote-tracking branch 'origin/main' into fix/reply-attribution-and-human-opens
# Conflicts:
#	internal/app/consumer/event_new_email.go
2026-09-18 14:44:41 +02:00
Matthew Meszaros 6aebfe7e63 feat: store IMAP-synced addresses as Name <addr> like the Gmail and Graph syncs instead of Name (addr), teach mailhdr.Bare, the reply path's sender and recipient checks and the warmup sender fallback to read the old form for existing rows and older workers, so a reply into an IONOS or any other IMAP mailbox is attributed to its lead again after the address checks added on 16 September refused every one of them, and add a consumer sweep that re-offers unclaimed inbound mail answering a campaign send or coming from a contact to reply processing at boot and daily so the replies missed that week are attributed without anyone touching the database 2026-09-18 14:37:35 +02:00
Matthew Meszaros 6a236423be Merge pull request #590 from warmbly/fix/warmup-thread-replies-out-of-inbox
Keep hand-typed replies in warmup threads out of the inbox and unibox
2026-09-18 12:33:28 +00:00
Matthew Meszaros 81d46bdcc8 feat: attribute a campaign reply by the thread it answers rather than requiring the From address to equal the contact's, so a person replying from a Gmail send-as alias, a forward or a colleague's desk counts as replied for that lead, stamp replied_at whether or not reply-intent automation is switched on, suppress the mailed address too when an alias reply opts out, and count only a person's opens in every open count and open rate (campaign overview, per step, daily, hourly, dashboard, recent activity) with machine opens shown as a separate not-counted figure, matching how the Leads tab already reads opened 2026-09-18 14:29:16 +02:00
Matthew Meszaros e737506ba0 feat: recognise a reply typed by hand in a warmup thread by the message it answers (In-Reply-To against warmup sends, receipts and earlier recognised turns, locally and through the pool link), keep it out of the unibox, file it out of the customer's Gmail, Outlook or IMAP inbox with the same folder action, record each recognised turn in warmup_thread_messages so the turn after it is recognised too, and let the daily sweep repair replies that already leaked 2026-09-18 14:12:33 +02:00
Matthew Meszaros 94482df9d1 Merge pull request #589 from warmbly/fix/campaign-progress-and-daily-budget-visibility
Fix campaign progress counts, the stuck Sending card, and explain a spent daily budget per mailbox
2026-09-18 12:08:03 +00:00
Matthew Meszaros 7e6cbd6b1f feat: count the send in flight on the last-email-of-the-day feed line so a cap-one mailbox is shown at its cap with a budget gate rather than at zero, and put live campaign progress in emails (contacts times steps) with a total_emails field so a six-step campaign no longer reads 100% once every contact has had its first email 2026-09-18 13:54:12 +02:00
Matthew Meszaros 52cdf829d6 feat: say a campaign is sending its last email of the day only when the whole mailbox pool has one send left, not just the provider-matched subset ESP matching narrowed it to 2026-09-18 13:18:40 +02:00
Matthew Meszaros 5b96ce903b feat: count campaign progress from each table on its own so one sent email is no longer multiplied by leads times steps into 378 of 63 contacts at 100%, show the live Sending card only while a named contact's email is in flight and close it on EMAIL_SENT instead of leaving Sending Unknown contact up all day, and write the day's last send and every budget-spent line to the campaign feed with a per-mailbox breakdown of the cap, the clamp that set it, sends today, the gate and warmup health band so a campaign sending one email a morning says why 2026-09-18 13:12:07 +02:00
Matthew Meszaros 7c880c4983 Merge pull request #588 from warmbly/fix/phantom-mailboxes-and-remaining-errors
fix: a deleted mailbox kept running on its worker forever, an IMAP UIDVALIDITY above 2^31 could not be stored, plus the remaining open errors
2026-09-18 11:03:09 +00:00
Matthew Meszaros 1f4e00acf4 feat: widen unibox_mailboxes.uid_validity and unibox_emails.uid to bigint, because RFC 3501 defines UIDVALIDITY and UID as unsigned 32-bit and the models carry them as uint32, so an IMAP server stamping a UIDVALIDITY at or above 2^31 could not bind the value at all and that mailbox's folder row could never be written nor its sync progress; uid_next and highestmodseq on the same table were already widened for this and these two were missed 2026-09-18 12:57:16 +02:00
Matthew Meszaros 55b66a68eb feat: hold the mailbox rows until the delete commits when collecting the worker assignments a scheduled deletion destroys, so a rotation landing between the read and the cascade cannot leave the new worker holding a mailbox nobody evicts, locking every mailbox in scope rather than only the assigned ones because one that gains a worker in that window is the same bug, and place the danger-zone live fixture's mailbox on a real worker so the assertion exercises what it claims to 2026-09-18 12:54:45 +02:00
Matthew Meszaros cd964aafa8 feat: stop a deleted mailbox living on inside its worker, by returning the worker assignments a scheduled org or user deletion destroys so the erasure path can evict them the way the single-mailbox delete already does, and by treating an assignment lookup that finds no row as the mailbox being gone rather than a failed lookup, which tells every live worker to drop it; and clear the rest of error tracking by retrying a mailbox delete that loses a deadlock to its own cascade instead of failing the person who clicked Disconnect, answering a daily-usage read for a mailbox that no longer exists with 404 rather than a reported 500, and guarding the inner data field on three list reads plus serialising an empty pool-link list as [] rather than null 2026-09-18 12:42:43 +02:00
Matthew Meszaros f7c033b674 Merge pull request #587 from warmbly/fix/password-reset-email-not-sent
fix: password reset reported success while sending nothing, and a failure spent the user's retry budget
v0.4.24
2026-09-18 09:47:56 +00:00
Matthew Meszaros 0e914ee390 feat: stop the password reset flow reporting success while sending nothing, by answering 200 only for an address with no account rather than for every cache and database fault, folding addresses to one case on every account lookup and write so a typed capital cannot miss the row or split an SSO account in two, refunding the two-per-four-hours budget when the failure was ours, retrying one transient send and quoting the link's real lifetime; and clear the rest of error tracking by grouping the engagement breakdown in a subquery so ORDER BY stops resolving opens against email_opens, dropping unibox_mailboxes and email_sync_state writes whose mailbox was deleted mid-sync instead of redelivering them forever, answering a corrupt argon2 hash with ErrCredentials rather than a 500, never filing a cancelled caller as a database incident, and reporting only the first websocket init failure of a streak 2026-09-18 11:42:49 +02:00
Matthew Meszaros ae4c1631e9 Merge pull request #586 from warmbly/fix/avro-field-defaults
fix: stop a new Avro field refusing the whole envelope, file historical warmup leaks out of the customer's mailbox, and stop a rollout evacuating a worker
2026-09-18 09:35:21 +00:00
Matthew Meszaros a0a19edeae feat: register a schema document whose fixed defaults are code-point strings and whose nested nulls are null so the registered envelope parses back, keep the warmup unibox row until the filing action is on the bus and the mailbox lookup is not a transient failure, recheck the heartbeat key before evacuating a worker, match the IMAP namespace prefix case-insensitively, and state the BACKWARD direction correctly 2026-09-18 11:29:48 +02:00
Matthew Meszaros a7cabe1b95 Merge pull request #585 from tunglambk/fix/instant-branch-target-wait
fix: an instant conditional branch no longer applies its target step's wait_after (#583)
2026-09-18 09:29:22 +00:00
Matthew Meszaros 4c941fdbca Merge pull request #584 from tunglambk/fix/managed-mailbox-delete-cloud-revocation
Release a cloud-managed mirror's cloud link when the mailbox is deleted (#582)
2026-09-18 09:28:06 +00:00
Matthew Meszaros eab6b05912 Merge pull request #579 from joaoppa/fix/hostinger-dkim-selectors
Hostinger's DKIM selectors are hyphenated, not numbered
2026-09-18 09:28:05 +00:00
Matthew Meszaros 292b523c5b feat: document in the sequences guide that an instant branch's email target goes out on the next scheduling pass inside sending hours and mailbox spacing while a non-instant path keeps the target's wait 2026-09-18 02:23:55 -07:00
Matthew Meszaros 195f6bf2cd feat: add a live scheduler test proving an instant branch's target is sendable through CalculateNextCampaignTime and the contact preview without its step wait_after, and that opting the branch out restores the wait 2026-09-18 02:23:25 -07:00
Matthew Meszaros 4c035e2521 feat: let RevokeForDelete treat a revoked cloud link as released so Disconnect still deletes cloud-managed mirrors after revoking the instance, with regression tests for the Disconnect flow and a revoked-link delete 2026-09-18 02:20:44 -07:00
Matthew Meszaros 719d31b264 feat: cover Hostinger's hyphenated DKIM selectors in the dnsauth MX-hint tests so dropping hostingermail-a and hostingermail-b from providerSelectors fails the suite 2026-09-18 02:19:18 -07:00
Matthew Meszaros 2e389ccc44 feat: make IMAP warmup filing survive a server that answers CREATE with ALREADYEXISTS or lists the folder under another spelling, qualify the bare folder name on the engagement and move paths so a Dovecot INBOX. namespace no longer refuses the SELECT, and never prefix INBOX itself 2026-09-18 11:12:24 +02:00
Matthew Meszaros bd1837833e feat: give every derived Avro field its zero as a default and register the marshalled schema so adding a field cannot refuse the whole envelope and stop every publish, file historical warmup leaks out of the customer's own mailbox rather than only the unibox, and make a worker earn a 10-minute absence before its mailboxes are evacuated so a version rollout costs no migrations 2026-09-18 10:34:36 +02:00
tunglambk bae46914d5 feat: stop applying a target step's wait_after when an instant conditional branch routes to it (#583) 2026-09-18 08:26:18 +00:00
tunglambk cf7e530e15 feat: release a cloud-managed mirror's cloud link when it is deleted through the mailbox delete, using the delete-only revocation that never calls back into the mailbox delete, so the mailbox returns to the cloud workspace instead of staying claimed by an instance that no longer holds it (issue #582) 2026-09-18 07:17:40 +00:00
Matthew Meszaros 9211a3958f Merge pull request #578 from warmbly/fix/closiqode-reported-issues
feat: fix the four standing defects in #574 and the same-workspace warmup pairing in #575
v0.4.23
2026-09-18 04:26:50 +00:00
Matthew Meszaros 8240f14e8b feat: fail closed on incomplete cloud mailbox revocation and document retry-safe deletion and TLS diagnostics 2026-09-17 21:21:34 -07:00
Matthew Meszaros e37c5053c2 feat: make warmup refunds atomic, count confirmed partner diversity in local and cloud mailbox views, and document cloud-safe mailbox deletion 2026-09-17 21:15:28 -07:00
Matthew Meszaros 177a0817c4 Merge remote-tracking branch 'origin/main' into fix/closiqode-reported-issues 2026-09-17 21:00:48 -07:00
Matthew Meszaros d739f449e3 feat: make the unibox search persistence regression deterministic by keeping the opened subject inside the debounced result set 2026-09-17 21:00:48 -07:00
Matthew Meszaros 68babc30f3 feat: give the mailbox delete its own cloud revocation that calls the pool before dropping the local row and refuses an unreadable link, so a nil answer is proof the credential is gone rather than proof the local row went, and drive the greylisting evidence guard through the real handler with stub repositories so removing it fails CI where the live test skips 2026-09-17 20:52:54 -07:00
Matthew Meszaros 703d7c3975 Merge pull request #581 from warmbly/fix/warmup-out-of-sight
Keep warmup out of the customer's mailbox, unibox and deliverability record
2026-09-18 03:51:54 +00: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 b7b6db633e Merge pull request #577 from warmbly/feature/google-oauth-not-recommended-warning
feat: mark Gmail OAuth as not recommended in the connect dialog
2026-09-18 03:34:52 +00:00
Matthew Meszaros 2ad9ed633e feat: stop the warmup guide's diversity note claiming a single workspace means the reader's own, since one distinct workspace is the signal whoever it belongs to 2026-09-17 20:23:37 -07:00
Matthew Meszaros 0bcc24cac5 feat: say in the retryable-evidence test why the mirrored condition exists alongside the live one, since the live handler test needs a database and skips in CI 2026-09-17 20:22:33 -07:00
Matthew Meszaros d2095a8a70 feat: stop a greylisted RCPT reply from being filed as bounce evidence now that the send carries the server's own words, revoke a cloud enrollment after the worker removal and put the mailbox back when the revocation is refused so a failed delete really changes nothing, drop the unenroll-under-Settings advice that makes the same failing call, and only log a within-workspace pairing when there is a sibling to draw 2026-09-17 20:19:46 -07:00
joao-crm f6c7569615 fix: probe Hostinger's hyphenated DKIM selectors alongside the numbered pair, since hostingermail-a and hostingermail-b are what the provider actually publishes and hostingermail1 and hostingermail2 answer on no domain we have been able to test, leaving every Hostinger-hosted sender reported as unsigned 2026-09-18 03:09:49 +00:00
Matthew Meszaros 7cca41b94d feat: document the mailbox_cloud_unenroll_failed conflict that a delete now returns when a Warmbly Cloud enrollment cannot be revoked, in the 409 section of the error codes reference and as the delete endpoint's own error table alongside mailbox_worker_unreachable 2026-09-17 20:05:11 -07:00
Matthew Meszaros 5936f39f9f Merge remote-tracking branch 'origin/main' into fix/closiqode-reported-issues 2026-09-17 20:02:49 -07:00
Matthew Meszaros 8ee1c50a1b feat: make a failed SMTP send name the step and the cause behind it instead of one bare SERVER_UNREACHABLE sentinel, give a refused warmup send its day back so sent_today can no longer climb past the target while the cap frees the slot, revoke a mailbox's Warmbly Cloud enrollment when it is deleted so the pool stops holding its password, and prefer warmup partners outside the sender's own workspace while showing the partner diversity a mailbox is actually getting (#574, #575) 2026-09-17 20:02:37 -07:00
Matthew Meszaros fdf7033c70 feat: correct the Gmail app-password instructions in the connect dialog and mailboxes guide, since Google removed the IMAP setting in January 2025 and app passwords are unavailable under Advanced Protection, security-key-only 2SV or an admin policy 2026-09-17 20:02:07 -07:00