Google Workspace — Gmail, Calendar, Drive, Sheets & Docs
为 Hermes 提供 Gmail、Calendar、Drive、Contacts、Sheets 和 Docs 集成。它使用 OAuth2,并支持自动刷新 token。优先使用 Google Workspace CLI (gws) 以获得更广泛的覆盖范围;如果不可用,则回退到 Google 的 Python 客户端库。
技能路径: skills/productivity/google-workspace/
Setup
整个配置过程都由 agent 驱动。只要让 Hermes 帮你设置 Google Workspace,它就会一步步引导你完成。流程如下:
- 创建一个 Google Cloud project,并启用所需 API(Gmail、Calendar、Drive、Sheets、Docs、People)
- 创建 OAuth 2.0 凭据(Desktop app 类型),并下载 client secret JSON
- 授权,Hermes 会生成授权 URL,你在浏览器中批准后,把重定向 URL 粘贴回来
- 完成,此后 token 会自动刷新
如果你只需要邮件功能,不需要 Calendar / Drive / Sheets,请改用 himalaya 技能。它只需要一个 Gmail App Password,2 分钟即可配置完成,不需要 Google Cloud project。
Gmail
Searching
$GAPI gmail search "is:unread" --max 10
$GAPI gmail search "from:boss@company.com newer_than:1d"
$GAPI gmail search "has:attachment filename:pdf newer_than:7d"
每条消息都会返回 JSON,其中包含 id、from、subject、date、snippet 和 labels。
Reading
$GAPI gmail get MESSAGE_ID
返回完整邮件正文的文本版本,优先纯文本,若没有则回退到 HTML。
Sending
# Basic send
$GAPI gmail send --to user@example.com --subject "Hello" --body "Message text"
# HTML email
$GAPI gmail send --to user@example.com --subject "Report" \
--body "<h1>Q4 Results</h1><p>Details here</p>" --html
# Custom From header (display name + email)
$GAPI gmail send --to user@example.com --subject "Hello" \
--from '"Research Agent" <user@example.com>' --body "Message text"
# With CC
$GAPI gmail send --to user@example.com --cc "team@example.com" \
--subject "Update" --body "FYI"
Custom From Header
--from 参数允许你自定义外发邮件中的发件人显示名。当多个 agent 共用同一个 Gmail 账号,而你又希望收件人看到不同的名字时,这个选项非常有用:
# Agent 1
$GAPI gmail send --to client@co.com --subject "Research Summary" \
--from '"Research Agent" <shared@company.com>' --body "..."
# Agent 2
$GAPI gmail send --to client@co.com --subject "Code Review" \
--from '"Code Assistant" <shared@company.com>' --body "..."
工作原理: --from 的值会被设置为 MIME 消息中的 RFC 5322 From header。Gmail 允许你在已经通过认证的邮箱地址上自定义显示名,而无需额外配置。收件人看到的是你指定的显示名(例如 “Research Agent”),而邮箱地址本身保持不变。
重要: 如果你在 --from 中填写了不同的邮箱地址(也就是不是当前认证账号的地址),那么 Gmail 要求该地址已经在 Gmail Settings → Accounts → Send mail as 中配置为 Send As alias。
--from 同时适用于 send 和 reply:
$GAPI gmail reply MESSAGE_ID \
--from '"Support Bot" <shared@company.com>' --body "We're on it"
Replying
$GAPI gmail reply MESSAGE_ID --body "Thanks, that works for me."
它会自动把回复串到原线程中(设置 In-Reply-To 和 References header),并使用原始消息的 thread ID。
Labels
# List all labels
$GAPI gmail labels
# Add/remove labels
$GAPI gmail modify MESSAGE_ID --add-labels LABEL_ID
$GAPI gmail modify MESSAGE_ID --remove-labels UNREAD
Calendar
# List events (defaults to next 7 days)
$GAPI calendar list
$GAPI calendar list --start 2026-03-01T00:00:00Z --end 2026-03-07T23:59:59Z
# Create event (timezone required)
$GAPI calendar create --summary "Team Standup" \
--start 2026-03-01T10:00:00-07:00 --end 2026-03-01T10:30:00-07:00
# With location and attendees
$GAPI calendar create --summary "Lunch" \
--start 2026-03-01T12:00:00Z --end 2026-03-01T13:00:00Z \
--location "Cafe" --attendees "alice@co.com,bob@co.com"
# Delete event
$GAPI calendar delete EVENT_ID
Calendar 时间必须带有时区偏移(例如 -07:00),或者直接使用 UTC(Z)。像 2026-03-01T10:00:00 这样的裸 datetime 含义不明确,会被当成 UTC。
Drive
$GAPI drive search "quarterly report" --max 10
$GAPI drive search "mimeType='application/pdf'" --raw-query --max 5
Sheets
# Read a range
$GAPI sheets get SHEET_ID "Sheet1!A1:D10"
# Write to a range
$GAPI sheets update SHEET_ID "Sheet1!A1:B2" --values '[["Name","Score"],["Alice","95"]]'
# Append rows
$GAPI sheets append SHEET_ID "Sheet1!A:C" --values '[["new","row","data"]]'
Docs
$GAPI docs get DOC_ID
返回文档标题以及完整的纯文本内容。
Contacts
$GAPI contacts list --max 20
Output Format
所有命令都返回 JSON。各服务的主要字段如下:
| Command | Fields |
|---|---|
gmail search | id, threadId, from, to, subject, date, snippet, labels |
gmail get | id, threadId, from, to, subject, date, labels, body |
gmail send/reply | status, id, threadId |
calendar list | id, summary, start, end, location, description, htmlLink |
calendar create | status, id, summary, htmlLink |
drive search | id, name, mimeType, modifiedTime, webViewLink |
contacts list | name, emails, phones |
sheets get | 单元格值组成的二维数组 |
Troubleshooting
| Problem | Fix |
|---|---|
NOT_AUTHENTICATED | 重新运行 setup(让 Hermes 帮你设置 Google Workspace) |
REFRESH_FAILED | token 已被撤销,需要重新执行授权流程 |
HttpError 403: Insufficient Permission | 缺少 scope,需要撤销后按正确服务重新授权 |
HttpError 403: Access Not Configured | 对应 API 尚未在 Google Cloud Console 中启用 |
ModuleNotFoundError | 使用 --install-deps 重新运行 setup 脚本 |