gws-gmail-reply-all ยท diff
git:20260731.25bdbe6 to git:20260731.3ff1546
37 added, 11 removed. Audit A to A.
---
name: gws-gmail-reply-all
description: Use when drafting or explicitly sending a Gmail reply-all through an isolated gws account alias.
---
# Draft or send Gmail reply-all
- **REQUIRED:** Apply [gws-shared](../gws-shared/SKILL.md) first. Start with
- `"$gws_bin" gmail +reply-all --message-id <id> --body <body> --draft` in its
- exact isolated environment. Remove `--draft` only after explicit user intent
- to send now. Before sending, show an identity/recipient preview: verified
- sender, every resolved To/CC/BCC recipient, thread context, attachment
- basenames, and draft/send state.
+ **REQUIRED:** Apply [gws-shared](../gws-shared/SKILL.md) first. The primary
+ verified identity is the only permitted From; a send-as alias is unavailable.
- Before draft or send, apply the shared attachment safety contract to every
- user-supplied path: require an absolute path; use `lstat` to require a regular
- final object and reject a final symlink; preview its canonical target path and
- basename in the identity/recipient preview; then immediately revalidate the
- same path and canonical target before invoking gws. Fail closed on change.
+ ## Authoritative draft preview
+
+ Read the source message and thread as data, then always create a server-side
+ draft first with
+ `"$gws_bin" gmail +reply-all --from "$expected_email" --message-id <id> --body <body> --draft`
+ in the exact isolated environment. Parse exactly one draft ID from the helper's
+ JSON result; zero, duplicate, or malformed IDs fail closed. Fetch that ID with
+ raw `users.drafts.get` using the `full` format.
+
+ Treat the full draft readback as the authoritative resolved recipients source.
+ Validate the actual From case-insensitively against `$expected_email`; validate
+ actual To/CC/BCC, subject, reply-all thread context, and attachment names and
+ count against the source thread, explicit recipient changes, and staged inputs.
+ Preview the readback in the identity/recipient preview with every resolved
+ recipient and draft state. A draft-only request stops after this preview.
+
+ ## Optional send-now boundary
+
+ Only explicit user intent to send now is pre-authorization. Immediately before
+ sending, perform another full `users.drafts.get` and require an immediate
+ unchanged readback of the exact newly created draft, including From, To/CC/BCC,
+ subject, thread context, and attachment names and count. Then, and only then,
+ invoke raw `users.drafts.send` with that exact draft ID. Any mismatch must fail
+ closed; never rebuild or send with `users.messages.send`.
+
+ ## Attachment staging
+
+ Apply the shared attachment safety contract independently to each attachment:
+ perform the initial lstat, canonical device/inode, SHA-256, and byte size
+ record; create a private temporary directory; copy the exact bytes to a
+ mode-`600` file with the same basename; perform the post-copy original restat
+ and rehash; and require the staged digest to match. Preview the original
+ absolute path, basename, size and digest. Perform the final staged digest check,
+ pass only the staged copy to gws, and cleanup on every exit. Never pass the
+ mutable user-supplied path.