Skip to main content

Google Workspace 技能

Hermes 的 Gmail、日历、Drive、联系人、表格和文档集成。使用 OAuth2 实现自动令牌刷新。当可用时,优先使用 Google Workspace CLI (gws) 以获得更全面的功能覆盖;否则回退至 Google 的 Python 客户端库。

技能路径: skills/productivity/google-workspace/

设置

整个设置过程由代理驱动——只需让 Hermes 帮你设置 Google Workspace,它会引导你完成每一步操作。流程如下:

  1. 创建 Google Cloud 项目 并启用所需 API(Gmail、日历、Drive、表格、文档、联系人)
  2. 创建 OAuth 2.0 凭据(桌面应用类型),并下载客户端密钥 JSON 文件
  3. 授权 —— Hermes 生成授权链接,你在浏览器中确认后,将重定向 URL 粘贴回来
  4. 完成 —— 从此时起,令牌将自动刷新
仅需邮件功能的用户

如果你只需要邮件功能(无需日历/Drive/表格),建议使用 himalaya 技能——它支持 Gmail 应用密码,仅需 2 分钟即可完成配置,无需创建 Google Cloud 项目。

Gmail

搜索

$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"

返回包含 idfromsubjectdatesnippetlabels 的 JSON 数据,每个消息对应一项。

阅读

$GAPI gmail get MESSAGE_ID

返回完整的消息正文文本(优先使用纯文本,若无则降级为 HTML)。

发送

# 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"

自定义发件人头信息

--from 标志可让你自定义发送邮件时的显示名称。这在多个代理共用同一 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 头部。Gmail 允许你在已认证的邮箱地址上自定义显示名称,无需额外配置。收件人看到的是自定义名称(如“研究代理”),而邮箱地址保持不变。

重要提示: 如果你在 --from 中使用了 不同的邮箱地址(非已认证账户),则该地址必须已在 Gmail 设置 → 账户 → 发送邮件作为中配置为 发送邮件别名

--from 标志同时适用于 sendreply

$GAPI gmail reply MESSAGE_ID \
--from '"Support Bot" <shared@company.com>' --body "We're on it"

回复

$GAPI gmail reply MESSAGE_ID --body "Thanks, that works for me."

自动进行线程回复(设置 In-Reply-ToReferences 头部),并使用原始消息的线程 ID。

标签

# 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

日历

# 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
warning

日历时间 必须 包含时区偏移(例如 -07:00)或使用 UTC(Z)。不带时区的日期时间(如 2026-03-01T10:00:00)是模糊的,将被当作 UTC 处理。

Drive

$GAPI drive search "quarterly report" --max 10
$GAPI drive search "mimeType='application/pdf'" --raw-query --max 5

表格

# 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"]]'

文档

$GAPI docs get DOC_ID

返回文档标题和全文内容。

联系人

$GAPI contacts list --max 20

输出格式

所有命令均返回 JSON。各服务的关键字段如下:

命令字段
gmail searchid, threadId, from, to, subject, date, snippet, labels
gmail getid, threadId, from, to, subject, date, labels, body
gmail send/replystatus, id, threadId
calendar listid, summary, start, end, location, description, htmlLink
calendar createstatus, id, summary, htmlLink
drive searchid, name, mimeType, modifiedTime, webViewLink
contacts listname, emails, phones
sheets get二维单元格值数组

故障排除

问题解决方法
NOT_AUTHENTICATED重新运行设置流程(让 Hermes 重新设置 Google Workspace)
REFRESH_FAILED令牌已被撤销 —— 重新执行授权步骤
HttpError 403: Insufficient Permission缺少权限范围 —— 撤销授权后,使用正确的服务重新授权
HttpError 403: Access Not ConfiguredGoogle Cloud 控制台中未启用相关 API
ModuleNotFoundError使用 --install-deps 运行设置脚本