Skip to main content
Version: Latest

Gmail

Proxy for the Gmail v1 REST API. Gmail is fundamentally user-scoped — every message and thread belongs to a single mailbox — so this connector only supports idp_passthrough. Each request carries the caller's own OAuth grant, and the policy layer adds operator-controlled guards on outbound mail and label manipulation.

Overview

Typical uses:

  • An agent reads the user's unread inbox to summarize their morning.
  • A scheduling bot sends confirmation emails from the user's address.
  • A compliance workflow flags and trashes phishing matches.

Service-account mode (domain-wide delegation impersonating a specific mailbox) is technically possible against Gmail but deliberately not shipped: most operator questions we've heard on agentic Gmail access are about preventing an agent from mass-emailing out of a service mailbox, not enabling it. If your use case does need SA mode, file an issue — the groundwork is already in the schema.

Default policy

The connector ships policy/gmail.rego (package pbac.connectors.identos.google_gmail). It enforces four things:

1. IdP-routing subject obligation

subject_obligations contains obl if {
input.resource.type == "urn:connector:identos:google-gmail"
input.connector.upstream_auth.type == "idp_passthrough"
input.subject.idp_provider != "google"
obl := { "type": "require_authn_at", "idp": "google", ... }
}

Same pattern as google-drive — callers from a non-Google session get a step-up obligation before any Gmail call succeeds.

2. Operator-enforced read-only mode

deny contains msg if {
input.resource.type == "urn:connector:identos:google-gmail"
input.action.method != "GET"
data[...].read_only == true
...
}

A single boolean at data.pbac.operator.connectors["identos.google-gmail"].read_only disables every mutating route: send_message, modify_labels, trash_message, untrash_message, create_draft, create_label, delete_label. Useful during an incident review or when piloting an agent that should observe but not act.

3. Outbound recipient guards

Operators define two lists and the rego evaluates them on every POST:

{
"allowed_recipient_domains": ["acme.com", "partner.example"],
"blocked_recipient_domains": ["competitor.example"]
}

The denylist is checked first — any recipient matching a blocked domain fails the request immediately. The allowlist is only enforced when non-empty; if set, every To/Cc/Bcc address must match. The gateway adapter populates input.resource.recipients by parsing the send / draft payload.

4. Protected labels

{
"protected_label_ids": ["Label_42_LEGAL_HOLD"]
}

Labels listed here can't be added, removed, or deleted. Prevents an agent from silently removing a legal-hold marker by calling modify_labels with removeLabelIds=[Label_42_LEGAL_HOLD]. Delete on the protected label itself is also blocked.

Supplying operator data

curl -X PUT http://localhost:8080/admin/policy/data/pbac/operator/connectors/identos.google-gmail \
-H "X-Admin-API-Key: $PBAC_ADMIN_API_KEY" \
-d '{
"read_only": false,
"allowed_recipient_domains": ["acme.com"],
"blocked_recipient_domains": ["competitor.example"],
"protected_label_ids": ["Label_42_LEGAL_HOLD"]
}'

Scope model

ScopeUsed for
PBAC scopes (internal)gmail:messages:read, gmail:messages:write, gmail:messages:send, gmail:labels:manageRoute authorization — note that send is a dedicated scope separate from write, so you can grant an agent the ability to label/archive mail without also granting it send
Upstream OAuth scopesgmail.readonly, gmail.send, gmail.modify, gmail.labelsThe Google-side grants the user must consent to

See Google Workspace: multi-connector setup for how gmail's upstream scopes compose with drive and calendar on a single Google IdP.

Manifest reference

  • ID: identos.google-gmail
  • Version: 1.0.0
  • Resource type: urn:connector:identos:google-gmail

Supported auth modes

TypeDetails
idp_passthroughrequires IdP google

Setup fields

IDLabelDefaultSecret?Notes
base_urlAPI base URLhttps://gmail.googleapis.comno

Scopes

Scope
gmail:messages:read
gmail:messages:write
gmail:messages:send
gmail:labels:manage

Routes

MethodPatternScopeResource template
GET/gmail/v1/users/me/profilegmail:messages:read
GET/gmail/v1/users/me/messagesgmail:messages:read
GET/gmail/v1/users/me/messages/{message_id}gmail:messages:readgmail://message/{{message_id}}
GET/gmail/v1/users/me/threadsgmail:messages:read
GET/gmail/v1/users/me/threads/{thread_id}gmail:messages:readgmail://thread/{{thread_id}}
POST/gmail/v1/users/me/messages/sendgmail:messages:send
POST/gmail/v1/users/me/messages/{message_id}/modifygmail:messages:writegmail://message/{{message_id}}
POST/gmail/v1/users/me/messages/{message_id}/trashgmail:messages:writegmail://message/{{message_id}}
POST/gmail/v1/users/me/messages/{message_id}/untrashgmail:messages:writegmail://message/{{message_id}}
GET/gmail/v1/users/me/labelsgmail:messages:read
POST/gmail/v1/users/me/labelsgmail:labels:manage
DELETE/gmail/v1/users/me/labels/{label_id}gmail:labels:managegmail://label/{{label_id}}
GET/gmail/v1/users/me/draftsgmail:messages:read
POST/gmail/v1/users/me/draftsgmail:messages:write

MCP tools

NameScopeDescription
get_profilegmail:messages:readGet the authenticated user's Gmail profile (email address, total messages, history ID).
list_messagesgmail:messages:readList messages in the authenticated user's mailbox. Supports Gmail search syntax (e.g. "from:alice newer_than:7d").
get_messagegmail:messages:readGet a single message by ID. Use format=full for headers+body, format=metadata for headers only.
list_threadsgmail:messages:readList conversation threads. Same query syntax as list_messages.
get_threadgmail:messages:readGet a single conversation thread with all its messages.
send_messagegmail:messages:sendSend an email. Supply either a pre-built RFC 822 'raw' payload (base64url) or the structured To/Cc/Bcc/Subject/Body fields and the connector will assemble the MIME message for you.
modify_labelsgmail:messages:writeAdd or remove labels on a message (e.g. mark as read by removing UNREAD, archive by removing INBOX).
trash_messagegmail:messages:writeMove a message to the Trash. Reversible for 30 days via untrash_message.
untrash_messagegmail:messages:writeRestore a trashed message to the inbox.
list_labelsgmail:messages:readList all labels in the authenticated user's mailbox (both system labels and user-created).
create_labelgmail:labels:manageCreate a new user label.
delete_labelgmail:labels:manageDelete a user-created label. System labels (INBOX, SENT, etc.) cannot be deleted.
list_draftsgmail:messages:readList draft messages.
create_draftgmail:messages:writeCreate a draft message (not sent). Same message payload shape as send_message.

Operator data schema

Keys the operator can supply under data.pbac.operator.connectors["identos.google-gmail"].* — consumed by the connector's policy.

KeyTypeDescription
read_onlybooleanGlobal kill-switch for all mutating routes (send, modify, trash, drafts, labels). When true, only read operations are allowed.
allowed_recipient_domainsarrayOutbound email domains the caller is allowed to send to (e.g. 'acme.com'). Empty means no restriction. If set, every To/Cc/Bcc recipient must match.
blocked_recipient_domainsarrayOutbound email domains that must never receive mail (evaluated before allowed_recipient_domains; easier to manage a small denylist than a large allowlist).
protected_label_idsarraySystem/user label IDs that modify_labels and delete_label must not touch. Useful for regulatory holds (LEGAL, LITIGATION_HOLD, etc.).