← 提示词库 Meta/muse-agent/skills/gmail/SKILL.md 原文 md
🌐 中英双语对照

name: "gmail"
description: "Work with the user's Gmail: search, read threads, draft, send, reply, forward, unsubscribe from mailing lists, manage labels, and open attachments."
icon: "gmail"
metadata: { "includeInPrompt": true }

Gmail / Gmail

Everything runs as hatch_gws_cli gmail <command>. The flows below give the exact command for each task, so start there. Commands come in two kinds:

一切通过 hatch_gws_cli gmail <command> 运行。下面的流程为每类任务给出了确切命令,请从那里入手。命令分两类:

Raw calls reach the whole API beyond the shortcuts: drafts, labels, threads, history, and settings like the vacation responder, forwarding, and send-as. To find a method, drill --help. hatch_gws_cli gmail users --help lists the resources (messages, threads, labels, drafts, settings). hatch_gws_cli gmail users <resource> --help then lists that resource's methods, for example users messages --help. Then hatch_gws_cli schema gmail.<method> (for example gmail.users.settings.updateVacation) gives that method's --params and --json.

原始调用能到达快捷方式之外的全部 API:草稿、标签、会话、历史,以及度假回复、转发、代发(send-as)等设置。要找方法,逐层执行 --help。hatch_gws_cli gmail users --help 列出资源(messages、threads、labels、drafts、settings);hatch_gws_cli gmail users <resource> --help 再列出该资源的方法,例如 users messages --help;然后 hatch_gws_cli schema gmail.<method>(例如 gmail.users.settings.updateVacation)给出该方法的 --params 与 --json。

Do not offer or attempt to create, edit, or delete Gmail filters.

不要提供或尝试创建、编辑、删除 Gmail 过滤器。

Every command uses the default Gmail account unless you add --account <account_id>. If the user has more than one Gmail linked and means a specific one, list them with hatch_gws_cli gmail accounts and pass the matching --account.

除非添加 --account <account_id>,每条命令都作用于默认 Gmail 账户。若用户链接了多个 Gmail 且指的是特定一个,先用 hatch_gws_cli gmail accounts 列出账户,再传入匹配的 --account。

Connecting / 连接

Gmail needs a one-time connect before commands return data. Run hatch_gws_cli gmail status. If it is not_connected, post the exact connect_url it returns as [Connect Gmail](<connect_url>) and wait for the user to connect. Don't invent a URL, send the user to Settings, or ask for credentials.

Gmail 需要先完成一次性连接,命令才会返回数据。运行 hatch_gws_cli gmail status。若结果为 not_connected,把返回的 connect_url 原样以 [Connect Gmail](<connect_url>) 形式发出,等待用户完成连接。不要编造 URL,不要把用户支去设置页,也不要索要凭据。

If the user asks to add or link another Gmail account, run hatch_gws_cli gmail status and post the exact add_account_url it returns as [Add Gmail account](<add_account_url>). Never reuse connect_url for an additional account. If add_account_url is absent, say that adding another account is unavailable. To remove one specific Gmail account while keeping the others, direct the user to that account under Connectors in Settings; do not disconnect Gmail entirely.

若用户要求添加或链接另一个 Gmail 账户,运行 hatch_gws_cli gmail status,把返回的 add_account_url 原样以 [Add Gmail account](<add_account_url>) 形式发出。绝不要把 connect_url 复用给额外的账户。若无 add_account_url,则说明当前无法添加其他账户。要移除某个特定 Gmail 账户而保留其他账户时,引导用户到设置中 Connectors 下的对应账户操作;不要整体断开 Gmail。

To disconnect, run hatch_gws_cli gmail disconnect and post its disconnect_url as [Disconnect Gmail](<disconnect_url>).

要断开连接,运行 hatch_gws_cli gmail disconnect,并把其 disconnect_url 以 [Disconnect Gmail](<disconnect_url>) 形式发出。

If a command reports a missing or invalid connection, rerun status and follow
the initial-connect flow when it returns a connect_url. If Google instead
returns 403, insufficientPermissions, or "insufficient authentication
scopes," use the additional-access flow below without retrying the command or
opening HITL. Do not hand-author credential files or run raw gws auth.
Describe the connection in plain words like "not connected yet," not a raw
status like not_connected.

若某命令报告连接缺失或无效,重新运行 status:返回 connect_url 时按初次连接流程处理。若 Google 返回的是 403、insufficientPermissions 或"insufficient authentication scopes",则走下文的额外授权流程,不要重试命令,也不要打开 HITL。不要手写凭据文件,也不要运行原始 gws auth。用平实语言描述连接状态,如"尚未连接",而不是 not_connected 这类原始状态。

Adding access to a connected account / 为已连接账户添加权限

If the user proactively asks to enable a documented Gmail capability, run
hatch_gws_cli gmail status --for-command <command-or-method>, passing the
documented command that needs access (for example, +draft, +send, or an
exact command key from /opt/hatch/skills/gmail/manifest.yaml, such as
users.messages.batch_modify). Use the same --account <account_id> selection as the
operation when the user targeted a particular linked account. Use the same
command after an attempted operation fails with Google's insufficient-scope
error. The capability-aware status check
returns the normal connect_url when Gmail is not connected; follow the
initial-connect flow in that case. When it is connected, it validates the
manifest mapping and returns scope_key plus scope_status. When
scope_status is not_granted, it also returns scope_add_url; copy that URL
exactly and post it on its own line:

若用户主动要求启用某项已写入文档的 Gmail 能力,运行 hatch_gws_cli gmail status --for-command <command-or-method>,传入需要权限的文档化命令(例如 +draft、+send,或 /opt/hatch/skills/gmail/manifest.yaml 中的确切命令键,如 users.messages.batch_modify)。当用户针对某个特定已链接账户时,使用与该操作相同的 --account <account_id> 选择。某次操作因 Google 的权限不足(insufficient-scope)错误失败后,也使用同一命令。这项能力感知的状态检查在 Gmail 未连接时返回正常的 connect_url;此时按初次连接流程处理。已连接时,它会校验 manifest 映射并返回 scope_key 与 scope_status。当 scope_status 为 not_granted 时,还会返回 scope_add_url;原样复制该 URL 并单独成行发出:

[Additional Gmail access](<scope_add_url>)

When scope_status is granted, the OAuth grant already covers the command;
do not show an add-access link or describe the failure as a scope problem. When
it is not_required, the command has no OAuth scope requirement. If the status
command fails because scope metadata is unavailable, report that access could
not be checked and do not guess or create a link.

当 scope_status 为 granted 时,OAuth 授权已覆盖该命令;不要展示添加权限链接,也不要把失败描述为权限(scope)问题。当其为 not_required 时,该命令没有 OAuth scope 要求。若状态命令因 scope 元数据不可用而失败,报告无法检查权限,不要猜测或自行创建链接。

Do not construct or rewrite the URL, pass an action-group key or raw Google
OAuth scope, or guess when the status command rejects the requested command. Do
not open a HITL approval, send the user to Settings, or tell them to disconnect
and reconnect: those flows do not add OAuth access. For a selected account,
tell the user to choose that same account on Google's consent screen; the
returned URL deliberately leaves account selection to Google. Wait for the user
to finish granting access before retrying the command.

不要构造或改写 URL,不要传 action-group 键或原始 Google OAuth scope,也不要在状态命令拒绝所请求的命令时靠猜。不要打开 HITL 审批、不要把用户支去设置页,也不要让用户断开重连:那些流程不会新增 OAuth 权限。对选定的账户,告诉用户在 Google 同意页上选择同一账户;返回的 URL 有意把账户选择留给 Google。等用户完成授权后再重试命令。

Rate limits / 速率限制

Gmail uses a weighted per-account request budget. Run Gmail commands sequentially. Combine redundant searches, start with a small --max, and increase it only when the first results are insufficient. Fetch full message bodies or attachments only for relevant IDs. If a result has kind: connector_rate_limited and terminal_for_attempt: true, stop Gmail work for this attempt and report the partial progress. Do not sleep, retry, delegate, or create replacement scheduled work. A parent agent or a later scheduled run can split and continue the remaining work.

Gmail 采用按账户加权的请求预算。Gmail 命令顺序执行。合并冗余搜索,--max 先取小值,仅在首批结果不足时再调大。只为相关 ID 获取完整正文或附件。若结果含 kind: connector_rate_limited 且 terminal_for_attempt: true,停止本轮 Gmail 工作,并报告已完成的进度。不要休眠、重试、委托或创建替代性计划任务。父智能体或后续的计划运行可以拆分并继续剩余工作。

Use this cost guide when planning common commands. +triage --max N costs up to 5 + 20N units (messages.list plus one messages.get per result). +read costs 20. +unsubscribe costs 20 per selected message before its non-Gmail request. A new +send normally costs 101 (settings.sendAs.list plus messages.send); a new +draft normally costs 11. Reply and forward add a 20-unit source-message read, reply-all adds a 1-unit profile read, and forwarding adds 20 per downloaded source attachment. Raw commands use the exact Gmail method weight enforced by Sentinel.

规划常用命令时参考以下成本。+triage --max N 最多花费 5 + 20N 单位(messages.list 加上每个结果一次 messages.get)。+read 花费 20。+unsubscribe 在其非 Gmail 请求之前对每封选中邮件花费 20。新 +send 通常花费 101(settings.sendAs.list 加 messages.send);新 +draft 通常花费 11。回复与转发额外产生一次 20 单位的源邮件读取,回复全部(reply-all)额外产生 1 单位的档案读取,转发每下载一个源附件额外 20。原始命令按 Sentinel 执行的确切 Gmail 方法权重计费。

Common flows / 常用流程

Search and read / 搜索与阅读

Find candidates with a targeted query in Gmail search syntax (from:, subject:, after:/before:, has:attachment, is:unread, -category:promotions), then read only the ones you need.
用 Gmail 搜索语法(from:、subject:、after:/before:、has:attachment、is:unread、-category:promotions)发出有针对性的查询找出候选,然后只读需要的那些。

Message reads preserve Gmail's raw Date / date fields for compatibility and add message_sent_at with canonical UTC and user-local forms. When Gmail exposes internalDate, the output also adds mailbox_recorded_at, which is Gmail's ordering timestamp rather than proof of receipt by the person. These are message transport timestamps, not timestamps for a delivery, payment, trip, meeting, or any other event described by the email. Never infer an event time from them; use only an event time stated by the message content, otherwise say the exact event time is unknown.

邮件读取为兼容起见保留 Gmail 原始的 Date / date 字段,并新增 message_sent_at,含规范 UTC 与用户本地时间两种形式。当 Gmail 暴露 internalDate 时,输出还会加上 mailbox_recorded_at,它是 Gmail 的排序时间戳,而不是收件人确已收取的证明。这些是邮件传输时间戳,不是邮件所述的快递、支付、行程、会议或任何其他事件的时间。绝不据此推断事件时间;只使用邮件正文明确陈述的事件时间,否则就说明确切事件时间未知。

【评论】把"传输时间戳"与"邮件所述事件时间"分开,是为了防止模型把邮件的收发时刻当作订单、行程等现实事件的发生时刻。

For relative date words in message content, such as today, tomorrow, yesterday, or this Friday, default to the calendar date of message_sent_at.user_local as the reference—not retrieval time or the current turn. An explicit date or timezone in the message body wins. message_sent_at is only the anchor for interpreting the relative wording, not the event time itself. If it is absent or invalid, or the sender's timezone versus the user's timezone makes the intended date unclear, quote the relative phrase and leave the absolute date uncertain rather than guessing.

对邮件内容中的相对日期词(如 today、tomorrow、yesterday、this Friday),默认以 message_sent_at.user_local 的日历日期为参照——而不是取回时间或当前对话轮次。正文中显式给出的日期或时区优先。message_sent_at 只是解释相对措辞的锚点,本身不是事件时间。若其缺失或无效,或发件人时区与用户时区使目标日期不明确,就引用相对短语并让绝对日期保持不确定,不要猜测。

Prefer metadata and snippets before full bodies. Widen the query, dates, or pagination if results look thin, and raise --max or page further when a task needs every match, not just the first 50. If a search was bounded or came up short, tell the user what you covered.

优先用元数据与摘要,再考虑完整正文。结果偏少时放宽查询、日期范围或分页;当任务需要全部匹配而不仅是前 50 条时,调大 --max 或继续翻页。若搜索有边界或不完整,要告知用户覆盖了哪些范围。

When it isn't clear which linked account the user means, run the search in each linked account, and don't tell the user an email doesn't exist until every account came up empty.

当不清楚用户指哪个已链接账户时,在每个已链接账户中都执行搜索;直到所有账户都为空,才能告诉用户该邮件不存在。

Count messages / 统计邮件数

Count mail by tallying real results in one of the ways below, and report the conversation (thread) count, not raw messages, to match Gmail's inbox and badge. The resultSizeEstimate in a messages list result is only an estimate and can be far off, so it is not the count.
按下述方式之一对真实结果进行累加来统计邮件,并报告会话(thread)数而非原始邮件数,以与 Gmail 的收件箱和角标一致。messages list 结果中的 resultSizeEstimate 只是估计值,可能相去甚远,因此不能作为计数。

Tell the user what you counted in plain words, like "unread in your Primary inbox," so the number and its scope match what they see in Gmail.

用平实语言告诉用户统计的是什么,如"你 Primary 收件箱中的未读",使数字及其口径与用户在 Gmail 中看到的一致。

Write and send / 撰写与发送

For raw API calls to send, insert, or import a message, or create or update a draft, write the complete email to a file and pass --upload <absolute-path>. Include the headers, a blank line, and the body. The wrapper captures the file for approval and handles base64 encoding. Files can be up to 32 MiB. Use --json only for metadata such as thread IDs; raw and message.raw are rejected.

用原始 API 调用发送、插入或导入邮件,或创建/更新草稿时,把完整邮件写入文件并传 --upload <absolute-path>。文件包含头部、一个空行和正文。包装器会把该文件留存供审批,并处理 base64 编码。文件最大 32 MiB。--json 只用于 thread ID 等元数据;raw 与 message.raw 会被拒绝。

Compose new mail, replies, and forwards with the commands below, and send only after the user approves the exact text:
用以下命令撰写新邮件、回复与转发,且只有用户批准了确切文本后才发送:

For a new message, take the recipients, subject, body, and any attachments from the user, not from your own guess.

新邮件的收件人、主题、正文与附件都要来自用户,不要靠自行猜测。

Unsubscribe / 退订

Use hatch_gws_cli gmail +unsubscribe --message-id <id> [--message-id <id> ...] for up to 20 messages. Its approval lists all selected senders; results include unsupported messages. It supports RFC 8058 mail with aligned Gmail DKIM covering From and both unsubscribe headers. Any Gmail DMARC result must pass and align.

使用 hatch_gws_cli gmail +unsubscribe --message-id <id> [--message-id <id> ...],最多 20 封。其审批会列出所有选中的发件人;结果中包含不受支持的邮件。它支持带 RFC 8058 的邮件,且需 Gmail DKIM 对齐、覆盖 From 与两个退订头。任何 Gmail DMARC 结果都必须通过且对齐。

Do not use browser, shell, mailto:, filter, or mailbox-action fallbacks. Report endpoint acceptance without claiming confirmed unsubscription, and never retry automatically.

不要使用浏览器、shell、mailto:、过滤器或邮箱动作等回退手段。可以报告端点已接受请求,但不得声称退订已确认,也不要自动重试。

Organize and delete / 整理与删除

Rules / 规则