Install
openclaw skills install google-workspace-byokGoogle Calendar and Gmail integration using your own GCP project credentials (BYoK — Bring Your Own Key). Direct OAuth2 auth against your own Google Cloud project. Read calendars, events, and emails across multiple Google accounts. Use this skill when users want to check their calendar, read emails, or manage schedules. Supports: listing/reading emails, Gmail search queries, downloading attachments, extracting text from PDF attachments, listing calendars, listing/getting events, checking free/busy status, and managing multiple Google accounts.
openclaw skills install google-workspace-byokDirect Google Calendar and Gmail API access using your own GCP project OAuth2 credentials. Supports multiple Google accounts.
cd {baseDir}/scripts && npm install
This installs googleapis (Google API client) and mupdf (PDF text extraction for email attachments).
⚠️ Important: Apps in "Testing" status have a 7-day token expiry. To get long-lived tokens, publish your app to "Production" in the Audience settings. For personal Gmail accounts (External user type), you can skip Google's verification review — you'll just see an "unverified app" warning during consent. This is fine for personal use.
node {baseDir}/scripts/setup.js --credentials /path/to/downloaded-credentials.json
This copies your credentials to ~/.openclaw/google-workspace-byok/credentials.json.
For each Google account you want to connect:
node {baseDir}/scripts/auth.js --account <label>
The <label> is a friendly name you'll use to reference this account (e.g., "personal", "work", "household").
Auth flow:
http://localhost/... — the page won't load, and that's expectedScopes requested (default — read/write):
calendar — Full read/write access to Google Calendargmail.readonly — Read-only access to GmailPass --readonly to request read-only calendar access instead.
Tokens are stored in ~/.openclaw/google-workspace-byok/tokens/<label>.json.
All scripts are in {baseDir}/scripts/. Run them with node.
# List all calendars
node {baseDir}/scripts/calendar.js --account <label> --action list-calendars
# List upcoming events (default: next 7 days, primary calendar)
node {baseDir}/scripts/calendar.js --account <label> --action events
# List events with options
node {baseDir}/scripts/calendar.js --account <label> --action events --calendar <calendarId> --days <number> --max <number>
# Get a specific event
node {baseDir}/scripts/calendar.js --account <label> --action get-event --calendar <calendarId> --event-id <eventId>
# Check free/busy
node {baseDir}/scripts/calendar.js --account <label> --action freebusy --days <number>
# List recent emails (default: 10)
node {baseDir}/scripts/gmail.js --account <label> --action list
# Search emails
node {baseDir}/scripts/gmail.js --account <label> --action list --query "from:someone@example.com" --max 20
# Read a specific email (includes attachment metadata with IDs)
node {baseDir}/scripts/gmail.js --account <label> --action read --message-id <messageId>
# Download all attachments from an email
node {baseDir}/scripts/gmail.js --account <label> --action attachment --message-id <messageId> --out-dir /tmp/attachments
# Download a specific attachment
node {baseDir}/scripts/gmail.js --account <label> --action attachment --message-id <messageId> --attachment-id <id> --out-dir /tmp
# List labels
node {baseDir}/scripts/gmail.js --account <label> --action labels
Gmail search uses the same query syntax as the Gmail web search box (e.g., is:unread, from:, newer_than:1d, has:attachment).
The skill includes mupdf for extracting text from PDF attachments — useful for newsletters, invoices, school letters, etc. It handles multilingual text (Japanese, Chinese, etc.) well.
# 1. Download the attachment
mkdir -p /tmp/attachments
node {baseDir}/scripts/gmail.js --account <label> --action attachment --message-id <id> --out-dir /tmp/attachments
# 2. Extract text from the PDF
node --input-type=module -e "
import * as mupdf from '{baseDir}/scripts/node_modules/mupdf/dist/mupdf.js';
import fs from 'fs';
const data = fs.readFileSync('/tmp/attachments/filename.pdf');
const doc = mupdf.Document.openDocument(data, 'application/pdf');
for (let i = 0; i < doc.countPages(); i++) {
const page = doc.loadPage(i);
console.log(page.toStructuredText('preserve-whitespace').asText());
}
"
Note:
mupdfis an ESM module — usenode --input-type=modulewithimportsyntax, notrequire().
# List configured accounts
node {baseDir}/scripts/accounts.js --action list
# Check token status
node {baseDir}/scripts/accounts.js --action status --account <label>
~/.openclaw/google-workspace-byok/
├── credentials.json # Your GCP OAuth credentials
└── tokens/
├── personal.json # Token for "personal" account
└── work.json # Token for "work" account
Error 403: access_denied — "has not completed the Google verification process"Your app is in Testing mode and the Google account isn't listed as a test user. Fix: Google Auth Platform → Audience → Test users → Add the email.
Error: invalid_grantThe refresh token expired or was revoked. Re-run node {baseDir}/scripts/auth.js --account <label> to re-authorize.
Apps in "Testing" publishing status issue tokens that expire after 7 days. Publish your app to "Production" for long-lived tokens. For personal Gmail (External user type), you can skip verification and just accept the "unverified app" warning.
Error: redirect_uri_mismatchYour credentials.json doesn't include http://localhost as a redirect URI. Edit your OAuth client in GCP Console → Authorized redirect URIs → add http://localhost.
npm install fails or mupdf won't installmupdf requires a C++ build toolchain on some platforms. If it fails, you can still use all other features — PDF text extraction is the only feature that requires it. Try: npm install --ignore-scripts to skip native compilation, then install mupdf separately if needed.