Dear Readers,
time to give our agents access to email. But before we wire anything into OpenClaw, we need API credentials — and Google makes it surprisingly easy to give away more access than you intended. This post covers how to set up OAuth credentials with the absolute minimum permissions.
Why Not an App Password?#
App passwords give full account access. No scope restrictions, no token expiration, no audit trail. For an AI agent that should only read your inbox and draft replies, that’s wildly excessive. OAuth lets us define exactly what the agent can and cannot do at the API level.
Google Cloud Console Setup#
Head to console.cloud.google.com and create a new project. I called mine openclaw-email — name doesn’t matter, but keeping it separate from other projects means you can nuke it cleanly if needed.
Enable the Gmail API#
Navigate to APIs & Services > Library, search for “Gmail API”, and enable it. Nothing else. Don’t enable “Google Workspace” or any of the suggested bundles — each enabled API is attack surface you don’t need.
OAuth Consent Screen#
Go to APIs & Services > OAuth consent screen. Choose External user type (unless you have a Workspace org).
Fill in the required fields:
- App name: Something descriptive like “OpenClaw Email Agent”
- User support email: Your email
- Developer contact: Your email again
The important part is the Scopes step. Click “Add or Remove Scopes” and add exactly these two:
https://www.googleapis.com/auth/gmail.readonly
https://www.googleapis.com/auth/gmail.composeThat’s it. gmail.readonly lets the agent read messages and list threads. gmail.compose lets it create drafts. Neither scope allows sending, deleting, or modifying existing messages.
Gotcha: Google will suggest https://mail.google.com/ as a scope — this is the full-access nuclear option. It lets you read, send, delete, and modify anything. Never select this for an agent.
Testing vs Production#
Leave the app in Testing mode for now. Add your Gmail address as a test user.
Gotcha: Testing mode tokens expire after 7 days. You’ll need to re-authorize weekly until you push to production. For a personal agent this is honestly fine — it forces you to periodically confirm the agent still has the access you intended. If it annoys you later, you can submit for verification, but Google’s review process takes days and requires a privacy policy URL.
Create OAuth Credentials#
Go to APIs & Services > Credentials and click Create Credentials > OAuth client ID.
- Application type: Desktop app (not Web application — the token exchange happens locally)
- Name:
openclaw-email-client
Download the JSON file. It’ll be named something like client_secret_123456789.apps.googleusercontent.com.json. Rename it to something sane:
mv ~/Downloads/client_secret_*.json /root/openclaw/gmail-credentials.jsonLock down the permissions:
chmod 600 /root/openclaw/gmail-credentials.jsonThis file contains your client_id and client_secret. It’s not a token — it can’t access your email on its own — but treat it as sensitive anyway.
First Token Exchange#
The Gmail MCP server (which we’ll set up in the next post) handles the OAuth flow automatically on first run. But here’s what happens under the hood:
- You run the MCP server with the credentials file
- It opens a browser for Google’s consent screen
- You log in and approve the scopes
- Google returns an authorization code
- The server exchanges it for an access token + refresh token
- Tokens get saved to a local file (typically
~/.gmail-mcp/tokens.json)
The refresh token is what matters long-term. It lets the server get new access tokens without your interaction. Guard it:
chmod 600 ~/.gmail-mcp/tokens.jsonGotcha: If you’re doing this on a headless server (which we are), the browser redirect won’t work directly. Run the initial auth from a machine with a browser, or use SSH port forwarding to handle the localhost callback. The MCP server docs cover the exact flow.
What We’ve Locked Down#
Let’s take stock of what the agent can and cannot do with these credentials:
| Action | Allowed |
|---|---|
| Read emails | Yes |
| List threads | Yes |
| Search inbox | Yes |
| Create drafts | Yes |
| Send emails | No |
| Delete emails | No |
| Modify labels | No |
| Access other Google services | No |
This is the first layer of defense. Even if every other guardrail fails — the SOUL.md gets ignored, the prompt gets injected, the agent goes rogue — it physically cannot send or delete anything. The OAuth scopes are enforced by Google’s servers, not by our code.
We’ll stack more layers on top in later posts. But this one is the foundation, and it’s the only layer that doesn’t depend on the AI behaving correctly.
Next up: Wiring Gmail into OpenClaw



