io.b3os/gmail 1.0.0 · email, productivity · MIT

Search and read mail, send plain-text messages, create drafts and change labels (read, starred, archived) in a Gmail mailbox with your own Google OAuth token. Reading gives headers, labels and a snippet; full bodies arrive base64-encoded from Gmail, which declarative actions cannot decode, so they are not included. Needs gmail.readonly, gmail.send, gmail.compose or gmail.modify depending on the actions you use.

Every call's result carries upstream_status and timing: validate_ms, inject_ms, render_ms, upstream_ms, map_ms and total_ms. upstream is the service's time; the others are B3OS's own (call actions). The snippets below show no timing values, because a fixture records none.

Connection

google, type oauth2: Google account (Gmail).

An OAuth access token for your Google account from your own Google Cloud OAuth client, with the scopes listed here. Store the refresh_token, client_id and client_secret with it so the vault can refresh the token (access tokens last an hour); B3OS never uses a Google client of its own.

How to get one: developers.google.com.

Scopes the pack's actions use: https://www.googleapis.com/auth/gmail.readonly, https://www.googleapis.com/auth/gmail.send, https://www.googleapis.com/auth/gmail.compose, https://www.googleapis.com/auth/gmail.modify. The manifest names them per connection, not per action.

The credential is sent only to gmail.googleapis.com.

Store the credential once as a vault connection for this pack and key, then name its id in a call's connections. Leave the key out and B3OS uses the project's newest connection for the pack and key without a subject (connections).

Hosts it reaches: gmail.googleapis.com.

Actions

ActionEffectMCP toolTitle
list-messagesreadgmail__list-messagesSearch messages
get-messagereadgmail__get-messageGet message
send-emailwritegmail__send-emailSend email
create-draftwritegmail__create-draftCreate draft
modify-labelswritegmail__modify-labelsChange message labels
list-labelsreadgmail__list-labelsList labels

list-messages

Search messages. Message and thread ids matching a Gmail search (the same syntax as the search box: from:alice is:unread newer_than:7d has:attachment label:work), newest first. Read each with get-message. Page with page_token.

Ref io.b3os/gmail/list-messages@1.0.0 · effect read · connection google · MCP tool gmail__list-messages

bash
curl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/gmail/list-messages@1", "input": { "query": "from:releases@example.com newer_than:7d", "max_results": 2 }, "connections": {"google": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'

Output, labeled fixture: Search messages (documented response shape, example values). From the bundle's fixtures/list-messages.json, not a live call.

json
{ "messages": [ {"id": "18c9a2b3d4e5f6a7", "thread_id": "18c9a2b3d4e5f6a7"}, {"id": "18c99f0e1d2c3b4a", "thread_id": "18c99f0e1d2c3b4a"} ], "next_page_token": "09876543210987654321", "result_size_estimate": 12}

When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:

pack_error.codeService statusRetryableMessage
not_found404nobuilt from the service's response
connection_unauthorized401noGoogle rejected the access token (expired or revoked); refresh or reconnect it.
rate_limited429, 403yesbuilt from the service's response
forbidden403nobuilt from the service's response
invalid_request400nobuilt from the service's response
conflict409nobuilt from the service's response

get-message

Get message. One message's From, To, Cc, Subject, Date and Message-ID headers, labels, a text snippet, size and receive time. The body is not included (see the pack description).

Ref io.b3os/gmail/get-message@1.0.0 · effect read · connection google · MCP tool gmail__get-message

bash
curl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/gmail/get-message@1", "input": {"id": "18c9a2b3d4e5f6a7"}, "connections": {"google": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'

Output, labeled fixture: Get message (documented response shape, example values). From the bundle's fixtures/get-message.json, not a live call.

json
{ "id": "18c9a2b3d4e5f6a7", "thread_id": "18c9a2b3d4e5f6a7", "labels": ["UNREAD", "IMPORTANT", "CATEGORY_PERSONAL", "INBOX"], "snippet": "The release is live; the changelog has the details.", "from": "Releases <releases@example.com>", "to": "mona@acme.example", "cc": null, "subject": "Release v2.4.0", "date": "Mon, 26 Oct 2026 07:56:40 +0000", "message_id": "<CAB3OSexample123@mail.gmail.com>", "internal_date_ms": "1792999000000", "size_estimate": 5012}

When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:

pack_error.codeService statusRetryableMessage
not_found404nobuilt from the service's response
connection_unauthorized401noGoogle rejected the access token (expired or revoked); refresh or reconnect it.
rate_limited429, 403yesbuilt from the service's response
forbidden403nobuilt from the service's response
invalid_request400nobuilt from the service's response
conflict409nobuilt from the service's response

send-email

Send email. Send a plain-text email from the connected mailbox to one or more recipients, with optional Cc and Bcc. Returns the sent message id and thread id. Not idempotent: two calls send two emails.

Ref io.b3os/gmail/send-email@1.0.0 · effect write · connection google · MCP tool gmail__send-email

bash
curl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/gmail/send-email@1", "input": { "to": "ops@example.com", "cc": "mona@acme.example", "subject": "Deploy finished", "text": "v2.4.0 is live.\r\nRollback plan: redeploy v2.3.9." }, "connections": {"google": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'

Output, labeled fixture: Send email (documented response shape, example values). From the bundle's fixtures/send-email.json, not a live call.

json
{ "id": "18c9b0c1d2e3f4a5", "thread_id": "18c9b0c1d2e3f4a5", "labels": ["SENT"]}

When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:

pack_error.codeService statusRetryableMessage
not_found404nobuilt from the service's response
connection_unauthorized401noGoogle rejected the access token (expired or revoked); refresh or reconnect it.
rate_limited429, 403yesbuilt from the service's response
forbidden403nobuilt from the service's response
invalid_request400nobuilt from the service's response
conflict409nobuilt from the service's response

create-draft

Create draft. Save a plain-text email as a draft in the connected mailbox for a person to review and send. Returns the draft id and message id. Not idempotent.

Ref io.b3os/gmail/create-draft@1.0.0 · effect write · connection google · MCP tool gmail__create-draft

bash
curl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/gmail/create-draft@1", "input": { "to": "customer@example.com", "subject": "Your refund", "text": "Hi, your refund was processed today." }, "connections": {"google": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'

Output, labeled fixture: Create draft (documented response shape, example values). From the bundle's fixtures/create-draft.json, not a live call.

json
{ "draft_id": "r-1234567890123456789", "message_id": "18c9b1d2e3f4a5b6", "thread_id": "18c9b1d2e3f4a5b6"}

When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:

pack_error.codeService statusRetryableMessage
not_found404nobuilt from the service's response
connection_unauthorized401noGoogle rejected the access token (expired or revoked); refresh or reconnect it.
rate_limited429, 403yesbuilt from the service's response
forbidden403nobuilt from the service's response
invalid_request400nobuilt from the service's response
conflict409nobuilt from the service's response

modify-labels

Change message labels. Add and remove labels on a message: remove UNREAD to mark it read, remove INBOX to archive it, add STARRED to star it, or add a user label. Returns the labels after the change.

Ref io.b3os/gmail/modify-labels@1.0.0 · effect write · connection google · MCP tool gmail__modify-labels

bash
curl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/gmail/modify-labels@1", "input": {"id": "18c9a2b3d4e5f6a7", "remove": ["UNREAD", "INBOX"]}, "connections": {"google": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'

Output, labeled fixture: Change message labels (documented response shape, example values). From the bundle's fixtures/modify-labels.json, not a live call.

json
{ "id": "18c9a2b3d4e5f6a7", "labels": ["IMPORTANT", "CATEGORY_PERSONAL"]}

When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:

pack_error.codeService statusRetryableMessage
not_found404nobuilt from the service's response
connection_unauthorized401noGoogle rejected the access token (expired or revoked); refresh or reconnect it.
rate_limited429, 403yesbuilt from the service's response
forbidden403nobuilt from the service's response
invalid_request400nobuilt from the service's response
conflict409nobuilt from the service's response

list-labels

List labels. The mailbox's labels: system labels (INBOX, SENT, UNREAD, STARRED, ...) and user labels with their ids, which search and modify-labels use.

Ref io.b3os/gmail/list-labels@1.0.0 · effect read · connection google · MCP tool gmail__list-labels

bash
curl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/gmail/list-labels@1", "input": {}, "connections": {"google": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'

Output, labeled fixture: List labels (documented response shape, example values). From the bundle's fixtures/list-labels.json, not a live call.

json
{ "labels": [ {"id": "INBOX", "name": "INBOX", "type": "system"}, {"id": "UNREAD", "name": "UNREAD", "type": "system"}, {"id": "Label_12", "name": "Customers", "type": "user"} ]}

When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:

pack_error.codeService statusRetryableMessage
not_found404nobuilt from the service's response
connection_unauthorized401noGoogle rejected the access token (expired or revoked); refresh or reconnect it.
rate_limited429, 403yesbuilt from the service's response
forbidden403nobuilt from the service's response
invalid_request400nobuilt from the service's response
conflict409nobuilt from the service's response
Ask a question... ⌘I