Google Workspace CLI (GWS)
Google Workspace CLI. Use when the user mentions Gmail, Google Drive, Calendar, Sheets, Docs, Tasks, People, Slides, Forms, Meet, Classroom, sending email, checking inbox, managing files, reading/writing spreadsheets, viewing schedules, standup reports, or any Google Workspace operation — even if they don't explicitly say 'gws'.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install skilldb:cyrushuang1995-cmyk~gws-google-workspacecURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/skilldb%3Acyrushuang1995-cmyk~gws-google-workspace/file -o gws-google-workspace.mdGit 仓库获取源码
git clone https://github.com/openclaw/skills/commit/3b9c2411abc441a7fbdb76bdc8ed6663e6565c4d# GWS — Google Workspace CLI
Google's official Workspace CLI (`@googleworkspace/cli`). One tool for Gmail, Drive, Calendar, Sheets, Docs, Tasks, People, Slides, Forms, Meet, Classroom, and more.
GitHub: https://github.com/googleworkspace/cli
## Setup
Each session, set these before using `gws`:
```bash
export GOOGLE_WORKSPACE_PROJECT_ID=<your-project-id>
export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=~/.config/gws/credentials.json
export GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file
```
First-time setup and authorization: see **Prerequisites** below.
## Prerequisites
### 1. 安装 gws
```bash
npm install -g @googleworkspace/cli
```
### 2. GCP Console 配置
前往 [Google Cloud Console → APIs & Services → Library](https://console.cloud.google.com/apis/library),启用以下 API:
| 服务 | API 名称 |
|------|----------|
| Gmail | Gmail API |
| Drive | Google Drive API |
| Calendar | Google Calendar API |
| Sheets | Google Sheets API |
| Docs | Google Docs API |
| Tasks | Tasks API |
| People | People API |
| Slides | Google Slides API |
| Forms | Forms API |
| Meet | Google Meet API |
| Classroom | Google Classroom API |
大部分 API 在 `gws auth login` 时会自动关联,但 Sheets/Docs/Slides 等可能需要手动启用后才能调用。
**重要:启用 API 和 OAuth scope 是两回事。** API 启用决定"能不能调这个服务",OAuth scope 决定"能做什么操作",两者都需要。
### 3. OAuth 授权
`gws` 是无头 CLI,授权流程需要用户在浏览器中完成:
```bash
gws auth login
```
1. CLI 输出 OAuth URL
2. **将链接发给用户**,让用户在浏览器中打开并授权
3. 用户将回调页面中的授权码复制回来
4. 在 CLI 中粘贴授权码,完成认证
凭证保存在 `GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE` 指定的路径。`gws auth login -s <service>` 支持分批授权特定服务,不会覆盖已有 scope。
如果遇到 `insufficient authentication scopes` 错误,重新运行 `gws auth login` 并勾选缺少的权限。
## Troubleshooting
- **`insufficient authentication scopes`** → 见 Prerequisites > Scope 说明,重新授权并勾选缺少的权限
- **`File not found`** → 检查是否使用了绝对路径,改用相对路径(见 Usage Philosophy)
- **上传后文件名为 "Untitled"** → 用 `files update` 重命名(见 Known API Quirks)
- **参数不确定** → `gws schema <api.method>` 查询任意 API 的完整参数结构
- **API 未启用** → 见 Prerequisites > GCP Console,启用对应 API
---
## Gmail
**Gmail** 是最常用的服务,支持完整的邮件 CRUD、搜索、标签、附件、线程、批量操作和设置管理。
每次 `gws` 调用有 ~2-3s 启动延迟,批量操作优先(`batchModify` 每批 ≤100 条)。逐条 get 邮件可用 `&` 并行 + `wait` 加速。
### 搜索与列表
Gmail 搜索语法通过 `q` 参数传递,功能强大:`newer_than:1d`、`is:starred`、`is:unread`、`from:xxx`、`subject:keyword`、`label:xxx`、`has:attachment`、`after:YYYY/MM/DD`、`before:YYYY/MM/DD`、`category:primary`(primary/promotions/social/updates/forums)等。
```bash
gws gmail users messages list --params '{"userId":"me","q":"is:unread","maxResults":20}'
gws gmail users messages list --params '{"userId":"me","q":"is:unread"}' --page-all
```
### 读取邮件
`messages list` 仅返回 ID,需逐条 `get`。只需要摘要用 `format=metadata`(更快省 token),需要正文用 `format=full`。
**注意**:API 返回的 header 顺序不固定(按内部存储顺序,非请求顺序),**必须按 header name 匹配,不能按数组 index 取值。**
邮件正文 parts 结构不固定——有些是单层 `.payload.parts[]`,有些是嵌套 `.payload.parts[].parts[]`,两种写法都要准备好。
```bash
# 提取 headers(按 name 匹配,不要按 index)
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"metadata","metadataHeaders":["From","Subject","Date"]}'
# → jq '.payload.headers | map({(.name): .value}) | add'
# 纯文本正文(先试单层,为空再试嵌套)
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"full"}' | jq -r '.payload.parts[] | select(.mimeType == "text/plain") | .body.data' | base64 -d
# 嵌套备选: jq -r '.payload.parts[].parts[]? | select(.mimeType == "text/plain") | .body.data' | base64 -d
# 快速预览(无需 base64,但有长度限制)
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"metadata"}' | jq -r '.snippet'
```
### 并行批量读取
利用 `&` 后台并行将 N×3s 降到 ~3s:
```bash
IDS=$(gws gmail users messages list --params '{"userId":"me","q":"is:unread","maxResults":10}' 2>/dev/null | jq -r '.messages[].id')
for id in $IDS; do
gws gmail users messages get --params "{\"userId\":\"me\",\"id\":\"$id\",\"format\":\"metadata\",\"metadataHeaders\":[\"From\",\"Subject\",\"Date\"]}" 2>/dev/null | jq -r '.payload.headers | map({(.name): .value}) | add | "\(.From[:30]) | \(.Subject) — \(.Date)"' &
done; wait
```
### 批量操作
`batchModify` 一次处理最多 100 条,避免逐条循环的延迟开销:
```bash
IDS=$(gws gmail users messages list --params '{"userId":"me","q":"is:unread","maxResults":100}' 2>/dev/null | jq -c '[.messages[].id]')
gws gmail users messages batchModify --params '{"userId":"me"}' --json "{\"ids\":$IDS,\"removeLabelIds\":[\"UNREAD\"]}"
gws gmail users messages batchModify --params '{"userId":"me"}' --json "{\"ids\":$IDS,\"addLabelIds\":[\"STARRED\"]}"
```
### 发送邮件
构造 RFC 2822 格式邮件,Base64 编码后发送:
```bash
# 纯文本
RAW=$(printf "To: recipient@example.com\r\nSubject: Hello\r\nFrom: me@gmail.com\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nBody text here" | base64 -w0)
gws gmail users messages send --json "{\"raw\":\"$RAW\"}" --params '{"userId":"me"}'
# HTML(改 Content-Type 为 text/html)
RAW=$(printf "To: recipient@example.com\r\nSubject: Hello\r\nFrom: me@gmail.com\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<h1>Title</h1><p>Body</p>" | base64 -w0)
gws gmail users messages send --json "{\"raw\":\"$RAW\"}" --params '{"userId":"me"}'
```
### 附件下载
先从 `format=full` 响应中提取 `attachmentId`,再用 `attachments get` 下载(同样受相对路径限制):
```bash
# 1. 获取附件列表
gws gmail users messages get --params '{"userId":"me","id":"MSG_ID","format":"full"}' | jq '[.payload.parts[] | select(.filename != "") | {filename, body: .body.attachmentId}]'
# 2. 下载(cd 到目标目录)
cd /path/to/target/dir
gws gmail users messages attachments get --params '{"userId":"me","messageId":"MSG_ID","id":"ATTACHMENT_ID"}' --output filename.pdf
```
### 线程 / 回复链
按对话线程查看邮件,避免重复同一封邮件的多个副本:
```bash
gws gmail users threads list --params '{"userId":"me","q":"is:unread","maxResults":10}'
gws gmail users threads get --params '{"userId":"me","id":"THREAD_ID","format":"metadata"}'
```
### 标签管理
```bash
gws gmail users labels list --params '{"userId":"me"}' | jq '.labels[] | {id, name, type}'
gws gmail users labels create --json '{"name":"Projects/AI","labelListVisibility":"labelShow","messageListVisibility":"show"}' --params '{"userId":"me"}'
gws gmail users messages batchModify --params '{"userId":"me"}' --json '{"ids":["MSG_ID"],"addLabelIds":["LABEL_ID"]}'
```
### Trash
```bash
gws gmail users messages trash --params '{"userId":"me","id":"MSG_ID"}'
gws gmail users messages untrash --params '{"userId":"me","id":"MSG_ID"}'
```
### 设置
```bash
gws gmail users settings getVacation --params '{"userId":"me"}'
gws gmail users settings sendAs list --params '{"userId":"me"}'
```
---
## Drive
**Drive** 支持文件和文件夹的完整生命周期管理。所有 `--upload` 和 `--output` 路径仅支持相对路径,必须先 `cd` 到目标目录。
### 浏览与搜索
```bash
gws drive files list --params '{"pageSize":10,"orderBy":"modifiedTime desc"}'
gws drive files list --params '{"q":"mimeType=\"application/vnd.google-apps.spreadsheet\""}'
gws drive files list --params '{"q":"'\''FOLDER_ID'\'' in parents"}'
```
### 上传(两步命名)
`files create` 的 name 参数无效(CLI 未传递给 API),上传后文件名始终为 "Untitled",必须先上传再 rename。注意:`files copy` 的 name 参数有效,不受此限制。
```bash
cd /path/to/target/dir
gws drive files create --params '{}' --upload file.txt --upload-content-type text/plain
gws drive files update --params '{"fileId":"FILE_ID"}' --json '{"name":"real_name.txt"}'
```
### 创建文件夹
```bash
gws drive files create --params '{}' --json '{"name":"Folder Name","mimeType":"application/vnd.google-apps.folder"}'
```
### 复制与移动
`files copy` 的 name 参数有效(与 upload 不同),可一步完成:
```bash
# 复制(可同时重命名)
gws drive files copy --params '{"fileId":"ID"}' --json '{"name":"Copy of file"}'
# 移动到文件夹
gws drive files update --params '{"fileId":"ID","addParents":"FOLDER_ID","removeParents":"root"}' --json '{}'
```
### 下载与导出
**决策原则**:原生文件(txt, pdf, docx 等)用 `get --alt media`;Google 原生格式(Sheets, Docs, Slides)用 `export` 转换。
```bash
gws drive files get --params '{"fileId":"ID","alt":"media"}' --output file.txt
gws drive files export --params '{"fileId":"ID","mimeType":"application/pdf"}' --output doc.pdf
gws drive files export --params '{"fileId":"ID","mimeType":"text/csv"}' --output data.csv
```
### 权限与存储
```bash
gws drive permissions list --params '{"fi