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
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
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
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
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
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
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
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
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
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
a900f1e04c
feat: make worker moves atomic and preserve safe concentration and health state
2026-09-17 07:45:23 -07:00
Matthew Meszaros
2a1e55354d
feat: merge latest main before requeueing worker capacity fixes
...
# Conflicts:
# internal/app/stripe/service_test.go
2026-09-17 06:57:20 -07:00
Matthew Meszaros
c1e45b194a
feat: merge latest main before worker capacity queueing
2026-09-17 06:26:07 -07:00
Matthew Meszaros
0c44ff9121
feat: renumber worker capacity migrations after latest main
2026-09-17 06:25:51 -07:00
Matthew Meszaros
ef062392ca
feat: renumber Stripe top-up attempt migration after main
2026-09-17 15:25:41 +02:00
Matthew Meszaros
8c7827c199
feat: make Stripe credit auto-top-ups idempotent across retries
2026-09-17 15:25:35 +02:00
Matthew Meszaros
9a2c565abe
feat: enable Stripe Tax for subscriptions, credit purchases, automatic top-ups, billing details, and failure alerts
2026-09-17 15:25:26 +02:00
Matthew Meszaros
d6025ea4c0
feat: address worker capacity review findings with safe migrations and recovery reporting
2026-09-17 06:24:14 -07:00
Matthew Meszaros
62e346c8e0
feat: restore cross-mailbox campaign reply tracking while preserving sent-folder safeguards
2026-09-17 06:03:56 -07:00
Matthew Meszaros
99273114b7
feat: renumber inbox tagging migration after direct mail analytics merged
2026-09-17 04:58:10 -07:00
Matthew Meszaros
b733d09f89
feat: make inbox follow-up labels safe for manual labels and automated mail
2026-09-17 04:57:52 -07:00
Matthew Meszaros
3c5bcc3fd8
feat: expose uncertain inbox intent without applying it as a trusted label
2026-09-17 04:57:52 -07:00
SUMAN JANA
3b8761d361
feat(inbox): explain every tag on hover, label live mail, and keep follow-ups working with no external service
2026-09-17 04:57:52 -07:00