Repository navigation
feat: add Gmail push via Cloud Pub/Sub with EventSource state changes - #13
Closed
lucamzanon wants to merge 15 commits into
Closed
lucamzanon wants to merge 15 commits into
lucamzanon wants to merge 15 commits into
Conversation
Behind GMAIL_ALIASES_ENABLED. Reads users.settings.sendAs (covered by the existing gmail.modify grant), offers the primary address plus accepted aliases as read-only identities with stable ids, and lets drafts, MIME imports and submissions use any of them. The identity is re-validated against Gmail right before drafts.send; a removed alias yields forbiddenFrom and keeps the draft. Signatures stay client-side. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Behind GMAIL_SCHEDULE_ENABLED. HOLDFOR/HOLDUNTIL submissions are stored in SQLite instead of being sent; a 5 s worker leases due entries atomically and re-validates identity, draft hash and ledger before drafts.send. Edited/deleted drafts, removed identities and entries that come due while the bridge is down beyond the tolerance are suspended, never sent. undoStatus=canceled cancels pending entries; EmailSubmission/query lists them; interrupted sends are reconciled on restart; /healthz reports per-status counters. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Behind GMAIL_PUSH_TOPIC/GMAIL_PUSH_TOKEN. The bridge issues users.watch for connected accounts and renews it daily; POST /gmail/push validates the shared token in constant time, persists the hint before the 204 ack, coalesces bursts per account and runs the existing incremental engine. With push configured the session advertises eventSourceUrl and /jmap/eventsource streams StateChange events after a sync changed state; streams are re-synced every 5 min as a safety net. /healthz gains push counters. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Author
|
Superseded by #14, which consolidates this stack into one reviewable branch. |
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.
Stacked on #12 (
feat/gmail-delayed-send); only the last commit is new.What
Behind
GMAIL_PUSH_TOPIC+GMAIL_PUSH_TOKEN, the Gmail backend replaces polling with Gmail push via Cloud Pub/Sub and gives Gmail accounts a JMAP EventSource:users.watchis issued for every connected account at startup and re-issued every 24 h (Google expires watches after 7 days); failures are counted in SQLite and retried hourly.watch/stopare the only new entries in the Gmail write allowlist.POST /gmail/push?token=…for a Pub/Sub push subscription: constant-time token check (401 otherwise), the{emailAddress, historyId}hint is persisted before the 204 acknowledgement, garbage/unknown accounts are acknowledged without logging anything, bursts are coalesced per account (1.5 s) into one run of the existing incremental engine. Duplicates and out-of-order deliveries are harmless because the engine always starts from the persisted cursor.eventSourceUrlandGET /jmap/eventsourcestreams RFC 8620StateChangeevents (Email/Thread/Mailbox) reusing the legacy hub's wire format, emitted only when a sync actually changed state. Accounts with open streams are also re-synced every 5 min as a safety net for delayed/lost notifications (Google documents both)./healthzreports watches, expiring-soon, renewal failures, notification counts, rejected/ignored requests, sync failures and open streams. No addresses or message contents in logs or counters.Setup (documented in the README): enable Pub/Sub, create the topic, grant
roles/pubsub.publishertogmail-api-push@system.gserviceaccount.com, create a push subscription tohttps://<PUBLIC_URL>/gmail/push?token=<secret>.Without the variables, behaviour is unchanged (no watch, no endpoint, no
eventSourceUrl).Tests
test/unit/gmail-push.spec.ts(4 tests): token/garbage/unknown handling and persistence before ack; burst coalescing into one history read with a StateChange delivered to open streams only when state moved and not after the stream closed; daily watch renewal with failure counting and hourly retry; session/endpoint gating on configuration.refs.spec.ts,search.spec.ts, same on upstream).🤖 Generated with Claude Code