gogcligog gmail thread命令详解:线程级读取、标签管理与附件下载
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
本文以 gogcli(Google Workspace in your terminal)的命令参考文档 docs/commands/gog-gmail-thread.md 为主体,结合 internal/cmd/gmail_thread.go 等源码实现,完整讲解gog gmail thread命令组的三个子命令(get / modify / attachments)、全部参数含义、线程 ID 的 Web 链接自动解析机制,以及面向脚本与 Agent 的输出、安全选项,读完后可直接在终端中以“整个会话线程”为单位完成邮件读取、打标与附件归档。
一、命令定位与基本用法
gog gmail thread是 gogcli 中按 Gmail 线程(Thread,即一封主题下的完整会话)组织操作的命令组。命令参考页开头给出的用法为:
gog gmail (mail,email) thread (threads,read) <command>括号中的内容来自 docs/commands/gog-gmail-thread.md 的命令定义,表示该命令存在多个等价写法:gmail可以是mail或email,thread可以是threads或read,因此gog mail thread ...、gog email thread ...均等价。从源码 internal/cmd/gmail.go 中的结构体标签可以看到,它注册在Organize分组下,help文案为 “Thread operations (get, modify)”。
父命令为 gog gmail,完整的子命令参考页分别为:
- gog gmail thread get — 获取整个线程(可下载附件)
- gog gmail thread modify — 批量修改线程内所有消息的标签
- gog gmail thread attachments — 列出/下载线程内全部附件
二、子命令一览
源码 internal/cmd/gmail_thread.go 中GmailThreadCmd定义了三个子命令,且各自带有别名(aliases):
| 子命令 | 别名 | 作用 | 参考文档 |
|---|---|---|---|
thread get | info、show | 获取线程内全部消息,可选下载附件 | gog-gmail-thread-get.md |
thread modify | update、edit、set | 修改线程内所有消息的标签 | gog-gmail-thread-modify.md |
thread attachments | files | 列出线程内全部附件 | gog-gmail-thread-attachments.md |
所有子命令的第一个位置参数均为<threadId>,且都接受第三节的 Web 链接形式。
三、threadId 支持直接粘贴 Gmail Web 链接
三个子命令入口处都会先调用normalizeGmailThreadID归一化输入(见 internal/cmd/gmail_thread.go)。该函数实现在 internal/cmd/webid.go,规则如下:
- 先去除首尾空白;空输入直接报错
usage("empty threadId")。 - 若输入可解析为 URL,且主机名(去掉
www.前缀后)是mail.google.com或gmail.google.com:- 查询参数中的
th=值若形似十六进制 ID,直接提取为线程 ID(经典链接形式); - 否则解析 URL 片段(fragment),取形如
#inbox/<threadId>中最后一段(去掉?之后的查询部分后按/切分),若形似十六进制 ID 则采用。
- 查询参数中的
- 形似十六进制 ID 的判定函数
looksLikeHexID(internal/cmd/webid.go)要求长度不小于 10 且只含0-9、a-f、A-F。
也就是说,以下写法都合法:
gog gmail thread get 189a1b2c3d4e5f60 gog gmail thread get "https://mail.google.com/mail/u/0/#inbox/189a1b2c3d4e5f60" gog mail thread get "https://mail.google.com/mail/?authuser=a%40b.com#all/189a1b2c3d4e5f60"反向操作同样内置:GmailURLCmd(internal/cmd/gmail_thread.go)会把线程 ID 转成https://mail.google.com/mail/?authuser=<account>#all/<id>形式的 Web 链接输出,文本模式每行id<TAB>url,--json模式输出{"urls": [{"id": ..., "url": ...}]}。此外gog open在打开mail.google.com线程链接时也会走同一个归一化函数(internal/cmd/open.go)。
四、gog gmail thread get:读取完整会话与附件下载
参考文档 docs/commands/gog-gmail-thread-get.md 给出的用法为:
gog gmail (mail,email) thread (threads,read) get (info,show) <threadId> [flags]4.1 命令专属参数
在继承自根命令的通用参数(见第七节)之外,get定义了以下专属参数(对应 internal/cmd/gmail_thread.go 的GmailThreadGetCmd结构体):
| 参数 | 类型 | 说明 |
|---|---|---|
--download | bool | 下载线程内所有消息的附件 |
--full | bool | 不截断,显示完整邮件正文 |
--sanitize-content(别名--sanitize、--safe) | bool | 输出面向 Agent 的净化内容:剥离 HTML、移除 HTTP(S) 链接、JSON 中省略原始 Gmail 载荷 |
--out-dir(别名--output-dir) | string | 附件写入目录(默认当前目录) |
--use-indexed-attachment-ids | bool | 全链路(输出、下载参数、保存文件名)改用 0 起始索引作为附件 ID;对应环境变量GOG_GMAIL_USE_INDEXED_ATTACHMENT_IDS |
4.2 源码级行为解析
GmailThreadGetCmd.Run的执行流程(internal/cmd/gmail_thread.go):
- 参数校验:trim 并归一化 threadId,空则报
empty threadId。 - 下载前置:若指定
--download,先解析--out-dir(经config.ExpandPath展开路径变量并filepath.Clean,默认.,见resolveGmailThreadAttachmentDir,internal/cmd/gmail_thread.go),并先走一次 dry-run 检查(--dry-run下只打印gmail.thread.get.download的意图动作后成功退出,不真正下载)。 - API 调用:通过
requireAccount取得账户、gmailService构造客户端后,调用svc.Users.Threads.Get("me", threadID).Format("full")—— 即 Gmail API 的threads.get且format=full,一次性拿回线程内每条消息的完整 header 与嵌套 payload。 - JSON 模式(
-j/--json):- 若同时
--download,遍历thread.Messages,逐条消息调用downloadAttachmentOutputs下载其collectAttachments收集到的附件; - 输出结构为
{"thread": <完整线程对象或净化后的线程>, "downloaded": [下载摘要...]};--sanitize-content时 thread 字段替换为sanitizedGmailThread结果; --use-indexed-attachment-ids时额外追加attachments数组(以 0 起始索引作为 ID),并调用stripAttachmentIDs抹掉 payload 中不透明附件 ID。
- 若同时
- 文本模式:
- 空线程直接输出
Empty thread; - 先打印
Thread contains N message(s)告知消息总数; - 逐条消息打印
=== Message i/N: <id> ===及状态标记(如已删除状态,由gmailHumanMessageStatusMarker根据labelIds生成),随后输出 From/To/Subject/Date 四个头部(--sanitize-content时头部文本同样经sanitizeGmailText处理); - 正文由
gmailcontent.BestBodyForDisplay选取最合适的显示 body;非--full时,正文超过gmailDefaultTextBodyLimit(20 000 个字符,定义于 internal/cmd/gmail_messages.go)会被truncateRunes截断,避免超大邮件刷屏; - 每条消息末尾打印附件区(
printAttachmentSection),--download时逐个输出Saved: <路径>或Cached: <路径>(命中缓存的文件标 Cached)。
- 空线程直接输出
典型用法示例(命令形式均来自参考文档与源码确认的参数):
# 完整读取一个线程 gog gmail thread get 189a1b2c3d4e5f60 # 不截断正文 + 下载全部附件到指定目录 gog gmail thread get 189a1b2c3d4e5f60 --full --download --out-dir ./inbox-attachments # JSON 输出并供脚本处理 gog gmail thread get 189a1b2c3d4e5f60 -j --results-only # 给 Agent 消费的安全输出:剥离 HTML 与链接 gog gmail thread get 189a1b2c3d4e5f60 --sanitize-content五、gog gmail thread modify:整线程批量打标
参考文档 docs/commands/gog-gmail-thread-modify.md 的用法:
gog gmail (mail,email) thread (threads,read) modify (update,edit,set) <threadId> [flags]专属参数(internal/cmd/gmail_thread.go):
| 参数 | 说明 |
|---|---|
--add | 要添加的标签,逗号分隔,可填标签名或标签 ID |
--remove | 要移除的标签,逗号分隔,可填标签名或标签 ID |
--add与--remove至少提供一个,否则报must specify --add and/or --remove(两个值均经splitCSV切分,internal/cmd/csv.go)。
源码流程(internal/cmd/gmail_thread.go):
- 校验 threadId 非空、标签参数非空;
--dry-run时打印gmail.thread.modify的意图动作(thread_id / add / remove)并退出;resolveModifyLabelIDs(internal/cmd/gmail_labels_utils.go)把标签名解析为标签 ID(借助labels.list接口对照现有标签);- 调用 Gmail API 的
threads.modify(svc.Users.Threads.Modify,请求体为ModifyThreadRequest{AddLabelIds, RemoveLabelIds}),一次作用于线程内全部消息; - JSON 模式输出
{"modified": "<threadId>", "addedLabels": [...], "removedLabels": [...]};文本模式输出Modified thread <threadId>。
单元测试 internal/cmd/gmail_thread_cmd_test.go 用 httptest 模拟了labels列表与/threads/{id}/modify两个端点,验证了--add INBOX --remove Custom场景下:标签名Custom被解析为 IDLabel_1后随请求体发送,且 JSON 输出字段与文本输出均符合预期——这印证了“按名称打标、按 ID 提交”的实现细节。
# 给整个线程加上「待办」标签并移除「已归档」标签 gog gmail thread modify 189a1b2c3d4e5f60 --add 待办,Label_7 --remove 已归档 # 预览而不修改 gog gmail thread modify 189a1b2c3d4e5f60 --add 待办 --dry-run六、gog gmail thread attachments:线程附件聚合
参考文档 docs/commands/gog-gmail-thread-attachments.md 的用法:
gog gmail (mail,email) thread (threads,read) attachments (files) <threadId> [flags]专属参数与thread get基本一致(--download、--out-dir、--use-indexed-attachment-ids,见 internal/cmd/gmail_thread.go)。其行为(internal/cmd/gmail_thread.go):
- 同样以
format=full拉取整个线程; - 对每条消息执行
collectAttachments递归收集嵌套 payload 中的附件元信息(文件名、大小、附件 ID); - 不带
--download时:文本模式打印Found N attachment(s):清单(printAttachmentLines);--json输出{"threadId": ..., "attachments": [...]},空线程时attachments为[]; - 带
--download时:逐条下载并打印Saved: <文件名> (<人类可读大小>) - <路径>(缓存命中则标Cached); - 下载文件命名规则在
downloadAttachment(internal/cmd/gmail_thread.go)中:<messageID>_<ref>_<safeFilename>,其中ref默认取附件 ID 前 8 个字符(索引模式下取 0 起始序号);文件名先经filepath.Base取最后一段以防路径穿越,为空或./..时回退为attachment。
# 只看一个线程有哪些附件 gog gmail thread attachments 189a1b2c3d4e5f60 # 全部下载到当前目录 gog gmail thread attachments 189a1b2c3d4e5f60 --download七、通用 Flags 与 Agent 安全选项
父命令参考页 docs/commands/gog-gmail-thread.md 的 Flags 表定义了作用于整个gog gmail thread命令树的通用参数(子命令页中同样继承),完整表格如下:
| Flag | 类型 | 默认值 | 说明 |
|---|---|---|---|
--access-token | string | 直接使用给定 access token(绕过本地存储的 refresh token;token 约 1 小时过期) | |
-a/--account/--acct | string | 账户邮箱、别名或auto(已认证 Google API 命令) | |
--client | string | OAuth 客户端名(选择已存储的凭据 + token 桶) | |
--color | string | auto | 颜色输出:auto|always|never |
--disable-commands | string | 禁用命令列表(逗号分隔,支持点路径) | |
-n/--dry-run/--dryrun/--noop/--preview | bool | 不做修改;打印意图动作后成功退出 | |
--enable-commands | string | 启用命令前缀列表(逗号分隔,支持点路径,用于收窄 CLI) | |
--enable-commands-exact | string | 精确启用命令列表(父命令不会连带启用子命令) | |
-y/--force/--assume-yes/--yes | bool | 跳过破坏性命令的确认 | |
--gmail-no-send | bool | false | 阻止 Gmail 发送类操作(Agent 安全) |
-h/--help | kong.helpFlag | 显示上下文相关帮助 | |
--home | string | 覆盖 gogcli 配置/数据/状态/缓存根目录(等价于GOG_HOME) | |
-j/--json/--machine | bool | false | 以 JSON 输出到 stdout(最适合脚本) |
--no-input/--non-interactive/--noninteractive | bool | 绝不交互提问,失败即退出(适合 CI) | |
-p/--plain/--tsv | bool | false | 输出稳定可解析文本(TSV、无颜色) |
--quota-project | string | 计费的 Google Cloud 项目(发送为 X-Goog-User-Project;部分 API 在--access-token或 ADC 下需要) | |
--readonly | bool | false | 运行时阻止修改类 API 请求;auth add也会仅申请只读 OAuth scope |
--results-only | bool | JSON 模式下仅输出主结果(丢弃 nextPageToken 等信封字段) | |
--select/--pick/--project | string | JSON 模式下选择字段(逗号分隔,支持点路径,尽力而为;多数命令推荐用--fields) | |
-v/--verbose | bool | 开启详细日志 | |
--version | kong.VersionFlag | 打印版本并退出 | |
--wrap-untrusted | bool | false | JSON/raw 输出时用“外部不可信内容”标记包裹抓取到的文本字段 |
与线程命令配合时,值得注意的几个点:
- 只读防护:
--readonly会在运行时拦截修改类 API 请求,配合thread get/thread attachments这类纯读取命令,可在脚本里确保“绝不改动邮箱”;而thread modify这类写操作在--readonly下会被阻止。 - dry-run:
thread modify与带--download的thread get/thread attachments都会先经过dryRunExit/attachmentDownloadDryRun,-n时只打印意图动作(含 thread_id、add/remove 列表或 out_dir)并成功退出,便于在 CI 中验证参数。 - CI 友好:
--no-input保证任何需要交互的地方直接失败而不是挂起等待;--json+--results-only可以最小化输出,方便jq消费。 - 多账户:
-a <邮箱或别名>指定操作账户,--home可把整个状态根目录指向隔离目录,便于并行会话。 - 安全输出:
--sanitize-content(thread get专属)与--wrap-untrusted(全局)分别对应“清洗正文”和“标记不可信内容”两种 Agent 消费策略;--gmail-no-send则全局封禁发送类操作,属于文档标注的 agent safety 开关。
八、继续深入
- 命令参考(自动生成于
gog schema --json,修改请运行make docs-commands,勿手工编辑):gog-gmail-thread.md、gog-gmail-thread-get.md、gog-gmail-thread-modify.md、gog-gmail-thread-attachments.md - 核心实现:internal/cmd/gmail_thread.go(三个子命令与
GmailURLCmd)、internal/cmd/webid.go(线程/消息 ID 的链接解析) - 标签解析:internal/cmd/gmail_labels_utils.go
- 测试:internal/cmd/gmail_thread_cmd_test.go(modify 的 JSON/文本双模式端到端验证)、internal/cmd/gmail_thread_run_test.go
- 父命令参考:gog-gmail.md,全部命令索引见 docs/commands/README.md
适用前提:命令行为以当前仓库源码为准,需先通过gog auth完成相应账户的 Gmail 授权;threads.get依赖 Gmail API 的读取 scope,threads.modify依赖修改类 scope,--readonly模式下写操作不可用。
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考