Matthew Meszaros
|
5241256274
|
feat: classify OAuth token refusals by what the provider actually said instead of calling every non-5xx refusal a dead grant: internal/pkg/mailauth reads the RFC 6749 error code, so a revoked or expired grant (invalid_grant and the interaction family) is an authentication error the customer must reconnect, while a 429 from the token endpoint, a 5xx, an unrecognised code and above all invalid_client stay retryable, because an expired app secret returns invalid_client for every Outlook mailbox on the install at once and deactivating all of them into a re-consent that cannot work either is a far worse outage than retrying until it is rotated; the Graph client logs the provider's own error code and description next to the verdict, and the tests drive real refusals through the real oauth2 transport on the fetch, list and send paths
|
2026-08-27 20:35:01 -07:00 |
|
joao-crm
|
801d1d5f83
|
feat: tell the worker to drop a mailbox the moment it is deactivated, and stop reporting a revoked OAuth grant as an unreachable mail server: every deactivation path now goes through deactivateAccount, which publishes the REMOVE_EMAIL command that already existed on both ends but had no caller, and the Graph client classifies a failure of the HTTP call itself so a refresh the provider refuses is an authentication error instead of a network one that promises a retry which can never succeed
|
2026-08-27 22:56:54 +00:00 |
|
Matthew Meszaros
|
a75ea012a0
|
feat: import a mailbox's recent history on connect and govern sync by fair use: a backfill on every provider (newest first, inside an operator-editable window and cap, resumable through a durable per-provider cursor relayed as SYNC_STATE), a per-mailbox sync governor with priority, live and backfill lanes on shared Redis windows that defers over-budget mail with the cursor held instead of dropping it and only deactivates a mailbox for a flood or chronic daily overage, sync.* budgets on the admin instance settings shipped inside ADD_EMAIL, saved IMAP folder cursors and last_synced_at finally written, a Sync card in the mailbox drawer fed by GET /emails/:id/sync, and docs
|
2026-08-18 09:09:52 -07:00 |
|
Matthew Meszaros
|
16b672e6f6
|
feat: wire OnTokenRefresh on the Gmail worker client so every send and sync stops panicking, since goog.Client was constructed with all four message and label callbacks but no token callback while goog.Init unconditionally wrapped the token source in stoken, whose Token() calls that callback on every single request from inside the oauth2 transport's RoundTrip, making the nil func value a guaranteed nil-pointer dereference on the first Gmail API call any mailbox made (the Outlook path immediately below it set the same field correctly, so no Microsoft mailbox was affected), additionally guarding both goog.Init and msgraph.Init so the stoken wrapper is only installed when there is somewhere to persist a refreshed token to, hardening stoken.Token itself against a nil callback because it runs inside RoundTrip where a panic takes down the caller's request rather than surfacing as an error, and adding a regression test that panics without the guard and passes with it (#118)
|
2026-08-16 07:46:00 +02:00 |
|
Matthew Meszaros
|
955ad1fc0c
|
feat: add the internal/client/msgraph Graph mail client (RAW MIME sendMail, delta sync of inbox/junk, warmup move/mark/flag actions, RFC-message-id resolution, throttling-aware error mapping) plus the shared inbound classification-header list
|
2026-07-04 08:07:49 +02:00 |
|