gogcli 草稿列表指南:gog gmail drafts list 命令的完整用法与分页原理
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
导读
gog gmail drafts list是 gogcli(Google Workspace in your terminal)中用于列出 Gmail 草稿的核心只读命令。本文以 docs/commands/gog-gmail-drafts-list.md 为主线,系统讲解该命令的调用形式、全部可用标志(Flag)及其含义,并结合 gmail_drafts.go 与 paged_list_helpers.go 等源码,深入剖析分页抓取、--max/--limit数量限制、JSON 输出结构以及--fail-empty非零退出码的底层实现。读完本文,你将能在终端中熟练列出、筛选与脚本化消费 Gmail 草稿列表。
说明:该命令的文档页面由
gog schema --json自动生成,仓库中标注“Do not edit this page by hand; runmake docs-commands”,因此本文所有参数均与 internal/cmd/gmail_drafts.go 中的命令结构体定义保持一致。
命令概览:从父命令到子命令
gog gmail drafts list位于gmail → drafts → list的命令层级中,其父命令为 gog gmail drafts,该父命令同时管理草稿的 create / get / delete / send / update / reply / reply-all / forward 等操作。在源码中,父命令定义为:
type GmailDraftsCmd struct { List GmailDraftsListCmd `cmd:"" name:"list" aliases:"ls" help:"List drafts"` Get GmailDraftsGetCmd `cmd:"" name:"get" aliases:"info,show" help:"Get draft details"` Delete GmailDraftsDeleteCmd `cmd:"" name:"delete" aliases:"rm,del,remove" help:"Permanently delete a draft (not recoverable; drafts are not moved to Trash)"` Send GmailDraftsSendCmd `cmd:"" name:"send" aliases:"post" help:"Send a draft"` Create GmailDraftsCreateCmd `cmd:"" name:"create" aliases:"add,new" help:"Create a draft"` Update GmailDraftsUpdateCmd `cmd:"" name:"update" aliases:"edit,set" help:"Update a draft"` Reply GmailDraftsReplyCmd `cmd:"" name:"reply" help:"Save a reply as a draft"` ReplyAll GmailDraftsReplyAllCmd `cmd:"" name:"reply-all" aliases:"replyall" help:"Save a reply-all as a draft"` Forward GmailDraftsForwardCmd `cmd:"" name:"forward" aliases:"fwd" help:"Save a forward as a draft"` }list子命令本身还提供别名ls,因此以下三种写法等价:
gog gmail drafts list gog gmail drafts ls gog gmail ls同时,顶层还允许把gmail简写为mail或email、把drafts简写为draft。完整的规范用法如下:
gog gmail (mail,email) drafts (draft) list (ls) [flags]命令专属标志:控制返回数量、分页与空结果行为
与gog gmail drafts父命令共享的全局标志不同,list子命令在源码 gmail_drafts.go 中只声明了四个专属标志:
| 标志 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--max--limit | int64 | 20 | 每页最大结果数 |
--page--cursor | string | 空 | 分页游标(page token),用于翻页 |
--all--all-pages--allpages | bool | false | 自动抓取全部页面直到结束 |
--fail-empty--non-empty--require-results | bool | false | 无结果时以退出码 3 结束 |
下面逐个深入讲解其实现与使用要点。
--max / --limit:单页返回上限,必须大于 0
--max(别名--limit)默认值为20,决定每次向 Gmail API 请求的maxResults。Run方法在一开始就会调用校验函数:
if err := validateGmailMaxResults(c.Max); err != nil { return err }该校验定义在 gmail_search_request.go:
func validateGmailMaxResults(maxResults int64) error { if maxResults <= 0 { return usage("--max must be > 0") } return nil }因此--max 0或负数会被直接拒绝并给出--max must be > 0的错误信息。增大该值可减少分页往返次数,但 Gmail API 本身对单次列表请求也有上限约束,实际使用时建议根据草稿规模在 20~500 之间权衡。注意:--max只控制单页大小,若要一次性取回全部草稿,应配合下面的--all使用。
--page / --cursor:手动分页游标
--page(别名--cursor)用于从指定页码游标继续拉取。源码中会把非空的 page token 透传给 Gmail API:
fetch := func(pageToken string) ([]*gmail.Draft, string, error) { call := svc.Users.Drafts.List("me").MaxResults(c.Max).Context(ctx) if strings.TrimSpace(pageToken) != "" { call = call.PageToken(pageToken) } resp, callErr := call.Do() ... }也就是说,命令内部通过Users.Drafts.List("me")调用 Gmail API,使用固定的"me"作为用户标识,即以当前登录账号为准。第一次调用无需携带--page;每页返回的nextPageToken可在文本输出中看到提示(见下文“分页与空结果提示”),将其填入--page即可继续获取下一页。
--all / --all-pages:自动抓取全部分页
--all(别名--all-pages、--allpages)会把分页逻辑交给统一的 loadPagedItems:
func loadPagedItemsT any ([]T, string, error) { if all { items, err := collectAllPages(page, fetch) ... } return fetch(page) }collectAllPages进一步调用 collectPages,其行为要点包括:
- 循环调用
fetch,直到返回的nextPageToken为空; - 内置
pageTokenGuard去重保护,防止分页循环导致死循环; - 单次调用最多抓取
10_000页作为兜底上限(collectAllPages传入maxPages=10_000)。
因此--all适合脚本化地一次性导出全部草稿 ID,例如:
gog gmail drafts list --all --json--fail-empty:无结果时退出码为 3
--fail-empty(别名--non-empty、--require-results)用于 CI 与脚本中判断“是否没有任何草稿”。其实现位于 paging.go:
const emptyResultsExitCode = 3 func failEmptyExit(failEmpty bool) error { if !failEmpty { return nil } return &ExitError{Code: emptyResultsExitCode, Err: nil} }当列表为空且设置了该标志时,命令以退出码3结束;0表示成功,非 0表示出错或条件未满足,因此3为“结果为空”保留了语义化的独立退出码,方便上层脚本区分“命令执行失败”与“没有数据”两种情形。
共享的全局标志:身份、输出与安全
list命令继承父命令gog gmail drafts的全部全局标志。除上表列出的四个专属标志外,实际执行时最常配合使用的是以下几组:
账号与认证相关
| 标志 | 类型 | 默认值 | 说明 |
|---|---|---|---|
-a--account--acct | string | 空 | 账号邮箱、别名或auto(用于已认证的 Google API 命令) |
--client | string | 空 | OAuth 客户端名称(选择已存储的凭据与 token 桶) |
--access-token | string | 空 | 直接使用提供的 access token(绕过已存储的 refresh token;token 约 1 小时过期) |
--quota-project | string | 空 | 用于计费的 Google Cloud 项目(作为X-Goog-User-Project请求头;部分 API 在使用--access-token或 ADC 时必需) |
多账号场景下,--account a@b.com可以精确指定要列出哪个账号的草稿;也可以使用别名。若未指定,则按配置选择默认账号。
输出格式相关
| 标志 | 类型 | 默认值 | 说明 |
|---|---|---|---|
-j--json--machine | bool | false | 以 JSON 输出到 stdout(最适合脚本化处理) |
-p--plain--tsv | bool | false | 以稳定的可解析纯文本输出到 stdout(TSV,无颜色) |
--results-only | bool | 空 | JSON 模式下只输出主要结果(丢弃nextPageToken等信封字段) |
--select--pick--project | string | 空 | JSON 模式下按逗号分隔选择字段(尽力而为,支持点路径;多数命令推荐改用--fields) |
--color | string | auto | 颜色输出策略:auto/always/never |
安全与交互相关
| 标志 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--readonly | bool | false | 运行时拦截所有变更类 API 请求;auth add也只会请求只读 OAuth 作用域 |
--gmail-no-send | bool | false | 阻断 Gmail 发送类操作(Agent 安全开关) |
-n--dry-run--noop--preview | bool | 空 | 不执行变更,只打印将要执行的动作并成功退出 |
-y--force--assume-yes | bool | 空 | 跳过破坏性命令的确认提示 |
--no-input--non-interactive | bool | 空 | 永不提示,直接失败(适合 CI) |
--wrap-untrusted | bool | false | 在 JSON/raw 输出中,为抓取到的文本字段包裹外部不可信内容标记 |
由于list本身是只读命令,--dry-run与--readonly对其影响较小,但同一父命令下的delete、send等操作会严格受-y/--force、--readonly、--gmail-no-send约束。另有--disable-commands、--enable-commands、--enable-commands-exact(以点路径限定命令白名单)、--home(覆盖 gogcli 的 config/data/state/cache 根目录,等价于GOG_HOME)、-v/--verbose、--version、-h/--help等通用标志,完整列表见 gog-gmail-drafts-list.md。
输出解析:表格输出、JSON 结构与空结果提示
默认文本输出:ID 与 MESSAGE_ID 两列
非 JSON 模式下,命令通过outfmt.WriteTable输出表格,列定义位于 gmail_presentation.go:
func gmailDraftColumns() []outfmt.Column[*gmail.Draft] { return []outfmt.Column[*gmail.Draft]{ {Header: "ID", Value: func(draft *gmail.Draft) string { return draft.Id }}, {Header: "MESSAGE_ID", Value: func(draft *gmail.Draft) string { if draft.Message == nil { return "" } return draft.Message.Id }}, } }即默认表格包含ID(草稿 ID)与MESSAGE_ID(对应消息 ID,无消息时为空)两列。compactGmailRows会先过滤掉响应中的空指针条目(见 gmail_presentation.go),避免 nil 行导致渲染异常。
JSON 输出:drafts 数组 + 信封字段
加--json后,输出结构定义在 gmail_drafts.go:
type item struct { ID string `json:"id"` MessageID string `json:"messageId,omitempty"` ThreadID string `json:"threadId,omitempty"` }每条草稿被整理为id、messageId(可选)、threadId(可选)三个字段,整体包裹在信封对象中:
{ "drafts": [ { "id": "r123456789", "messageId": "18abc...", "threadId": "18abc..." } ], "nextPageToken": "0..." }nextPageToken即为翻页游标;若配合--results-only,该信封字段会被丢弃,只输出drafts主体,方便下游直接消费。测试用例 execute_gmail_more_commands_test.go 中即以--json --account a@b.com gmail drafts list的形式对列表、get、create、update、send、delete 等草稿全链路进行了端到端验证。
分页与空结果提示
- 若当前页仍有下一页,命令会通过
printNextPageHintWithAll打印提示,告知可继续使用--page <token>翻页或改用--all/--all-pages一次抓全(见 output_helpers.go); - 当列表为空且未指定
--fail-empty时,文本模式会在 stderr 打印No drafts并正常退出(退出码 0);指定--fail-empty后则以退出码3结束; - JSON 模式下空结果同样通过
writePagedJSONResult输出信封(drafts为空数组),并根据--fail-empty决定是否以退出码 3 结束(见 paged_list_helpers.go)。
实战示例
列出当前账号前 20 条草稿:
gog gmail drafts list列出草稿并输出为 JSON(便于 jq 处理):
gog gmail drafts list --json指定账号与单页数量:
gog gmail drafts list --account me@example.com --max 50一次性抓取全部草稿 ID:
gog gmail drafts list --all --json --results-only在 CI 脚本中判断“是否有草稿”(无结果时退出码为 3):
gog gmail drafts list --fail-empty --json延伸阅读
- 父命令与同层级子命令:gog gmail drafts(create / get / delete / send / update / reply / reply-all / forward)
- Gmail 系列命令入口:gog gmail
- 全部命令索引:Command index
- 核心实现:internal/cmd/gmail_drafts.go(
GmailDraftsListCmd定义于 L31-L36,Run方法于 L38-L102) - 分页基础设施:internal/cmd/paged_list_helpers.go 与 internal/cmd/paging.go(
--all全量抓取、--fail-empty退出码 3、页游标去重保护) - 输出列定义:internal/cmd/gmail_presentation.go
- 数量校验:internal/cmd/gmail_search_request.go
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考