Gmail API

Gmail API

Google's REST API for Gmail. Replaces IMAP for clients that want native access to Gmail-specific concepts: labels, threads, history-based delta sync, snippet, snooze. The standard for serious Gmail integrations.

Why not just use IMAP?

Gmail-over-IMAP is a leaky abstraction:

The REST API exposes the real semantics. mxr uses it for Gmail accounts; falls back to IMAP for everything else.

Core endpoints

Authentication

OAuth2 only. See OAuth for Email. Gmail's required scopes:

Permissions are coarse — there's no "read only this label" scope.

Current mxr uses gmail.readonly, gmail.modify, and gmail.labels. It relies on gmail.modify for Gmail API send calls rather than requesting gmail.send separately.

Delta sync via historyId

Each Gmail account has a monotonic historyId. Every change (new message, label edit, deletion) bumps it. The client stores the last seen historyId, then queries history.list?startHistoryId=N to get everything that happened since.

Output: a list of historyRecord entries, each describing message additions, deletions, label additions, label deletions. The client applies these deltas to its local store.

The catch: historyIds expire. Google keeps history for ~7 days (sometimes longer). If your client has been offline longer, the history endpoint returns 404, and you must reset to a full sync.

Mxr handles this in crates/sync/engine.rs: catches NotFound on Gmail cursor, resets to SyncCursor::Initial, retries.

Labels vs folders

Gmail's label model:

mxr's internal model captures this with LabelKind: System | Folder | User plus provider_id for the original Gmail label ID.

Watch / Pub-Sub for push notifications

Polling Gmail for changes is wasteful. Two push mechanisms:

Mxr doesn't use these — it's local-only and a Pub/Sub setup would defeat that. mxr polls on an interval (configurable, default 60s).

What mxr does

Per crates/provider-gmail/src/:

Common pitfalls

Comparable APIs

See also