Claw — Google Workspace for AI Agents
name: clawemail
by cto1 · published 2026-03-22
$ claw add gh:cto1/cto1-clawemail---
name: clawemail
description: "Google Workspace via ClawEmail.com service — Gmail, Drive, Docs, Sheets, Slides, Calendar, Forms. Use PROACTIVELY when the user asks to send email, create documents, manage files, schedule events, or work with any Google service."
metadata: {"openclaw":{"emoji":"🦞","requires":{"env":["CLAWEMAIL_CREDENTIALS"]},"primaryEnv":"CLAWEMAIL_CREDENTIALS"}}
---
# Claw — Google Workspace for AI Agents
Use `claw` for Gmail, Drive, Docs, Sheets, Slides, Calendar, and Forms via your @clawemail.com account.
Setup
1. Save your ClawEmail credentials JSON to `~/.config/clawemail/credentials.json`
2. Set the environment variable: `export CLAWEMAIL_CREDENTIALS=~/.config/clawemail/credentials.json`
Get credentials at https://clawemail.com — sign up, then visit `/connect/YOUR_PREFIX` to authorize OAuth.
Getting an Access Token
All API calls need a Bearer token. Use the helper script to refresh and cache it:
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)The script caches tokens for 50 minutes. Always assign to `TOKEN` before making API calls.
---
Gmail
Search emails
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)
curl -s -H "Authorization: Bearer $TOKEN" \
"https://gmail.googleapis.com/gmail/v1/users/me/messages?q=newer_than:7d&maxResults=10" | python3 -m json.toolCommon query operators: `from:`, `to:`, `subject:`, `newer_than:`, `older_than:`, `is:unread`, `has:attachment`, `label:`, `in:inbox`.
Read a message
curl -s -H "Authorization: Bearer $TOKEN" \
"https://gmail.googleapis.com/gmail/v1/users/me/messages/MESSAGE_ID?format=full" | python3 -m json.toolFor plain text body only, use `format=minimal` and decode the payload. For readable output:
curl -s -H "Authorization: Bearer $TOKEN" \
"https://gmail.googleapis.com/gmail/v1/users/me/messages/MESSAGE_ID?format=full" \
| python3 -c "
import json,sys,base64
m=json.load(sys.stdin)
hdrs={h['name']:h['value'] for h in m['payload']['headers']}
print(f\"From: {hdrs.get('From','')}\nTo: {hdrs.get('To','')}\nSubject: {hdrs.get('Subject','')}\nDate: {hdrs.get('Date','')}\n\")
def get_body(part):
if part.get('body',{}).get('data'):
return base64.urlsafe_b64decode(part['body']['data']).decode('utf-8','replace')
for p in part.get('parts',[]):
if p['mimeType']=='text/plain': return get_body(p)
for p in part.get('parts',[]):
b=get_body(p)
if b: return b
return ''
print(get_body(m['payload']))
"Send an email
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)
python3 -c "
import base64,json
raw = base64.urlsafe_b64encode(
b'To: recipient@example.com\r\nSubject: Hello\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nMessage body here'
).decode()
print(json.dumps({'raw': raw}))
" | curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @- \
"https://gmail.googleapis.com/gmail/v1/users/me/messages/send"For HTML emails, replace `Content-Type: text/plain` with `Content-Type: text/html` and use HTML in the body.
Reply to a message
Same as send, but add `In-Reply-To:` and `References:` headers from the original message, and include `threadId` in the JSON body:
python3 -c "
import base64,json
raw = base64.urlsafe_b64encode(
b'To: recipient@example.com\r\nSubject: Re: Original Subject\r\nIn-Reply-To: <original-message-id>\r\nReferences: <original-message-id>\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nReply body'
).decode()
print(json.dumps({'raw': raw, 'threadId': 'THREAD_ID'}))
" | curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @- \
"https://gmail.googleapis.com/gmail/v1/users/me/messages/send"List labels
curl -s -H "Authorization: Bearer $TOKEN" \
"https://gmail.googleapis.com/gmail/v1/users/me/labels" | python3 -m json.toolAdd/remove labels
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"addLabelIds":["LABEL_ID"],"removeLabelIds":["INBOX"]}' \
"https://gmail.googleapis.com/gmail/v1/users/me/messages/MESSAGE_ID/modify"---
Google Drive
List files
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)
curl -s -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/drive/v3/files?pageSize=20&fields=files(id,name,mimeType,modifiedTime,size)&orderBy=modifiedTime desc" | python3 -m json.toolSearch files
curl -s -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/drive/v3/files?q=name+contains+'report'&fields=files(id,name,mimeType,modifiedTime)" | python3 -m json.toolQuery operators: `name contains 'term'`, `mimeType='application/vnd.google-apps.document'`, `'FOLDER_ID' in parents`, `trashed=false`, `modifiedTime > '2025-01-01'`.
Common MIME types:
Create a folder
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"My Folder","mimeType":"application/vnd.google-apps.folder"}' \
"https://www.googleapis.com/drive/v3/files?fields=id,name" | python3 -m json.toolUpload a file
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-F "metadata={\"name\":\"report.pdf\"};type=application/json" \
-F "file=@/path/to/report.pdf;type=application/pdf" \
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id,name" | python3 -m json.toolDownload a file
For Google Docs/Sheets/Slides (export):
curl -s -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/drive/v3/files/FILE_ID/export?mimeType=application/pdf" -o output.pdfExport formats: `text/plain`, `text/html`, `application/pdf`, `application/vnd.openxmlformats-officedocument.wordprocessingml.document` (docx), `text/csv` (sheets).
For binary files (download):
curl -s -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/drive/v3/files/FILE_ID?alt=media" -o output.fileShare a file
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"role":"writer","type":"user","emailAddress":"user@example.com"}' \
"https://www.googleapis.com/drive/v3/files/FILE_ID/permissions"Roles: `reader`, `commenter`, `writer`, `owner`. Types: `user`, `group`, `domain`, `anyone`.
Delete a file
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/drive/v3/files/FILE_ID"---
Google Docs
Create a document
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"My Document"}' \
"https://docs.googleapis.com/v1/documents" | python3 -m json.toolRead a document
curl -s -H "Authorization: Bearer $TOKEN" \
"https://docs.googleapis.com/v1/documents/DOCUMENT_ID" | python3 -m json.toolFor plain text extraction:
curl -s -H "Authorization: Bearer $TOKEN" \
"https://docs.googleapis.com/v1/documents/DOCUMENT_ID" \
| python3 -c "
import json,sys
doc=json.load(sys.stdin)
text=''
for el in doc.get('body',{}).get('content',[]):
for p in el.get('paragraph',{}).get('elements',[]):
text+=p.get('textRun',{}).get('content','')
print(text)
"Append text to a document
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests":[{"insertText":{"location":{"index":1},"text":"Hello, world!\n"}}]}' \
"https://docs.googleapis.com/v1/documents/DOCUMENT_ID:batchUpdate"Replace text in a document
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests":[{"replaceAllText":{"containsText":{"text":"OLD_TEXT","matchCase":true},"replaceText":"NEW_TEXT"}}]}' \
"https://docs.googleapis.com/v1/documents/DOCUMENT_ID:batchUpdate"Insert a heading
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests":[{"insertText":{"location":{"index":1},"text":"My Heading\n"}},{"updateParagraphStyle":{"range":{"startIndex":1,"endIndex":12},"paragraphStyle":{"namedStyleType":"HEADING_1"},"fields":"namedStyleType"}}]}' \
"https://docs.googleapis.com/v1/documents/DOCUMENT_ID:batchUpdate"Heading styles: `HEADING_1` through `HEADING_6`, `TITLE`, `SUBTITLE`, `NORMAL_TEXT`.
---
Google Sheets
Create a spreadsheet
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"properties":{"title":"My Spreadsheet"}}' \
"https://sheets.googleapis.com/v4/spreadsheets" | python3 -m json.toolRead cells
curl -s -H "Authorization: Bearer $TOKEN" \
"https://sheets.googleapis.com/v4/spreadsheets/SPREADSHEET_ID/values/Sheet1!A1:D10" | python3 -m json.toolWrite cells
curl -s -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"values":[["Name","Age","City"],["Alice","30","NYC"],["Bob","25","LA"]]}' \
"https://sheets.googleapis.com/v4/spreadsheets/SPREADSHEET_ID/values/Sheet1!A1:C3?valueInputOption=USER_ENTERED" | python3 -m json.toolAppend rows
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"values":[["Charlie","35","Chicago"]]}' \
"https://sheets.googleapis.com/v4/spreadsheets/SPREADSHEET_ID/values/Sheet1!A:C:append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS" | python3 -m json.toolClear a range
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
"https://sheets.googleapis.com/v4/spreadsheets/SPREADSHEET_ID/values/Sheet1!A1:D10:clear"Get spreadsheet metadata
curl -s -H "Authorization: Bearer $TOKEN" \
"https://sheets.googleapis.com/v4/spreadsheets/SPREADSHEET_ID?fields=properties.title,sheets.properties" | python3 -m json.tool---
Google Slides
Create a presentation
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"My Presentation"}' \
"https://slides.googleapis.com/v1/presentations" | python3 -m json.toolGet presentation info
curl -s -H "Authorization: Bearer $TOKEN" \
"https://slides.googleapis.com/v1/presentations/PRESENTATION_ID" | python3 -m json.toolAdd a new slide
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests":[{"createSlide":{"slideLayoutReference":{"predefinedLayout":"TITLE_AND_BODY"}}}]}' \
"https://slides.googleapis.com/v1/presentations/PRESENTATION_ID:batchUpdate" | python3 -m json.toolLayouts: `BLANK`, `TITLE`, `TITLE_AND_BODY`, `TITLE_AND_TWO_COLUMNS`, `TITLE_ONLY`, `SECTION_HEADER`, `ONE_COLUMN_TEXT`, `MAIN_POINT`, `BIG_NUMBER`.
Add text to a slide
First get the slide's page object IDs, then insert text into a placeholder:
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests":[{"insertText":{"objectId":"PLACEHOLDER_OBJECT_ID","text":"Hello from ClawEmail!","insertionIndex":0}}]}' \
"https://slides.googleapis.com/v1/presentations/PRESENTATION_ID:batchUpdate"Add an image to a slide
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests":[{"createImage":{"url":"https://example.com/image.png","elementProperties":{"pageObjectId":"SLIDE_ID","size":{"width":{"magnitude":3000000,"unit":"EMU"},"height":{"magnitude":2000000,"unit":"EMU"}},"transform":{"scaleX":1,"scaleY":1,"translateX":1000000,"translateY":1500000,"unit":"EMU"}}}}]}' \
"https://slides.googleapis.com/v1/presentations/PRESENTATION_ID:batchUpdate"---
Google Calendar
List upcoming events
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)
curl -s -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/calendar/v3/calendars/primary/events?timeMin=$(date -u +%Y-%m-%dT%H:%M:%SZ)&maxResults=10&singleEvents=true&orderBy=startTime" | python3 -m json.toolGet events in a date range
curl -s -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/calendar/v3/calendars/primary/events?timeMin=2025-03-01T00:00:00Z&timeMax=2025-03-31T23:59:59Z&singleEvents=true&orderBy=startTime" | python3 -m json.toolCreate an event
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"summary": "Team Meeting",
"description": "Weekly standup",
"start": {"dateTime": "2025-03-15T10:00:00-05:00", "timeZone": "America/New_York"},
"end": {"dateTime": "2025-03-15T11:00:00-05:00", "timeZone": "America/New_York"},
"attendees": [{"email": "colleague@example.com"}]
}' \
"https://www.googleapis.com/calendar/v3/calendars/primary/events" | python3 -m json.toolUpdate an event
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"summary":"Updated Meeting Title","location":"Conference Room A"}' \
"https://www.googleapis.com/calendar/v3/calendars/primary/events/EVENT_ID" | python3 -m json.toolDelete an event
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/calendar/v3/calendars/primary/events/EVENT_ID"List calendars
curl -s -H "Authorization: Bearer $TOKEN" \
"https://www.googleapis.com/calendar/v3/users/me/calendarList" | python3 -m json.tool---
Google Forms
Create a form
TOKEN=$(~/.openclaw/skills/clawemail/scripts/token.sh)
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"info":{"title":"Feedback Form"}}' \
"https://forms.googleapis.com/v1/forms" | python3 -m json.toolAdd questions
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests":[{"createItem":{"item":{"title":"How would you rate this?","questionItem":{"question":{"required":true,"scaleQuestion":{"low":1,"high":5,"lowLabel":"Poor","highLabel":"Excellent"}}}},"location":{"index":0}}}]}' \
"https://forms.googleapis.com/v1/forms/FORM_ID:batchUpdate"Get form responses
curl -s -H "Authorization: Bearer $TOKEN" \
"https://forms.googleapis.com/v1/forms/FORM_ID/responses" | python3 -m json.tool---
Tips
When to Use
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...