Learn · Setup guides
How to Connect Gmail API to AI Agents with Outloop
Last updated:
In short
Gmail uses OAuth, not an API key — and Outloop keeps the whole OAuth credential away from the agent.
You enable the Gmail API, add the Gmail scopes, create one Google Cloud OAuth client, and exchange it for a refresh token in the OAuth Playground. Outloop stores the OAuth parts locally in macOS Keychain, and agents read mailbox data, organize messages, create drafts, and send email only through the secure API Bridge — without ever seeing the client secret, refresh token, or access token.
What this setup gives you
You will enable the Gmail API in Google Cloud, add the Gmail OAuth scopes, create an OAuth client for the OAuth Playground, generate a refresh token, and store the credential in Outloop. After that, AI agents can run the full mailbox workflow — read mailbox data, organize messages, create drafts, and send email — when you grant the matching Gmail scopes. Outloop stores the OAuth parts locally and lets agents access Gmail only through the secure API Bridge; the raw credential never appears to the agent, in chat, logs, repos, or project files.
client_secret, refresh_token,
access_token, authorization code, or Authorization header. Their only
destination is the Outloop Mac app — never Outloop Cloud, the website, chat, docs, or
.env files. Every screenshot in this guide has the credential fields redacted.
What you need before starting
- ✓Access to a Google Cloud project with the OAuth consent screen configured.
- ✓A Client ID and Client Secret for your first Google connector. After that, Outloop reuses the saved Google OAuth app and never asks for the secret again.
- ✓The Google account / mailbox you want agents to work with — you will sign in as it in your browser.
- ✓Outloop installed and activated, with a workspace selected.
Which Google account connects what
Three separate identities — keep them apart
Most failed Gmail setups are one confusion: assuming the Google account that manages the Cloud project is also the account that can open the mailbox agents will work in. It does not have to be, and often should not be.
- 1
The Google Cloud project and OAuth app
This owns the Client ID and Client Secret. It can belong to your agency or to your client — Outloop does not care which, and cannot tell the difference.
cloud-admin@agency.example— manages the Google Cloud project - 2
The connected Google account
This is the account you pick in Google's own chooser during the browser sign-in. It is the account that must actually own or be able to open the mailbox agents will work in.
data-owner@client.example— is chosen at sign-in because it owns the mailbox agents will work in - 3
Outloop workspace access
This decides which workspace may use the stored credential, which resources it may reach, and which capabilities agents get. It is set in the Access Profile, after the sign-in succeeds.
In that example, cloud-admin@agency.example
created the OAuth app once, and every connector after it reuses that app — but the account you
actually sign in as is data-owner@client.example,
because that is the identity Gmail will check when an agent asks for a file.
- →If the app's audience is External and it is still in Testing, the account must be added as a Test user first.
- →If the audience is Internal, only accounts inside that Google Workspace organisation can sign in at all.
- →The Gmail API must be enabled in the Google Cloud project the app belongs to.
- →The account must genuinely have access to the mailbox agents will work in. A successful sign-in proves identity, not reach.
1. Enable the Gmail API
In Google Cloud Console, open APIs & Services → Library, search
Gmail API, and click Enable.
The product page confirms with a green API Enabled badge (service
name gmail.googleapis.com). The scope panel in
the next step only lists scopes for APIs that are already enabled, so do this first.
2. Add the Gmail OAuth scopes
In Google Auth Platform → Data access, click Add or remove scopes.
Tick the four Gmail scopes in the table (or paste any missing ones into Manually add scopes), click Add to table, then Update:
https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.modify https://www.googleapis.com/auth/gmail.compose https://www.googleapis.com/auth/gmail.send
gmail.readonly — read messages and
settings; gmail.modify — organize (labels,
archive); gmail.compose — manage drafts;
gmail.send — send mail. Google classes
readonly, modify, and compose as restricted scopes and send as a sensitive scope — expect
the unverified-app warning during authorization until the consent screen is verified. If your agents only
need part of the workflow, authorize the narrower subset.
3. Create the OAuth client
In Google Auth Platform → Clients, create a new OAuth client. Choose Application type: Web application, name it Outloop OAuth Playground - Gmail, and under Authorised redirect URIs add the OAuth Playground URL:
https://developers.google.com/oauthplayground
Click Create. The confirmation dialog shows the Client ID and Client secret — copy both now; the secret is not shown again after you close the dialog.
You only enter the Google OAuth app once
The first Google connector you set up asks for the Client ID and Client Secret from your Google Cloud OAuth client. Tick save as my default Google OAuth app and every later Google connector — Drive, Sheets, Docs, Slides and Google Ads — picks it from the Google OAuth app dropdown with no Client Secret to re-enter. When a saved profile supplies the app, Outloop shows “Using <client-id> — no Client Secret needed. This connector still signs in separately and gets its own access.”
Reusing the app does not mean sharing one login. Each connector still opens its own browser sign-in and gets its own refresh token, its own scopes and its own connected account — so you can revoke or re-authenticate one connector without touching the others.
Shared agency app or workspace-dedicated?
Which setup should I choose?
There are two reasonable answers for Gmail, and the right one depends on who owns the Google Cloud infrastructure — not on how many clients you have.
Agency-global (shared OAuth app)
One OAuth app your agency owns, reused by every Google connector you add. This is the default and the right choice for most agencies.
- ✓Client ID and Client Secret entered once, then picked from a dropdown.
- ✓Every connector still runs its own Google sign-in.
- ✓Each one gets its own scopes, its own refresh token, its own connected account and its own revocation.
- ✓Reusing the app grants no data access by itself — workspace grants and Access Profiles stay explicit.
Workspace-dedicated
A separate OAuth client — or a separate Google Cloud project — for one workspace or one client.
- →The client owns the Google Cloud infrastructure and wants to keep owning it.
- →They need stronger administrative separation, or their own consent branding and audience rules.
- →They want separate quotas and their own lifecycle control.
- →The mailbox belongs to the client's own Google Workspace and their admin wants an Internal-audience app inside their organisation.
A separate Google Cloud project is the strongest operational separation. A separate OAuth client inside the same project is lighter separation — useful, but the project is still shared.
4. Add Gmail in Outloop
In Outloop, open API Keys & Access → Add Access, search gmail, and choose Gmail under Google Workspace Pack (it is an OAuth service, not a paste-one-key service). Pick the workspace scope — shared / global works well when several workspaces will use the same mailbox credential.
The panel opens on Connect in your browser. Two collapsed disclosures sit under it — Setup details — Google Cloud OAuth client, scopes and caveats (the Cloud Console detail from steps 1–3) and Before you connect with a prerequisite count. Open them if you want the background; you do not need them to continue.
Under Access to request from Google, pick the level agents should have. The full option is preselected and its label ends in (recommended); a read-only option is offered but never preselected. Then check the Google OAuth app dropdown — if you have already saved a Google OAuth app profile, this connector uses it and asks for no Client Secret.
5. Connect the account in your browser
Click Connect Gmail in your browser. Your browser opens Google's own sign-in, you sign in as the mailbox you want agents to work with, and you approve the consent screen there — on Google's page, not in Outloop. Outloop then mints and stores the refresh token host-side.
.env file. If you would rather manage
the token yourself, the Advanced — manual refresh token
route below is still fully supported.
6. Confirm the account and capabilities
Back in Outloop, a confirmation card shows Connected as the Google account you just signed in with. Check it — this is the moment to catch a sign-in to the wrong mailbox, before any agent uses it.
Under Agents will be able to (change any time in the Access profile) you get capability checkboxes. Practical ones are pre-checked. Destructive ones are prefixed with ⚠ and are unchecked — leave them that way unless you specifically intend agents to perform them. Then click Confirm — this is the approved account.
7. Save the Access Profile
OAuth is not the finish line — the Access Profile is
When Gmail hands you back to Outloop, the connector is authenticated but not yet authorized. Agents cannot use it until you make the authorization decision yourself:
- OAuth connected
- Confirm the account
- Open the Access Profile
- Review what agents may do
- Choose capabilities
- Save the Access Profile
- Copy the proof prompt
Gmail has no list of resource IDs to approve — the reach is the account you connected. So the decision here is capabilities: what agents may actually do inside that account, with anything destructive left off unless you turn it on.
Gmail is pinned to the connected mailbox itself rather than to a list of file IDs, so the decision here is which capabilities the workspace gets — read, organize, draft, send — not which resources it can see. Choose the narrowest tier the work actually needs, then click Save Access Profile.
8. macOS Keychain: click Always Allow
When macOS asks for Keychain access, click Always Allow. If you click Deny or only Allow once, agents may not be able to use the credential reliably at runtime — the prompt reappears on every read and a dismissed prompt fails the request even though the credential is stored correctly.
9. Runtime proof
In a real runtime proof, Outloop successfully called Gmail through the secure API Bridge — a safe read of the mailbox profile, run by an agent that never saw the credential:
service: gmail decision / code: allow / OK HTTP status: 200 secret_exposed: false runtime-verified: yes
The setup is complete when the proof shows runtime-verified: yes
and secret_exposed: false. Your agent can now use
Gmail through Outloop; the OAuth credential stays in macOS Keychain.
Advanced — manual refresh token
You do not need this if the browser connect worked. It is here because it is still supported, and because some teams prefer to mint the refresh token themselves — for example when the connecting machine cannot open a browser session as the target account, or when you want the token generated under a process you control. In the Outloop panel this lives behind the collapsed Advanced — manual refresh token disclosure.
Get a refresh token from the OAuth Playground
Open developers.google.com/oauthplayground and click the gear icon:
- →Check Use your own OAuth credentials.
- →Set Access type: Offline and Force prompt: Consent Screen.
- →Paste the OAuth Client ID and Client Secret from step 3 (do not screenshot the pasted values).
- →In Step 1, paste the four Gmail scopes into Input your own scopes and click Authorize APIs.
- →Sign in with the Gmail account you want agents to work with and approve the consent screen.
The Playground returns to Step 2 with an authorization code. Click
Exchange authorization code for tokens and copy the
refresh_token — its only destination is the
Outloop Mac app. The access token you can ignore; Outloop mints its own.
Paste the values into Outloop
Open Advanced — manual refresh token in the Gmail panel and fill in:
- →Client ID and Client Secret from Google Cloud (step 3) — or leave them to a saved Google OAuth app profile.
- →Refresh Token from the OAuth Playground.
- →OAuth scope tier — select Full mailbox workflow — read, drafts, organize + send mail to match the four scopes you authorized. The tier you pick is what agents can do through Outloop.
Then click Save pasted refresh token.
Changing the account or the credential later
Changing the account or the credential later
Three controls on the Gmail connector look similar and do different things. Picking the wrong one is the most common way a working connector gets broken on purpose.
Re-authenticate
Reuses the OAuth app you already selected and refreshes the authorization for the account that is already connected.
When: Use it when the refresh token expired or was revoked and you want the same account back.
Safety: It must not quietly become an account switch. If Outloop finds a different account at the other end, it reports the mismatch and keeps the previous token.
Connect as a different Google account
Keeps the same Client ID and Client Secret and opens Google's account chooser so you can pick another identity.
When: Use it when the wrong account was connected, or when the client moved the data to a different Google account.
Safety: The stored token is replaced only after Outloop positively verifies that the newly connected identity is the one you intended. A mismatch, a missing identity, a failed verification or a cancelled sign-in all leave the previous credential exactly as it was.
Replace the full credential
Swaps the OAuth app itself — a different Google Cloud project, Client ID or Client Secret.
When: Use it when the OAuth app is changing hands, or a client is moving the connector onto their own Cloud project.
Safety: This is not the same as choosing another Google data account. Confirm with "Sign in and replace" only when you actually mean to change the app.
What the agent never sees
- ✓Agents never see the OAuth Client Secret, refresh token, access token, or Authorization headers.
- ✓Outloop mints short-lived access tokens host-side and injects the headers itself — the credential is used on the wire, never handed to the agent.
- ✓Every runtime request is audited, and results are redacted.
- ✓Hard deletes and mailbox settings / admin changes (forwarding, filters, delegates) stay blocked by runtime policy.
- ✓Gmail send is allowed only when both the OAuth scope you authorized and Outloop policy allow it.
What the Gmail API can do through Outloop
Reads
- ✓Mailbox profile and metadata, message and thread listing and search (
users.messages,users.threads), label listing.
Writes (gated by scope + policy)
- ✓Create and update drafts (
users.drafts) undergmail.compose. - ✓Organize: add/remove labels, archive, mark read/unread (
users.messages.modify) undergmail.modify. - ✓Send mail (
users.messages.send) undergmail.send.
Blocked by Outloop runtime policy
- ✕Hard deletes (Google's own
gmail.modifyscope also cannot permanently delete past the trash). - ✕Mailbox settings and admin changes — forwarding, filters, delegates.
Verified vs not claimed yet
- Verified Gmail read access through Outloop: a safe mailbox-profile read returned decision allow / OK, HTTP 200,
secret_exposed: false,runtime-verified: yes, with an audit entry. - Supported, not verified yet Drafts, organize, and send: supported by the API and permitted through bridge policy under the authorized scopes, but not runtime-verified in this guide. The safest first write to test is creating a draft — it changes nothing in anyone's inbox.
- Not claimed Hard deletes and mailbox settings / admin changes are blocked by runtime policy — this guide makes no claim that agents can perform them through Outloop.
Gmail API through Outloop vs the Gmail MCP
Google offers a remote Gmail MCP server (currently part of the Google Workspace Developer Preview Program) with tools for drafts, thread search, and labels. MCP can be a useful path; the comparison below is specific to Gmail and to what is actually live in this workspace.
| Area | Gmail API through Outloop | Gmail MCP |
|---|---|---|
| Live in this workspace | Live now The API path is the only Gmail path connected here. | Not connected here Google offers a remote Gmail MCP server (Google Workspace Developer Preview), but it is not connected in this workspace. |
| Verified in this guide | Verified in this guide Proven with a real Gmail read proof through Outloop (allow / OK, HTTP 200, secret_exposed: false, runtime-verified: yes). | Not verified here |
| Auth model | OAuth client + refresh token stored in macOS Keychain; Outloop mints short-lived access tokens host-side. | OAuth 2.0 session between the AI application and Google (gmail.readonly + gmail.compose); token handling depends on the client. |
| Raw secret exposure to the agent | Secret-safe The credential is used on the wire; the agent never sees the client secret, refresh token, access token, or Authorization header. | Depends on the connector/OAuth session model. |
| Audit trail | Audited Every API Bridge request is auditable through Outloop, with redacted results. | Not through Outloop. |
| Workspace / client routing | Workspace-scoped The credential is granted per workspace; wrong-client access is blocked by policy. | Not through Outloop. |
| Read actions | Full Gmail API v1 reads under the authorized scope: messages, threads, labels, mailbox profile and metadata. | search_threads, get_thread, list_drafts, list_labels. |
| Write actions | Drafts, label/organize operations, and send — each gated by the authorized scope and Outloop runtime policy. Hard deletes and mailbox settings changes stay blocked. | create_draft, label/unlabel operations, create_label. The documented toolset has no send tool. |
Troubleshooting
Google shows an account chooser
Expected. Outloop asks Google for the chooser on purpose, so a sign-in can never silently reuse whichever account your browser happened to be logged into. Pick the account that owns or can open the mailbox agents will work in — which is often not the account that manages the Google Cloud project.
“Google hasn’t verified this app”
This appears because the OAuth app is your own and has not been through Google's verification. If it is your app and you trust it, expand Advanced and continue. If you do not know who owns the app, stop — that warning is doing its job, and clicking past an unknown app is not a routine step.
Which audience the app uses decides who can get that far at all. An External app in Testing only admits accounts added as Test users. An Internal app only admits accounts inside its Google Workspace organisation. For customer-facing production use, complete Google's verification rather than living in Testing.
The wrong Google account got connected
Use Connect as a different Google account on the connector. It keeps the same Client ID and Client Secret and reopens Google's chooser. The stored token is only replaced once Outloop verifies the new identity is the intended one — if it does not match, Outloop reports the mismatch and keeps the previous credential. Nothing is lost by trying.
A credential that works but sits on the wrong account is deliberately not marked runtime-verified for that workspace. Working and correct are different things.
BACKEND_AUTH_FAILED during connect
Google rejected the sign-in, so the new credential failed Outloop's safe verification. The important part: the previous credential is unchanged. Do not delete the connector, the OAuth app or the workspace as a first move. Check, in this order — that you signed in as the account that can reach the mailbox agents will work in; that the account is admitted by the app's audience (a Test user on an External+Testing app); and that the API is enabled in the right Cloud project. Then try the connect again.
Reconnecting never asked for the Client ID and Secret
Expected. Disconnecting a Gmail credential does not delete your saved Google OAuth app profile — that is a separate object, kept on purpose so later connectors do not re-enter a Client Secret. Outloop reused it. If you specifically want a different app, pick another saved profile from the Google OAuth app dropdown, or create a new one and save it alongside. This is reuse working, not a stale credential silently retained.
“Copy workspace run prompt” is not available
The Access Profile has not been saved yet. Open the Access Profile, choose the reach and the capabilities, and click Save Access Profile — the run prompt becomes available once the authorization is recorded. OAuth succeeding is not the same as the workspace being authorized, and this is the step that closes the gap.
The connection stops working after about a week
If the OAuth app's audience is External and its publishing status is still Testing, Google expires refresh tokens for that app after roughly seven days. Two honest options: publish the app to In production, or use an Internal audience if everyone signing in is inside your Google Workspace organisation. Publishing may require Google's verification review depending on the scopes the app requests — that is Google's process and its outcome and timing are not ours to promise.
I do not see a refresh token in the Playground
Confirm Use your own OAuth credentials is checked, Access type is Offline, Force prompt is Consent Screen, and the redirect URI in Google Cloud is exactly https://developers.google.com/oauthplayground. Then authorize again.
The proof returns 403
Usually the authorized scopes do not cover the request — for example a send attempt when only gmail.readonly was granted, or a scope tier picked in Outloop that is wider than what the OAuth app actually requested. Check the tier on the connector, then use Re-authenticate to request the scopes you need. A 403 on Gmail is about scope, not about file sharing — unlike Docs, Sheets and Slides, where it usually means the connected identity cannot open one specific file.
Runtime access fails even though the key is stored
Check the macOS Keychain prompt was answered with Always Allow (step 8) and that Runtime access is turned on for the Gmail key row in Outloop.
Rotate or revoke access
- →Narrow what agents can do — reduce the capability tier in the Access Profile and save. Send and draft can be withdrawn without touching the credential.
- →Rotate the token — use Re-authenticate on the connector. Same mailbox, fresh authorization.
- →Revoke everything for this connector — remove the Gmail credential in Outloop, then revoke Outloop's access for that account at myaccount.google.com/permissions. Do both: removing the local credential does not revoke the grant at Google.
- →Rotate the Client Secret — create a new secret on the OAuth client in Google Cloud, then use Sign in and replace on every connector using that saved app profile. Mailbox access is unaffected; the app credential changes.
Official Google documentation
- →Gmail API reference — users.messages, drafts, labels and send.
- →Gmail API scopes — which scopes are restricted, which are sensitive, and what each permits.
- →OAuth app verification — what Google requires for restricted scopes, including the security assessment.
- →Using OAuth 2.0 to access Google APIs — refresh-token behaviour, including the Testing-status expiry.
Outloop is available with guided onboarding for agency teams. Outloop is an independent tool and is not affiliated with or endorsed by Google. See the security model, the Google Drive setup guide, or the Google Analytics GA4 setup guide.
Once the proof succeeds, your agents can read, draft, organize, and send Gmail through Outloop — without seeing the OAuth credential.
Outloop is available with guided onboarding for AI agencies, operators, and dev shops.