Gmail PubSub
Gmail Pub/Sub -> OpenClaw
Section titled “Gmail Pub/Sub -> OpenClaw”Goal: Gmail watch -> Pub/Sub push -> gog gmail watch serve -> OpenClaw webhook.
Prereqs
Section titled “Prereqs”gcloudinstalled and logged in (install guide).gog(gogcli) installed and authorized for the Gmail account (gogcli.sh).- OpenClaw hooks enabled (see Webhooks).
tailscalelogged in (tailscale.com). Supported setup uses Tailscale Funnel for the public HTTPS endpoint. Other tunnel services can work, but are DIY/unsupported and require manual wiring. Right now, Tailscale is what we support.
Example hook config (enable Gmail preset mapping):
{ hooks: { enabled: true, token: "OPENCLAW_HOOK_TOKEN", path: "/hooks", presets: ["gmail"], },}To deliver the Gmail summary to a chat surface, override the preset with a mapping that sets deliver + optional channel/to:
{ hooks: { enabled: true, token: "OPENCLAW_HOOK_TOKEN", presets: ["gmail"], mappings: [ { match: { path: "gmail" }, action: "agent", wakeMode: "now", name: "Gmail", sessionKey: "hook:gmail:{{messages[0].id}}", messageTemplate: "New email from {{messages[0].from}}\nSubject: {{messages[0].subject}}\n{{messages[0].snippet}}\n{{messages[0].body}}", model: "openai/gpt-5.2-mini", deliver: true, channel: "last", // to: "+15551234567" }, ], },}If you want a fixed channel, set channel + to. Otherwise channel: "last" uses the last delivery route (falls back to WhatsApp).
To force a cheaper model for Gmail runs, set model in the mapping (provider/model or alias). If you enforce agents.defaults.models, include it there.
To set a default model and thinking level specifically for Gmail hooks, add hooks.gmail.model / hooks.gmail.thinking in your config:
{ hooks: { gmail: { model: "openrouter/meta-llama/llama-3.3-70b-instruct:free", thinking: "off", }, },}Notes:
- Per-hook
model/thinkingin the mapping still overrides these defaults. - Fallback order:
hooks.gmail.model→agents.defaults.model.fallbacks→ primary (auth/rate-limit/timeouts). - If
agents.defaults.modelsis set, the Gmail model must be in the allowlist. - Gmail hook content is wrapped with external-content safety boundaries by default. To disable (dangerous), set
hooks.gmail.allowUnsafeExternalContent: true.
To customize payload handling further, add hooks.mappings or a JS/TS transform module under hooks.transformsDir (see Webhooks).
Wizard (recommended)
Section titled “Wizard (recommended)”Use the OpenClaw helper to wire everything together (installs deps on macOS via brew):
openclaw webhooks gmail setup \ --account openclaw@gmail.comDefaults:
- Uses Tailscale Funnel for the public push endpoint.
- Writes
hooks.gmailconfig foropenclaw webhooks gmail run. - Enables the Gmail hook preset (
hooks.presets: ["gmail"]).
Path note: when tailscale.mode is enabled, OpenClaw automatically sets hooks.gmail.serve.path to / and keeps the public path at hooks.gmail.tailscale.path (default /gmail-pubsub) because Tailscale strips the set-path prefix before proxying. If you need the backend to receive the prefixed path, set hooks.gmail.tailscale.target (or --tailscale-target) to a full URL like http://127.0.0.1:8788/gmail-pubsub and match hooks.gmail.serve.path.
Want a custom endpoint? Use --push-endpoint <url> or --tailscale off.
Platform note: on macOS the wizard installs gcloud, gogcli, and tailscale via Homebrew; on Linux install them manually first.
Gateway auto-start (recommended):
- When
hooks.enabled=trueandhooks.gmail.accountis set, the Gateway startsgog gmail watch serveon boot and auto-renews the watch. - Set
OPENCLAW_SKIP_GMAIL_WATCHER=1to opt out (useful if you run the daemon yourself). - Do not run the manual daemon at the same time, or you will hit
listen tcp 127.0.0.1:8788: bind: address already in use.
Manual daemon (starts gog gmail watch serve + auto-renew):
openclaw webhooks gmail runOne-time setup
Section titled “One-time setup”- Select the GCP project that owns the OAuth client used by
gog.
gcloud auth logingcloud config set project <project-id>Note: Gmail watch requires the Pub/Sub topic to live in the same project as the OAuth client.
- Enable APIs:
gcloud services enable gmail.googleapis.com pubsub.googleapis.com- Create a topic:
gcloud pubsub topics create gog-gmail-watch- Allow Gmail push to publish:
gcloud pubsub topics add-iam-policy-binding gog-gmail-watch \ --member=serviceAccount:gmail-api-push@system.gserviceaccount.com \ --role=roles/pubsub.publisherStart the watch
Section titled “Start the watch”gog gmail watch start \ --account openclaw@gmail.com \ --label INBOX \ --topic projects/<project-id>/topics/gog-gmail-watchSave the history_id from the output (for debugging).
Run the push handler
Section titled “Run the push handler”Local example (shared token auth):
gog gmail watch serve \ --account openclaw@gmail.com \ --bind 127.0.0.1 \ --port 8788 \ --path /gmail-pubsub \ --token <shared> \ --hook-url http://127.0.0.1:18789/hooks/gmail \ --hook-token OPENCLAW_HOOK_TOKEN \ --include-body \ --max-bytes 20000Notes:
--tokenprotects the push endpoint (x-gog-tokenor?token=).--hook-urlpoints to OpenClaw/hooks/gmail(mapped; isolated run + summary to main).--include-bodyand--max-bytescontrol the body snippet sent to OpenClaw.
Recommended: openclaw webhooks gmail run wraps the same flow and auto-renews the watch.
Expose the handler (advanced, unsupported)
Section titled “Expose the handler (advanced, unsupported)”If you need a non-Tailscale tunnel, wire it manually and use the public URL in the push subscription (unsupported, no guardrails):
cloudflared tunnel --url http://127.0.0.1:8788 --no-autoupdateUse the generated URL as the push endpoint:
gcloud pubsub subscriptions create gog-gmail-watch-push \ --topic gog-gmail-watch \ --push-endpoint "https://<public-url>/gmail-pubsub?token=<shared>"Production: use a stable HTTPS endpoint and configure Pub/Sub OIDC JWT, then run:
gog gmail watch serve --verify-oidc --oidc-email <svc@...>Send a message to the watched inbox:
gog gmail send \ --account openclaw@gmail.com \ --to openclaw@gmail.com \ --subject "watch test" \ --body "ping"Check watch state and history:
gog gmail watch status --account openclaw@gmail.comgog gmail history --account openclaw@gmail.com --since <historyId>Troubleshooting
Section titled “Troubleshooting”Invalid topicName: project mismatch (topic not in the OAuth client project).User not authorized: missingroles/pubsub.publisheron the topic.- Empty messages: Gmail push only provides
historyId; fetch viagog gmail history.
Cleanup
Section titled “Cleanup”gog gmail watch stop --account openclaw@gmail.comgcloud pubsub subscriptions delete gog-gmail-watch-pushgcloud pubsub topics delete gog-gmail-watch