Gmail
The Gmail skill lets Maestro read your inbox and send paced outreach using your own Gmail account, over the official Gmail API. Authentication uses OAuth — Maestro never sees or stores your password.
What this skill does
| Operation | Purpose | Status |
|---|---|---|
list_inbox | Return recent threads matching a query (sender, label, time window). | Shipped |
read_thread | Fetch the full message contents for one thread — headers, decoded text + html bodies, labels. | Shipped |
send_email | Send a single message immediately. Pass thread_id + in_reply_to_message_id to thread replies correctly. | Shipped |
label_thread | Add or remove Gmail labels on a thread by name (auto-creates missing labels). | Shipped |
queue_paced_send | Queue a batch of messages and pace sends across a time window so you don’t trigger sender-reputation flags. | Planned — pairs with a persistent send queue and scheduler. |
What you’ll set up
Connecting Gmail to Maestro takes about 15 minutes the first time. You’ll:
- Create a Google Cloud project (free, no billing required).
- Enable the Gmail API on that project.
- Configure the OAuth consent screen so Google knows what your app is.
- Create OAuth 2.0 client credentials.
- Paste those credentials into Maestro’s secrets vault.
- Click Connect Gmail in Maestro and authorize the connection.
After that, the connection is persistent. Maestro refreshes access tokens automatically; you re-authorize only if you revoke the connection from your Google account or change scopes.
Prerequisites
- A Google account that owns the inbox you want to connect. For team installs use a workspace email, not a personal one.
- A running Maestro instance you can reach in a browser. (For local development this is
http://localhost:3000. For a self-hosted production install it’s whatever domain you put Maestro on.) - Admin access to that Maestro instance — you need to write to the secrets vault.
Step 1 — Create a Google Cloud project
- Open console.cloud.google.com.
- In the project picker at the top of the page, click New Project.
- Name it something memorable like
maestro-gmail(the name is internal and only you see it). - Leave Organization at No organization unless you have a Google Workspace and want this project under it.
- Click Create.
You don’t need to enable billing. The Gmail API has a free quota that comfortably covers a single design-partner workload.
Step 2 — Enable the Gmail API
- With your new project selected, open the navigation menu (☰) → APIs & Services → Library.
- Search for Gmail API.
- Click the Gmail API result, then Enable.
You only need to do this once per project.
Step 3 — Configure the OAuth consent screen
This is the screen your users (probably just you) will see when authorizing Maestro.
-
APIs & Services → OAuth consent screen.
-
Choose External as the user type. (Internal is only available for Google Workspace organizations.) Click Create.
-
Fill in the required fields:
- App name:
Maestro(or whatever you want shown on the consent screen). - User support email: your email.
- Developer contact information: your email.
- App name:
-
Click Save and continue.
-
Scopes screen: click Add or remove scopes and add the following:
https://www.googleapis.com/auth/gmail.readonly— read messages and threads.https://www.googleapis.com/auth/gmail.send— send messages on your behalf.https://www.googleapis.com/auth/gmail.labels— read and apply labels.https://www.googleapis.com/auth/gmail.modify— required bylabel_threadto attach Maestro labels to threads.
Maestro requests only the scopes the operations you actually use require. Adding the broader
gmail.modifyis the safest path — without it,label_threadwill fail at runtime. -
Save and continue through the Test users screen. Add your own Google account as a test user. While the consent screen is in Testing mode, only listed test users can complete the OAuth flow — that’s fine for self-host.
-
Review and finish.
Publishing status. Leaving the app in Testing is correct for self-host. You only need to Publish the app (which triggers Google’s verification) if you want users outside your Google Workspace to authorize without being added as test users — that’s a v2+ concern.
Step 4 — Create OAuth 2.0 credentials
-
APIs & Services → Credentials.
-
Click Create credentials → OAuth client ID.
-
Application type: Web application.
-
Name:
Maestro(internal, only you see it). -
Authorized redirect URIs: add the callback URL for your Maestro instance.
- Local development:
http://localhost:3001/api/oauth/google/callback - Self-hosted production:
https://your-maestro-domain.com/api/oauth/google/callback
The path
/api/oauth/google/callbackis what Maestro listens on. Only the protocol + host changes between dev and prod. - Local development:
-
Click Create.
-
Google shows you a Client ID and Client secret. Copy both — you’ll paste them into Maestro in the next step. The secret is only shown once; if you lose it, regenerate and update Maestro.
Step 5 — Add the credentials to Maestro
-
Open Maestro and navigate to Secrets.
-
Click + Add secret and create two entries:
Secret name Kind Value google_oauth_client_idstringThe Client ID from step 4. google_oauth_client_secretapi_keyThe Client secret from step 4. -
Save. The values are encrypted with AES-256-GCM before they hit the database; the master key lives in your
.envand never in the DB. See Secrets for the threat model.
Step 6 — Connect your Gmail account
- Navigate to Skills → Gmail in Maestro.
- Click Connect Gmail.
- You’ll be redirected to Google’s consent screen. Sign in with the account that owns the inbox you want to connect.
- Google will warn you that Maestro (the app you just configured) hasn’t been verified by Google. This is expected for an app in Testing mode — click Advanced → Go to Maestro (unsafe). (Google labels every unverified app this way; it’s not a comment on Maestro specifically.)
- Review the requested scopes and click Allow.
- Google redirects you back to Maestro. The Gmail skill detail page now shows Connected as [your email].
Maestro stores the OAuth bundle (access_token, refresh_token, expires_at, granted scopes) as a single secret of kind oauth2 named gmail_oauth. The access token is short-lived (~1 hour); the refresh token doesn’t expire unless you revoke access. Maestro refreshes automatically on 401.
Verifying the connection
Run a list_inbox test from the Skills → Gmail page:
- Click Test next to the
list_inboxoperation. - Leave the query blank and set
max_results: 5. - Click Run. You should see five recent threads with subjects + sender info.
If that works, your Gmail integration is healthy. The Test UI for individual operations lands when the Skills detail page gets its full operation runner (currently a placeholder); for now, attach the Gmail skill to an agent and trigger a run to exercise the operations end-to-end.
You’re done. Cold-leads and reply-triage agents that depend on the Gmail skill will now find it configured.
Troubleshooting
“Access blocked: This app’s request is invalid” Your redirect URI doesn’t match what’s registered in Google Cloud. Confirm Step 4’s redirect URI exactly matches the URL Maestro is reachable on, including protocol and port.
“This app isn’t verified” warning every time That’s the Testing status warning. Click Advanced → Go to Maestro (unsafe). To suppress it, you’d need to publish the app and go through Google’s verification flow — only worth it for cloud SaaS or large team installs.
401 Unauthorized on operations after connecting
The access token expired and refresh failed. Common causes:
- The refresh token was revoked from your Google account permissions.
- The OAuth client secret was rotated in Google Cloud but not updated in Maestro’s secrets.
Reconnect from Skills → Gmail → Reconnect.
insufficient_permission on label_thread
The OAuth flow didn’t request the gmail.modify scope. Re-run Step 3.5 to add the scope, then Reconnect in Maestro to capture the new scope.
Quota exceeded
The free Gmail API quota is generous (1 billion quota units per day, ~250 quota units per send_email). If you hit it, either wait 24 hours or enable billing on your Cloud project. For typical design-partner workloads this is not a concern.
Permissions & data handling
Maestro requests the smallest scope set that supports its operations. Specifically:
| Scope | Why Maestro needs it |
|---|---|
gmail.readonly | Read inbox messages for the reply-triage agent. |
gmail.send | Send outreach drafted by the cold-leads agent. |
gmail.labels | Discover existing labels so label_thread can apply them by name. |
gmail.modify | Apply labels to threads. Does not allow deleting messages. |
Maestro does not request gmail.compose (drafts), gmail.settings.basic, or any account-management scopes. It cannot delete messages, change account settings, or read mail outside your inbox.
OAuth tokens live in the encrypted secrets vault. The master key is in your .env, not the database. See Secrets for the full threat model.
You can revoke Maestro’s access at any time from myaccount.google.com/permissions. Revoking there immediately invalidates Maestro’s tokens; the next operation will fail with a 401 and the skill UI will prompt you to reconnect.
Related
- Skills overview — how the skill system works.
- Secrets — encryption and master-key handling.
- Pipelines — where Gmail-driven activities are written.