guide · gmail api

How should a product team implement the Gmail API safely?

Implement the Gmail API as delegated access to a specific Gmail mailbox, not as a generic email-delivery credential. Choose the smallest OAuth scope that supports the feature, protect authorization state and refresh tokens, and keep every mailbox tenant-scoped. Build messages with a mature Internet-message library, record the returned Gmail message ID, and synchronize changes through Pub/Sub plus history records. Treat service-account impersonation as a Workspace administrator decision. Finally, keep API acceptance, receiving-server delivery, and inbox placement as separate outcomes.

Choose the mailbox model before writing code

The Gmail API operates on a user's Gmail mailbox. It is appropriate when a product must read that mailbox, organize its labels and threads, create drafts, send as the authorized user, or synchronize mailbox changes. That authority is materially broader than calling an application email API from a verified product domain. Start by naming the exact mailbox job and the actor who grants access. A user-facing product normally uses OAuth consent for each connected Google account. An internal Google Workspace automation might instead use administrator-approved domain-wide delegation. If the only requirement is sending receipts, verification links, alerts, or other product-triggered messages from a domain the company controls, avoid mailbox access entirely and evaluate a transactional email API. This architecture decision reduces unnecessary access before any security control or consent screen has to compensate for it.

Authorize the narrowest practical scope

Configure an OAuth client for the correct application type, use an exact registered redirect URI, and bind the authorization response to the initiating browser session with an unpredictable state value. Request access in context, when the user turns on the feature that needs it. For a send-only integration, `https://www.googleapis.com/auth/gmail.send` is narrower than scopes that read or modify the mailbox. Google classifies `gmail.send` as sensitive, while scopes such as `gmail.readonly`, `gmail.compose`, and `gmail.modify` are restricted. A public app using sensitive or restricted access can require OAuth verification, and server-side storage or transmission of restricted-scope data can trigger additional security-assessment requirements. Request offline access only when background work is genuinely required. Encrypt refresh tokens, associate each token with one internal tenant and Google subject, never expose it to browser code or logs, and provide a tested disconnect path that deletes local credentials and stops background processing.

Understand service accounts and domain-wide delegation

A service account is an application identity, not a drop-in Gmail inbox. By itself it does not gain access to employees' messages. For Google Workspace user data, a super administrator must explicitly authorize the service account's numeric client ID and an exact list of OAuth scopes through domain-wide delegation. The application then requests delegated credentials for a named user, and each API call acts with that user's permissions within the authorized scopes. Keep the impersonated subject explicit in job data and audit logs so a background worker cannot silently switch mailboxes. Use separate service accounts for materially different workloads, avoid downloadable private keys when the runtime can use managed credentials, and review domain-wide grants on a schedule. Consumer Gmail accounts do not have a Workspace administrator who can grant this organization-wide delegation, so use user OAuth consent for those accounts.

Send messages without losing control or auditability

Gmail accepts a complete Internet email message in the `raw` field, encoded with base64url, through `users.messages.send`; a product can also create and later send a draft. Use a maintained message library to generate the From, To, Cc, Bcc, Subject, Date, Message-ID, text, HTML, and attachment structure instead of joining header lines manually. Validate recipients and content before encoding, reject header injection, and set explicit size limits. Make the product action idempotent before calling Gmail: persist a stable application event key, the intended mailbox subject, and a send-attempt state. After a successful response, store Gmail's returned message ID and thread ID with that event. If the client times out after transmitting the request, reconcile mailbox state before retrying because the message may already have been accepted. A blind retry can produce a duplicate email even when the original response was lost. Use draft creation plus human review when the content or recipients require approval.

Synchronize mailbox changes with history records

For a server-side mailbox integration, a Gmail watch publishes change signals through Google Cloud Pub/Sub. The notification is a prompt to synchronize, not a complete email payload. Persist the watch response's current history ID and expiration, acknowledge notifications quickly, and call `users.history.list` from the last successfully committed history ID to discover message and label changes. Fetch only the messages needed by the feature, then advance the checkpoint after local writes succeed. Notifications can be delayed or duplicated, so make message and history processing idempotent. Gmail requires a mailbox watch to be renewed at least every seven days and recommends daily renewal; schedule renewal well before expiration and alert on failures. If a stored history ID is outside Gmail's available range, the API returns HTTP 404. Treat that as a defined recovery path: perform a controlled full synchronization, establish a new checkpoint, and resume incremental processing rather than retrying the invalid history ID forever.

Use a staged implementation and verification workflow

First, document whether the feature sends, reads, modifies, or watches mail, and map each operation to its minimum OAuth scope. Second, create separate Google Cloud projects or OAuth clients for development and production, with exact redirect URIs and named credential owners. Third, implement authorization with state validation, offline access only when needed, encrypted token storage, token revocation, and tenant-level access checks. Fourth, test with controlled mailboxes: connect, refresh an expired access token, revoke consent, reconnect, send once, simulate an ambiguous timeout, and confirm duplicate prevention. Fifth, if receiving changes, provision Pub/Sub permissions, start a watch, process history incrementally, force a stale-checkpoint recovery, and verify watch renewal. Sixth, add per-user work queues, bounded exponential backoff, structured error classification, and audit logs that omit message bodies and tokens by default. Before launch, complete any required Google verification and security review, publish accurate data-use disclosures, and rehearse credential rotation and user-data deletion.

Plan for quotas, retries, and partial failure

Gmail measures API use in quota units, not only request count. Google's quota page lists 1,200,000 units per minute per project and 6,000 units per minute per user per project. It lists `messages.send`, `drafts.send`, and `watch` at 100 units each, and a 500-recipient limit per message. Gmail's separate user sending limits still apply across API, web, and SMTP clients. Treat the Cloud console and current documentation as runtime configuration inputs rather than hard-coding published limits into business logic. Serialize or fairly queue work per mailbox, cap concurrency, and retry only transient responses with jittered exponential backoff and a finite deadline. Do not retry authorization, policy, invalid-recipient, or malformed-message errors as if they were capacity problems. A multipart batch reduces connection overhead but each inner call still consumes quota and can fail independently.

Keep acceptance, delivery, and inbox placement separate

A successful `messages.send` call means Gmail accepted the authorized API request and returned a Gmail Message resource. It does not prove that every recipient's mail server accepted the message, and it cannot establish where a receiving system classified the message. Recipient-server delivery means the destination system accepted SMTP responsibility. Inbox placement is a later filtering outcome, such as primary inbox, promotions, quarantine, or spam. Gmail's mailbox API is therefore not a substitute for a provider event stream when a product needs delivery, bounce, or complaint telemetry for transactional mail. Preserve the Gmail message ID for reconciliation, but describe the user-visible state precisely as sent or accepted by Gmail unless separate evidence supports delivery. Authentication, expected recipients, content quality, sending behavior, and destination policy all affect downstream handling. An API response cannot determine or promise the recipient's final mailbox folder.

Know when a transactional email API fits a different job

Use Gmail API when the product needs authorized access to a person's or organization's Gmail mailbox, including threads, labels, drafts, or mailbox synchronization. A transactional email API fits a different architecture: application-triggered messages sent from domains the organization controls, without delegated authority to read a user's Gmail mailbox. A product can use both types of systems when the boundaries are explicit, for example Gmail OAuth to read a support agent's connected mailbox and a separately verified transactional provider to send product receipts. Keep credentials, consent, message stores, retry policies, and audit records separate so mailbox authority cannot leak into application-wide sending and a transactional credential cannot read a user's Gmail.

Frequently asked questions

Can a service account access any Gmail mailbox?

No. A service account does not automatically receive Gmail user-data access. A Google Workspace super administrator must grant domain-wide delegation to its numeric client ID and approved scopes, after which the application explicitly impersonates a user in that organization. For consumer Gmail accounts, use user OAuth consent instead.

Which OAuth scope should a send-only Gmail integration request?

Start by evaluating `https://www.googleapis.com/auth/gmail.send`, which permits sending on the user's behalf without granting general mailbox reading. Confirm that no product requirement actually needs drafts, message reads, labels, or modification before requesting a broader scope, and account for Google's sensitive-scope verification rules.

Does a successful Gmail API send mean the message was delivered?

No. It confirms Gmail accepted the authorized API operation and returned a message record. Receiving-server acceptance and inbox placement are separate downstream states. Do not label the message delivered or promise inbox placement unless another trustworthy signal supports that conclusion.

Do Gmail push notifications contain the full new message?

No. A Pub/Sub notification signals that mailbox state changed and includes information used to continue synchronization. The application should query Gmail history from its saved history ID, fetch the required message data, process idempotently, and then advance its checkpoint.

How often must a Gmail mailbox watch be renewed?

Google requires calling `watch` at least once every seven days and recommends daily renewal. Store the returned expiration, renew ahead of it, monitor failures, and keep a fallback synchronization job so a missed renewal does not silently create an unbounded data gap.

When should a team use a transactional email API instead of Gmail API?

Use a transactional email API when the job is application-triggered email from organization-controlled domains and no feature needs access to a person's Gmail mailbox. Use Gmail API when the product specifically needs delegated mailbox messages, threads, labels, drafts, settings, or send-as authority.

Sources