Integrations

Gmail

Connect Gmail to Project88 — read, search, send, and label emails from any agent.

The Gmail integration connects an authenticated Gmail account to your org via Composio. Once connected, every agent in the org has access to Gmail tools by default (you can scope them per agent on the Tools tab).

Connect

  1. ⌘KSettings → Connections
  2. Search "Gmail" in the catalog (900+ toolkits are surfaced dynamically via the composio-auth Edge Function v6).
  3. Click Connect. An OAuth popup opens and is closed by a static public/oauth-callback.html page that postMessages the result back.
  4. The tokens are stored encrypted in Supabase Vault via the insert_integration RPC. The plaintext token never reaches your browser.

You'll see Gmail in your Connections list with a "Connected" status.

Tools exposed

The integration unlocks Gmail tools dynamically. Common ones include:

ToolWhat it does
GMAIL_FETCH_EMAILSSearch / list emails matching a query
GMAIL_SEND_EMAILSend a new email
GMAIL_REPLY_TO_EMAILReply to a thread
GMAIL_CREATE_LABELCreate a Gmail label
GMAIL_LABEL_THREADApply a label

The proxy applies description overrides to about a dozen of these tools so the LLM picks them up reliably — Composio's stock descriptions are sometimes generic and the LLM ignores them.

Auto-fallback to Outlook

If an agent tries Gmail tools and there's no Gmail connection, the proxy auto-falls-back to the equivalent Outlook tools when an Outlook integration exists. The user-facing experience is "the agent reads your email" without the user having to know which provider is connected.

Inbox mode

Once Gmail is connected, the Inbox mode is populated automatically — three-panel email client with folders, labels, search, attachments, and inline reply.

Real-time inbox: Gmail push notifications

When configured, new messages toast on every app surface (not just Inbox) within a few seconds of landing in Gmail. See Inbox → Real-time inbox for the user-facing behavior. Setup on the platform side is a one-time GCP Pub/Sub + secrets pass:

  1. Create a Pub/Sub topic in the same GCP project that owns the OAuth client, and grant gmail-api-push@system.gserviceaccount.com the Pub/Sub Publisher role on it.
  2. Create a push subscription on the topic pointing at https://<project>.supabase.co/functions/v1/gmail-webhook?token=<shared-secret>. The webhook authenticates on the shared secret (verify_jwt is off, since Google sends no Supabase JWT) — both the URL param and the stored secret are trimmed before comparison, so a paste with a trailing newline doesn't silently 403 every push.
  3. Set the Supabase edge secrets:
    • GMAIL_PUBSUB_TOPIC — the topic's fully-qualified name (projects/<project>/topics/<topic>), used by gmail-watch when it registers a per-integration users.watch.
    • GMAIL_WEBHOOK_SECRET — the same shared secret you baked into the push-subscription URL.

Once both secrets exist, gmail-watch registers a watch per integration on account connect, and a 12-hour pg_cron job renews every registered watch (Gmail watches expire in ≤7 days). Without these secrets everything no-ops gracefully — the Inbox keeps polling as before, no crashes, no console noise.

The end-to-end pipeline: Gmail users.watch → GCP Pub/Sub → gmail-webhook edge function → history.list delta → email_events INSERT → Supabase Realtime → toast + refetch in EmailProvider. A 10-min recency guard prevents backfill after watch re-plug from toast-storming. Migration 149 adds the gmail_watch_state and email_events tables backing it.

Outlook accounts stay on the existing 60 s label-count poll — Microsoft Graph webhooks are a separate effort.

Disconnect

Settings → Connections → Disconnect on the Gmail card. The integration row is soft-deleted; the Vault secret is revoked.

Where to next

On this page