gogcligog chat dm send:在终端发送 Google Chat 私信的完整实战指南
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
本篇指南围绕 gogcli 的gog chat dm send命令展开,讲解如何在终端(脚本、CI 或 Agent 工作流中)向指定 Google Workspace 用户发送 Google Chat 私信。读完本文,你将掌握该命令的参数与别名、--thread回复线程的用法、dry-run 预览与 JSON 输出的行为细节,并能对照仓库源码理解它“先建 DM space、再发 Message”的完整调用链与安全边界。
命令概览
gog chat dm send是 gog chat 命令族 中用于发送私信(Direct Message)的子命令。其用法如下(create、post是send的等价别名,在内部实现中通过 chat_dm.go 的aliases:"create,post"声明):
gog chat dm send (create,post) <email> [flags]- 位置参数
<email>:收件人邮箱(必填); --text:消息文本(必填);--thread:可选,指定要回复的线程。
它与同级子命令 gog chat dm space(查找或创建 DM space)共享同一套底层逻辑——send实际上会先执行space的 setup 动作,再投递消息。命令文档页由gog schema --json自动生成,修改后应通过make docs-commands重新生成(参见 生成文档页 顶部说明)。
内部实现:从邮箱到消息投递的完整调用链
结合 internal/cmd/chat_dm.go 中的ChatDMSendCmd.Run实现,一次gog chat dm send的执行顺序如下:
参数校验(先于一切副作用):
<email>去除首尾空白后必须非空,并经过validatePlainEmail校验——必须是纯邮箱字符串,形如Tester <x@example.com>的“姓名 + 邮箱”写法会被直接拒绝;--text去除空白后必须非空;--thread若提供,会先按spaces/_/threads/...模板预校验格式(chat_dm.go),非法线程资源以 usage 错误(退出码 2)提前失败。- 测试用例 TestExecute_ChatDM_InvalidEmailFailsBeforeDryRun 明确验证了这一点:非法邮箱、
"Tester <x@example.com>"格式、以及带多余分段的--thread值,都会在创建任何 chat 服务之前就报错,测试断言工厂函数不应被调用。
Dry-run 提前退出:校验通过后调用
dryRunExit(实现见 internal/cmd/dryrun.go)。当带有-n/--dry-run等 flag 时,命令打印计划操作chat.dm.send及其请求体(email、text、thread)后以退出码 0 结束,不触碰认证密钥环、不发起任何 API 调用。账号解析与 Workspace 限制:
requireAccount(flags)按-a/--account(邮箱、别名或auto)解析当前认证账号;随后requireWorkspaceAccount强制要求账号为 Google Workspace 账号——消费级 Gmail(@gmail.com)账号会被拒绝,chat_helpers.go 中的错误信息为 “chat requires a Google Workspace account (non-gmail.com)”。获取 Chat API 客户端:
chatService(见 runtime_services.go)从运行时服务注册表中取出按账号绑定的*chat.Service,认证所需 scope 包括chat.spaces与chat.messages(见 internal/googleauth/service.go)。setup DM space:
setupDMSpace(chat_dm.go)调用Spaces.Setup,请求体为SpaceType: "DIRECT_MESSAGE"的 space 加上一个HUMAN类型、Name为users/<email>的 membership。邮箱会经normalizeUser(chat_helpers.go)规范化为users/前缀资源名。从源码结构看,发送前无条件执行一次 setup,依赖 Google Chatspaces.setup的幂等性来复用已存在的 DM space,并以此拿到 space 资源名作为下一步的发送目标。构建并发送消息:以
&chat.Message{Text: text}构造消息;若提供了--thread,此时用真实 space 名重新规范化线程资源名(normalizeThread(space.Name, thread),见 chat_dm.go),并通过Spaces.Messages.Create(space, message)发送。附带线程时还会设置MessageReplyOption("REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD")——即线程已失效时回退为新建线程,而不是直接报错。结果输出:
- JSON 模式(
-j):输出{"message": <完整消息对象>},便于脚本解析; - 文本模式:逐行输出
resource\t<spaces/.../messages/...>与thread\t<spaces/.../threads/...>(若响应中存在),见 chat_dm.go。
- JSON 模式(
--thread参数的两种合法写法
normalizeThread(chat_helpers.go)对线程资源做了双轨校验,--thread可以传:
- 完整资源名:
spaces/<spaceID>/threads/<threadID>——必须恰好 4 段且结构正确,否则报invalid thread resource; - 裸线程 ID:可以只传线程 ID(允许带
threads/前缀),命令会将其拼接到 setup 得到的 DM space 之下。
注意裸 ID 中不能再包含/,否则视为非法。这一行为同样被 TestExecute_ChatDM_InvalidEmailFailsBeforeDryRun 中的--thread "spaces/AAA/threads/t1/extra"(5 段)用例覆盖。
常用实战示例
以下命令均可直接复制运行(前提:已用gog auth add添加了一个 Workspace 账号):
# 最基本的私信 gog chat dm send user@example.com --text "ping" # 使用 send 的别名 post gog chat dm post user@example.com --text "hello" # 回复某个已有线程(完整资源名或裸线程 ID 均可) gog chat dm send user@example.com --text "follow up" \ --thread "spaces/<spaceID>/threads/<threadID>" # dry-run:不真正发送,打印意图后以 0 退出 gog chat dm send user@example.com --text "ping" --dry-run # JSON 输出,便于脚本处理 gog chat dm send user@example.com --text "ping" --json # 指定账号(多账号环境)与只读保护 gog chat dm send user@example.com --text "ping" -a work@company.com gog chat dm send user@example.com --text "ping" --readonly # 会拦截该变更类请求--dry-run的 JSON 输出形态为{"dry_run": true, "op": "chat.dm.send", "request": {"email": ..., "text": ..., "thread": ...}},可直接接入自动化管道的预检环节。
完整 Flags 参考
下表完整继承自 命令参考页(由gog schema --json生成)。除命令专属的--text、--thread外,其余为全局 flag,在gog所有子命令上语义一致:
| Flag | Type | Default | Help |
|---|---|---|---|
--access-token | string | Use provided access token directly (bypasses stored refresh tokens; token expires in ~1h) | |
-a--account--acct | string | Account email, alias, or auto for authenticated Google API commands | |
--client | string | OAuth client name (selects stored credentials + token bucket) | |
--color | string | auto | Color output: auto|always|never |
--disable-commands | string | Comma-separated list of disabled commands; dot paths allowed | |
-n--dry-run--dryrun--noop--preview | bool | Do not make changes; print intended actions and exit successfully | |
--enable-commands | string | Comma-separated list of enabled command prefixes; dot paths allowed (restricts CLI) | |
--enable-commands-exact | string | Comma-separated list of exact enabled commands; dot paths allowed and parent commands do not enable children | |
-y--force--assume-yes--yes | bool | Skip confirmations for destructive commands | |
--gmail-no-send | bool | false | Block Gmail send operations (agent safety) |
-h--help | kong.helpFlag | Show context-sensitive help. | |
--home | string | Override gogcli config/data/state/cache root (equivalent to GOG_HOME) | |
-j--json--machine | bool | false | Output JSON to stdout (best for scripting) |
--no-input--non-interactive--noninteractive | bool | Never prompt; fail instead (useful for CI) | |
-p--plain--tsv | bool | false | Output stable, parseable text to stdout (TSV; no colors) |
--quota-project | string | Google Cloud project to bill for API usage (sent as X-Goog-User-Project; some APIs require it with --access-token or ADC) | |
--readonly | bool | false | Block mutating API requests at runtime; auth add also requests read-only OAuth scopes |
--results-only | bool | In JSON mode, emit only the primary result (drops envelope fields like nextPageToken) | |
--select--pick--project | string | In JSON mode, select comma-separated fields (best-effort; supports dot paths). Desire path: use --fields for most commands. | |
--text | string | Message text (required) | |
--thread | string | Reply to thread (spaces/.../threads/...) | |
-v--verbose | bool | Enable verbose logging | |
--version | kong.VersionFlag | Print version and exit | |
--wrap-untrusted | bool | false | In JSON/raw output, wrap fetched text fields in external untrusted-content markers |
对本命令而言,几个值得重点关注的 flag:
-n/--dry-run:在参数校验之后、任何认证与 API 调用之前生效,适合把“发消息”这种变更操作纳入可回放的脚本;-j/--json与--results-only:JSON 模式下响应外层包裹message字段;加--results-only可只保留主结果、丢弃nextPageToken之类的外层字段;--select支持点路径字段裁剪(尽力而为);--readonly:运行时拦截变更类 API 请求——dm send属于变更操作,开启后会失败,这为 Agent 场景提供了“只读模式”的硬边界(配套的 Agent 安全策略见 safety-profiles);--no-input:永不交互式提示,遇到需要确认的场景直接失败,适合 CI;--wrap-untrusted:在 JSON 输出中为取回的文本字段包裹外部不可信内容标记,供下游 LLM/Agent 消费时隔离提示注入风险(本项目中 chat 线程列表的测试 验证了该包裹行为)。
行为边界与测试佐证
- Workspace 账号是硬前提:消费级 Gmail 账号执行
chat dm send会直接得到 usage 错误,而不是走到 API 层(requireWorkspaceAccount,chat_helpers.go)。 - 端到端行为有测试覆盖:TestExecute_ChatDMSend_JSON 用 fake Chat 服务端完整演练了真实请求序列——先
POST /spaces:setup拿到spaces/dm1,再POST /spaces/dm1/messages断言请求体中的text等于ping,最后校验 stdout 包含spaces/dm1/messages/m1。这与前文“先 setup 再 Create”的调用链一一对应;TestExecute_ChatDMSpace_JSON 则断言了 setup 请求体中 membership 的name被规范化为users/user@example.com。 - 错误即退出码 2 的 usage 错误:缺
--text、非法邮箱等属于使用错误,以ExitError{Code: 2}返回,脚本可通过退出码区分“用法错误”与“API 错误”。
小结
gog chat dm send用一条命令封装了 Google Chat 私信的两个 API 步骤(spaces.setup+spaces.messages.create),并通过参数前置校验、Workspace 账号限制、dry-run 通道和--readonly硬边界,使其既能用于人工交互,也能安全地嵌入脚本与 Agent 工作流。更多 chat 相关能力(空间管理、消息列表/搜索、表情回应)可参考 docs/commands 下 gog-chat.md 及其子页面,命令总入口见 命令索引。
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考