Install
$ agentstack add skill-proptermalone-proptermaltwo-gmail ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
> INTEGRATION STUB. This skill wires Claude Code to an external tool/account that you must supply and configure: a Gmail/Google Workspace CLI (the real setup uses a gws-style CLI wrapped by a local ~/bin/gmail script) + your Google account. It ships as a working example of the integration pattern, not a turnkey feature. See docs/integrations.md for what to install and how to plug in your own credentials. Without a Gmail/Google Workspace CLI + your Google account, this skill won't run — that's expected.
Create Gmail drafts and sends via a local ` wrapper (the example setup uses a ~/bin/gmail script wrapping a gws`-style Google Workspace CLI). Mandatory for any Gmail interaction — handles encoding, line wraps, threading, and sanitizer checks that would otherwise fail.
Instructions
Always use ` for Gmail draft creation, sends, AND deletes. Never hand-roll RFC-822 with Python's email library or call the underlying gws gmail users drafts create / messages send / drafts delete` directly — the wrapper wraps them, with mandatory sanitizer checks (create/send) and a clobber-guard (delete/update) that prevent recurring failure modes.
Subcommands (the example wrapper is invoked as gmail):
gmail draft— create or update a draft (default for the "drafts not send" rule).--updateis guarded (see below).gmail send— send immediately (sanitizer still mandatory; use sparingly — prefer drafts)gmail delete --draft-id— delete a draft, guarded against clobbering your edits (see below). ALWAYS use this; never rawgws ... drafts delete.gmail check— run sanitizer only, no API call (useful for pre-flighting copy-pasted text)
Clobber guard — deleting / updating a draft you created earlier
You may edit drafts in the Gmail web UI and send them without telling the agent. A draft handed to you on a prior turn has an extremely high likelihood of having changed. The wrapper defends against silently destroying those edits:
- On
draftcreate/update, the tool records the body it wrote under~/.config/gmail-tool/. gmail deleteandgmail draft --updatere-read the live draft first and REFUSE (exit 2, with a diff) if it differs from what the tool wrote — i.e. if you edited it. Pass--forceonly after confirming.- Gmail
drafts.deleteis permanent (no Trash). NEVER delete or supersede a draft via rawgws gmail users drafts delete— that bypasses the guard. A PreToolUse hook can block the raw form; usegmail delete.
gmail delete --gws-config ~/.config/gws- --draft-id r1234567890
To supersede a draft, prefer gmail draft --update (in-place, guarded) over create-new-then-delete-old.
Common patterns
Simple draft to a secondary account:
gmail draft --gws-config ~/.config/gws- \
--to recipient@example.com \
--subject "Subject text" \
--body-file /tmp/body.txt
Threaded reply (preserves In-Reply-To, References, threadId):
gmail draft --gws-config ~/.config/gws- \
--to helpdesk@example.com --cc original-sender@example.com \
--subject "Re: original subject" \
--body-file /tmp/reply.txt \
--reply-to-msg-id
Standalone reply (visible in Drafts label, not nested under thread): Add --no-thread to the above. Recipient-side threading still works via the In-Reply-To/References headers.
Force-send (sanitizer still runs): Use gmail send with the same args (no --update). The "drafts not send" default means this should be rare and explicit.
Defaults
- Body: write to
/tmp/body-.txtand pass--body-file(avoids shell-quoting hell) - Account: pass
--gws-configexplicitly. Default is whateverGOOGLE_WORKSPACE_CLI_CONFIG_DIRenv points to. For multiple Workspace accounts, keep one config dir per account (e.g.~/.config/gws-). - Subject and body: tool transliterates non-ASCII (em-dash →
--, smart quotes → straight) for max portability — a fine default. Pass--keep-utf8if you specifically want to preserve accents/em-dashes: the body goes out ascharset=utf-88bit, and the subject is RFC-2047-encoded (=?utf-8?…?=) so an em-dash subject or an accented name renders correctly in Gmail and recipient clients. This is a case worth testing explicitly the first time you wire up--keep-utf8in your own wrapper — a naive subject-encoding helper can return raw undecoded unicode instead of the RFC-2047 form, producing mojibake (â€") that only shows up once a real message lands in an inbox. Cheap insurance after any non-ASCII subject: confirm the on-the-wire header withgws gmail users messages get --params '{"userId":"me","id":"","format":"raw"}'and check theSubject:line is=?utf-8?…?=— themetadataformat auto-decodes the header, so userawto catch a raw-bytes regression. The sanitizer checks your input, not the tool's own output, so it won't catch a bug in your own encoding path. - Sanitizer warnings block by default. Pass
--ack-warningsto proceed. Use--dry-runto preview without API call.
Failure modes the tool eliminates
These are the recurring problems that motivated the wrapper — never re-introduce them by going around:
email.message.EmailMessage.set_content()quoted-printable encodes UTF-8 and hard-wraps at 78 chars, breaking commands and URLs- Forgetting RFC-2047 on Subject → recipient sees
â€"artifacts for em-dashes - Forgetting
Content-Transfer-Encoding: 8bit→ same as above - Hand-fabricating In-Reply-To headers → broken threading on recipient side
- Manually pre-wrapping prose at 80 chars → format=flowed clients can't reflow
- Mojibake (
â€",é, etc.) silently sent through — recipient sees garbage - Backslash line-continuation in commands → recipient's mail client may break them
- "Re:" subject without
--reply-to-msg-id→ looks like a reply but isn't threaded
All caught by the sanitizer. Don't go around it.
When NOT to use the tool
- Sending an existing draft built in the Gmail web UI: that draft never went through the sanitizer, so use raw
gws gmail users drafts sendonly if you explicitly want that bypass. - Bulk operations (>10 drafts at once): the wrapper isn't optimized for that; confirm before doing it.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: PropterMalone
- Source: PropterMalone/PropterMaltwo
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.