Fix Gmail API bugs, speed up bulk ops, and add sync/archive/rules features#1
Open
chrisdjbaker wants to merge 4 commits into
Open
Fix Gmail API bugs, speed up bulk ops, and add sync/archive/rules features#1chrisdjbaker wants to merge 4 commits into
chrisdjbaker wants to merge 4 commits into
Conversation
Correctness fixes: - Centralize Gmail API calls in gmailApi.ts with bounded exponential backoff. Replaces ad-hoc retry loops that (a) retried 429/403 forever with no cap, (b) passed swapped args on the unsubscribe-header retry, and (c) retried permanent 403s as if transient. - fetchMessageIdsPage no longer crashes when Gmail omits `messages` on a zero-result query. - parseListUnsubscribeHeader strips angle brackets correctly when the value has surrounding whitespace. - fetchProgress is merged per-account instead of clobbering other accounts, and reflects messages actually processed (no float drift). Auto-unsubscribe: - Implement RFC 8058 one-click POST (List-Unsubscribe-Post) as the preferred automatic path; previously dead code. - Recurse the full MIME tree when scraping body unsubscribe links, so nested multipart/alternative bodies are handled. Performance: - Trash via batchModify (up to 1000 ids/request) instead of one request per message. - Fetch sender metadata via Gmail's multipart batch endpoint (100 sub-requests/call) instead of 40 individual GETs. Hardening: - Guard content-script DOM lookups; detect the account email by pattern instead of a fixed title split position. - Remove the placeholder uninstall-survey URL. - Restore a Jest suite (32 tests) covering the above.
Feature: incremental sync - New syncSenders.ts uses Gmail history.list to apply only added/deleted messages since the last refresh, with a full-resync fallback when the history cursor has expired (404). fetchAllSenders now records the history cursor and a message->sender index (senderStore.ts) so syncs can decrement counts/size on deletion. Feature: storage size + archive - Capture each message's sizeEstimate (free, same response) and surface per-sender size in the UI; sort by size. - New Archive action (remove INBOX, no trash) via the shared batchModify path in modifySenders.ts. Feature: drill-down + undo - getSenderPreview shows a sender's recent subjects/snippets in a modal. - Trashing records the affected ids; Undo restores them (remove TRASH, restore INBOX) from the success modal. Feature: saved auto-clean rules - Backed by Gmail server-side filters (create/list/delete) so Gmail applies them automatically; managed from a new Rules modal. blockSender now routes through the same rule machinery. UI: search box, sort (emails/size/name), select-all-visible, and richer confirmations that show storage freed. CI: restore a GitHub Actions workflow running build, tests, and eslint. Storage: add the unlimitedStorage permission for the message index. Tests: 49 passing (store conversions, modify/undo, rules, history delta, size formatting, aggregation).
The login screen previously only displayed instructions and relied on silent token acquisition, so a first-time user could never trigger the OAuth consent grant. Wire the login page to signInWithGoogle (interactive) using the account detected from the active Gmail tab, with busy and error states.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes several bugs in the Gmail API layer, speeds up the bulk
operations, makes auto-unsubscribe land for many more senders, and adds a set
of features (incremental sync, archive, storage-size insights, per-sender
preview, undo, and saved auto-clean rules). The build, test suite, and linter
are all green, and a CI workflow is restored to keep them that way.
A full write-up lives in
CHANGELOG.md.Bug fixes
gmailApi.ts). One transport withexponential backoff and a hard retry cap, replacing ad-hoc retry loops that:
retried 429/403 forever (could hang the UI); passed swapped arguments
on the unsubscribe-header retry; and retried permanent 403s as transient.
fetchMessageIds— Gmail omitsmessageson anempty query, which threw and aborted the trash/unsubscribe flow. Now guarded.
List-Unsubscribeparsing stripped angle brackets using the untrimmedlength, mangling values with surrounding whitespace.
now merged per-account and based on messages actually processed.
detected by pattern rather than a fixed title split position.
Performance
batchModify(up to 1000 ids/request) instead of onerequest per message.
instead of 40 individual GETs.
Auto-unsubscribe
List-Unsubscribe-Post) is now the preferredpath, so more senders unsubscribe with no email and no manual click.
multipart/alternativebodies that were previously missed.New features
history.list, with a full-resync fallback when the cursor expires.the scan), sort-by-size, and an Archive action (remove from Inbox).
last trash batch.
Gmail server-side filters (no background polling).
Testing & compatibility
npm run build,npm test, andnpx eslint srcall pass.gmail.modify,gmail.settings.basic) — no new consent screen. Adds theunlimitedStoragepermission for the incremental-sync message index.
I'm happy to split this into smaller PRs or adjust anything if you'd prefer to
take it in pieces.