gog 的 Gmail 技能手册:用 gogcli 在终端安全地操作 Gmail
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
导读
gog(gogcli)是一个把 Google Workspace 装进终端命令行的工具,而.agents/skills/gog-gmail/SKILL.md正是为 AI Agent 与开发者准备的Gmail 操作技能卡片:它规定了「在动手前先验证环境、默认只读、写操作必须先声明」的安全工作流,并给出了 Gmail 全部 22 个一级子命令的用途索引。读完本文,你将掌握用gog搜索、读取、收发与归档 Gmail 的标准姿势,理解--readonly、--gmail-no-send、--wrap-untrusted等安全护栏在源码层的落地方式,以及如何借助schema机器可读契约在脚本或 Agent 中不猜命令语法。
技能定位:这份 SKILL.md 是给谁用的
gog-gmail/SKILL.md由 scripts/gen-agent-skills.mjs 自动生成(文件头注释明确写了do not edit),它与.agents/skills/目录下 gog-admin、gog-calendar、gog-drive 等二十多个技能卡片组成一套Agent 能力清单。每个技能卡的配套.agents/skills/gog-gmail/agents/openai.yaml会把它暴露给 Agent:
interface: display_name: "gog Gmail" short_description: "Operate Gmail safely with gog" default_prompt: "Use $gog-gmail to perform this Gmail task safely."这份文档面向的读者有两类:
- AI Agent / LLM 调用者:需要稳定的 JSON 输出、确定的退出码、非交互模式,以及防止误写误删的命令护栏;
- 终端自动化脚本作者:需要把「检查认证 → 只读搜索 → 条件性写入」固化为可重复的 shell 流程。
在深入 Gmail 命令之前,SKILL 要求先阅读共享规则文档 .agents/skills/gog/SKILL.md,其中规定了所有服务共用的 auth、输出、安全与 live-write 规则——本文后续的护栏讲解同样适用于该文档。
Safe start:动手前必须完成的四步校验
SKILL 文档给出的安全起点是一个三段式 bash 片段,对应三个截然不同的目的:
gog auth list --check --json --no-input gog schema gmail --json gog --readonly --account user@example.com gmail search 'newer_than:7d' --max 10 --json --wrap-untrustedgog auth list --check --json --no-input:验证认证状态。--check会实际检查令牌有效性,--json让输出可被脚本解析,--no-input保证在自动化环境中不出现交互式提示——认证失败就直接报错退出,而不是挂起等待输入。gog schema gmail --json:拉取 Gmail 服务的机器可读契约(命令语法、稳定退出码、有效安全状态)。SKILL 明确警告「不要猜命令语法」(Do not guess command syntax),一切以gog gmail <command> --help和gog schema gmail <command> --json为准。- 只读搜索:
--readonly在运行时层面阻断一切变更类 API 请求;--account user@example.com显式指定账号;--json --wrap-untrusted让 Google 返回的文本内容被包进「外部不可信内容」标记,供 Agent 安全解析。
SKILL 随后给出四条操作铁律:
- 显式选账号:始终用
--account指定账号,避免隐式默认账号带来的错误操作风险; - Agent 解析 Google 内容:一律使用
--json --wrap-untrusted; - 不得变更数据:任务不涉及写操作时必须带
--readonly; - 自动化环境:使用
--no-input;对支持的写操作先用--dry-run预览; - 任何写/删操作前:确认确切的账号、对象与变更内容。
命令总览:Gmail 的 22 个一级子命令
SKILL 文档用一张表列出了gog gmail的全部一级子命令。对照源码 internal/cmd/gmail.go 中的GmailCmd结构体,这张表与代码里的cmd:标签一一对应,并且按group分成了读(Read)、组织(Organize)、写(Write)、管理(Admin)四类:
| 命令 | 用途 | 代码分组 |
|---|---|---|
archive | 归档消息或显式线程(从收件箱移除) | Organize |
attachment | 下载单个附件 | Read |
autoreply | 对匹配消息只回复一次 | Write |
batch | 批量操作(永久删除需要更宽的 Gmail scope;普通删除请用 trash) | Organize |
drafts | 草稿操作 | Write |
forward | 转发消息给新收件人(别名fwd) | Write |
get | 获取单条消息(full\|metadata\|raw) | Read |
history | Gmail 历史记录 | Read |
import | 将 RFC822/EML 消息导入 Gmail | Write |
labels | 标签操作 | Organize |
mark-read | 标记消息已读(别名read-messages) | Organize |
messages | 消息操作 | Read |
raw | 输出原始 Gmail API 响应 JSON(Users.Messages.Get,无损,供脚本与 LLM 使用) | Read |
reply | 回复消息 | Write |
reply-all | 回复所有参与者(别名replyall) | Write |
search | 用 Gmail 查询语法搜索线程(别名find,query,ls,list) | Read |
send | 发送邮件 | Write |
settings | 设置与管理(含 filters/delegates/forwarding/autoforward/sendas/vacation/watch 子组) | Admin |
thread | 线程操作(get、modify) | Read |
track | 邮件打开追踪 | Write |
trash | 移入回收站 | Organize |
unread | 标记消息未读(别名mark-unread) | Organize |
url | 打印线程的 Gmail 网页 URL | Read |
源码提示:
GmailCmd中还声明了watch、autoforward、delegates、filters、forwarding、sendas、vacation等hidden:""字段,它们作为独立隐藏命令存在,同时在GmailSettingsCmd中被正式暴露为settings的子命令(见 internal/cmd/gmail.go)。
SKILL 特别强调两点使用纪律:
- 拿不准命令语法时,先
gog gmail <command> --help看旗标、gog schema gmail <command> --json看机器可读契约; batch的永久删除语义:永久删除需要更宽的 Gmail scope(https://mail.google.com/),日常「删除」应该走gmail trash,这与共享规则文档 .agents/skills/gog/SKILL.md 中「gmail batch delete 永久删除消息、需要更宽 OAuth scope,优先用 gmail trash」的说明完全一致。
核心场景一:只读搜索(Read)
gmail search是 Agent 与脚本使用频率最高的入口。命令定义在 internal/cmd/gmail_search.go 的GmailSearchCmd中,关键参数如下:
| 参数 | 类型/默认 | 说明 |
|---|---|---|
query | 位置参数(可多段,自动拼接) | Gmail 查询语法,如'newer_than:7d'、'from:example@example.com' |
--from-contact | string | 解析一个 Google 联系人,自动扩展出from:(email OR email)追加到查询 |
--max/--limit | int64,默认 10 | 最大结果数(源码中validateGmailMaxResults会做上限校验) |
--page/--cursor | string | 分页游标 |
--all/--all-pages/--allpages | bool | 拉取全部分页 |
--count | bool | 输出全量匹配数(totalMatches精确值或totalMatchesAtLeast下界) |
--oldest | bool | 显示首封消息日期而非最后一封 |
--fail-empty/--non-empty/--require-results | bool | 无结果时以退出码 3 退出,便于管道判断 |
--timezone/-z、--local | string | 输出时区(IANA 名称,默认取GOG_TIMEZONE→ 配置 → 本地) |
从源码调用链可以看到它的完整流程(internal/cmd/gmail_search.go):
- 校验
--max上限 →requireAccount解析账号; - 拼接 query;若给了
--from-contact,调用gmailFromContactQuery解析联系人并展开from:子句; - 通过
gmailService拿到 Gmail API client,调用svc.Users.Threads.List("me")(即搜索的是线程 Thread而非单条消息); - 用
loadPagedItems处理分页(--page游标 /--all全量); - 若指定
--count,调用countGmailThreadMatches统计全量匹配数并写入 payload; - 解析标签 ID → 名称映射,按
--oldest/时区渲染线程详情; - JSON 模式下输出
{"threads": [...], "nextPageToken": ...}信封结构。
因此--results-only可以去掉信封、只留下threads数组,配合--select做字段投影(如--results-only --select id),这是脚本里「只取 ID 列表」的标准姿势。
读消息时的内容安全
SKILL 的共享规则建议正文检查优先用--sanitize-content(除非明确需要原始 payload)。该开关的实现在 internal/cmd/gmail_sanitize.go:
sanitizeGmailText:先做 HTML 反转义,再用正则https?://[^\s<>"']把 URL 替换为[url removed]`——这是对邮件正文中不可信链接的主动降险;sanitizeGmailBody:HTML 正文先经extractSanitizedHTMLText抽取纯文本,再压缩空白为单空格并TrimSpace;- 输出结构
gmailSanitizedMessageOutput只保留 ID、ThreadID、LabelIDs、Snippet、InternalDate、SizeEstimate、Headers、Body、Attachments 等字段,去掉了原始 MIME 中的可执行风险面。
配合--wrap-untrusted(JSON/raw 输出把外部拉取的文本字段包进不可信内容标记),这两层共同保证「Agent 拿到的 Gmail 内容是可以安全解析的文本,而不是可以注入指令的原始 HTML」。
核心场景二:发送、回复与转发(Write)
SKILL 对写操作给出的原则是:先确认账号、对象 ID 与确切变更,优先用支持--dry-run的命令。
共享规则文档提供了回复邮件的推荐姿势——不要用gmail send手工重建回复 MIME,而是用一等公民命令:
gog --account user@example.com gmail reply <messageId> --body-file reply.txt gog --account user@example.com gmail reply-all <messageId> --body-file reply.txt \ --bcc introducer@example.com --remove former-participant@example.comreply/reply-all会自动继承主题、默认引用原文、保留显示名与内联图片,并把--to/--cc/--bcc视为「追加式」的放置或移动;--no-quote可省略原文。其余写命令还包括forward、import(RFC822/EML 导入)、drafts、autoreply(对匹配消息只回复一次)、send与track(邮件打开追踪)。
--gmail-no-send的实现级护栏
「除非任务是发邮件,否则一律加--gmail-no-send」这条规则在源码里有完整的三层落地,见 internal/cmd/gmail_no_send.go:
var gmailSendCommandPaths = map[string]struct{}{ "send": {}, "gmail.send": {}, "gmail.reply": {}, "gmail.reply-all": {}, "gmail.replyall": {}, "gmail.autoreply": {}, "gmail.forward": {}, "gmail.fwd": {}, "gmail.drafts.send": {}, }enforceGmailNoSend在命令解析层(kong.Context)拦截:
- 命令路径不在发送集合内 → 直接放行;
- 命中发送集合且给了
--gmail-no-send→ 报错Gmail sending is blocked by --gmail-no-send; - 再检查全局配置键
gmail_no_send与按账号的 no-send 名单(config no-send),逐层拦截。
注释里特别说明:这一层守卫在--dry-run下同样生效(因为 dry-run 在 post-auth 检查到达之前就退出了),且按账号守卫只在存在 no-send 配置时才解析账号,避免无谓地触发 keyring 读取。这解释了为什么 SKILL 要求「对支持的写操作先--dry-run」——即使预览,发送类命令也会被完整护栏罩住。
发现机制:schema 与生成的命令文档
SKILL 反复强调「不要猜语法」,其背后的可执行机制是三层发现路径:
gog gmail --help # 服务级帮助 gog gmail <command> --help # 命令级帮助(全部旗标) gog schema gmail <command> --json # 机器可读契约仓库同步维护了由gog schema --json自动生成的命令参考文档(文件头注明Generated from gog schema --json. Do not edit this page by hand; run make docs-commands),例如:
- docs/commands/gog-gmail.md ——
gog gmail服务页,含全部子命令索引与全局旗标表(--readonly、--gmail-no-send、--wrap-untrusted、--dry-run、--enable-commands、--disable-commands等); - docs/commands/gog-gmail-search.md ——
search子命令的完整旗标表,包括--count、--fail-empty、--from-contact、--oldest、--timezone等; - docs/commands/README.md —— 全部命令索引。
手动编写 Agent 工具描述或 shell 封装时,直接引用这些生成文档即可获得与二进制完全同步的参数定义,不必人工维护。
组合实战:把安全搜索固化成可复用流程
综合 SKILL 与共享规则文档,一个「安全且 Agent 友好」的 Gmail 只读流程可以写成:
# 1. 先验证认证(自动化环境必须 --no-input) gog auth list --check --json --no-input || gog auth doctor --check --json --no-input # 2. 只读搜索最近 7 天邮件,JSON + 不可信内容包裹 gog --readonly --account user@example.com \ gmail search 'newer_than:7d' --max 10 --json --wrap-untrusted # 3. 取某条消息的安全化正文(优先 --sanitize-content) gog --readonly --account user@example.com \ gmail get <messageId> --sanitize-content --json --wrap-untrusted # 4. 线程级查看 gog --readonly --account user@example.com \ gmail thread get <threadId> --sanitize-content --json --wrap-untrusted需要追加命令级运行守卫时,用共享规则中的--enable-commands/--disable-commands把 CLI 收窄到白名单:
gog --readonly --enable-commands gmail.search,gmail.get --gmail-no-send \ --account user@example.com gmail search 'from:example@example.com' --json这条命令同时叠加了只读、命令白名单、禁发邮件三层限制,即使 Agent 的后续行为失控,也无法越出「搜索 + 读取」的范围。
写给 Agent 与自动化脚本的关键约定
最后汇总 SKILL 与配套源码对自动化场景的硬性约定:
- stdout 只放数据:人类可读的提示与进度走 stderr,stdout 专供
--json/--plain(TSV)结构化输出; - 稳定退出码:
--fail-empty无结果退出码为 3,配合--json可被脚本直接判断分支; - 不可信内容处理:读 Google 内容一律
--json --wrap-untrusted,正文检查优先--sanitize-content;raw子命令保留无损原始响应,但仅供需要完整 payload 的场景; - 绝不输出敏感信息:不得打印 access token、refresh token、OAuth client secret 或 keyring 密码;服务环境下的
GOG_KEYRING_BACKEND=file、GOG_KEYRING_PASSWORD、HOME必须由启动gog的进程提供; - 破坏性命令需
--force:除非用户明确要求该确切的变更,Agent 不得自行追加--force; - 临时对象要清理:测试创建类命令时使用带临时前缀的命名,验证后立即删除或移入回收站。
延伸阅读
- .agents/skills/gog/SKILL.md —— 所有服务共享的认证、输出、安全与 live-write 规则(Gmail 技能的前置文档)
- internal/cmd/gmail.go —— Gmail 命令注册表与子命令分组
- internal/cmd/gmail_no_send.go ——
--gmail-no-send三层护栏实现 - internal/cmd/gmail_sanitize.go ——
--sanitize-content正文清洗实现 - docs/commands/gog-gmail.md 与 docs/commands/gog-gmail-search.md —— 由
schema生成的命令与旗标权威参考 - docs/agent-skills.md 与 docs/safety-profiles.md —— Agent 技能清单与安全配置文件说明
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考