Files
googleworkspace--cli/docs/skills.md
Justin Poehnelt 6e4daaf4f9 feat(gmail): Gmail helpers rollup — mail-builder, --attachment, +read (#526)
* refactor(gmail): replace hand-rolled email construction with mail-builder

Replace custom MessageBuilder, RFC 2047 encoding, header sanitization,
and address encoding (including #482) with the mail-builder crate
(Stalwart Labs, 0 runtime deps). Each command builds a
mail_builder::MessageBuilder directly.

Introduce structured types throughout:
- Mailbox type (parsed display name + email) replaces raw string passing
- sanitize_control_chars strips ASCII control characters (CRLF, null,
  tab, etc.) at the parse boundary — defense-in-depth for mail-builder's
  structured header types, superseding sanitize_header_value,
  sanitize_component, and encode_address_header from #482
- OriginalMessage fields use Option<T> instead of empty-string sentinels
- parse_original_message returns Result with validation (threadId, From,
  Message-ID)
- Pre-parsed Config types (SendConfig, ForwardConfig, ReplyConfig) with
  Vec<Mailbox> — parse at the boundary, not downstream
- parse_forward_args and parse_send_args return Result with --to
  validation, consistent with parse_reply_args
- parse_optional_mailboxes helper normalizes Some(vec![]) to None for
  optional address fields (--cc, --bcc, --from)
- Envelope types borrow from Config + OriginalMessage with lifetimes
- Message IDs stored bare (no angle brackets), parsed once at boundary
- References stored as Vec<String> instead of space-separated string
- ThreadingHeaders bundles In-Reply-To + References with debug_assert
  for bare-ID convention
- Shared CLI arg builders (common_mail_args, common_reply_args)
  eliminate duplicated --cc/--bcc/--html/--dry-run definitions

Additional improvements:
- finalize_message returns Result instead of panicking via .expect()
- Mailbox::parse_list filters empty-email entries (trailing comma edge
  case)
- format_email_link percent-encodes mailto hrefs to prevent parameter
  injection
- Forward date handling: omits Date line when absent instead of showing
  empty "Date: "
- Dry-run auth: log skipped auth as diagnostic instead of silently
  discarding errors
- Restore --html tips in after_help strings (gmail_quote CSS, cid:
  image warnings, HTML fragment advice) lost in release PR #434
- Update execute_method call for upload_content_type parameter (#429)

Delete: MessageBuilder, encode_header_value, sanitize_header_value,
encode_address_header, sanitize_component, extract_email,
extract_display_name, split_mailbox_list, build_references.

* feat(gmail): add --from flag to +send for send-as alias support

Consistent with +reply, +reply-all, and +forward which already support
--from. Uses the same parse_optional_mailboxes path and
apply_optional_headers plumbing.

* fix: quote display names with RFC 2822 special characters in +reply

When replying to emails from corporate senders with display names like
"Anderson, Rich (CORP)" <email@adp.com>, the +reply command fails with
"Invalid To header" (400) from the Gmail API.

The root cause: encode_address_header() strips quotes from the display
name via extract_display_name(), then reconstructs the address without
re-quoting. When the display name contains RFC 2822 special characters
(commas, parentheses), the unquoted form is ambiguous — commas split
it into multiple malformed mailboxes and parentheses are interpreted
as RFC 2822 comments.

Fix: re-quote the display name when it contains any RFC 2822 special
characters, using a single-pass character iterator that preserves
already-escaped sequences and escapes bare quotes/backslashes.

Fixes #512

* feat(gmail): add --attachment flag, +read helper, and mail-builder migration

Consolidates PRs #491, #513, #517, and #502 into a single rollup:

- Migrate message construction to mail-builder crate (RFC-compliant MIME)
- Add --from flag to +send for send-as alias support
- Add --attachment flag to +send with MIME auto-detection and path validation
- Add +read helper for extracting message body/headers (text, HTML, JSON)
- Serialize support for OriginalMessage and Mailbox types
- Display name quoting handled natively by mail-builder

* chore: regenerate skills [skip ci]

* fix: use validate_safe_file_path for attachment path validation

Addresses Gemini review: validate_safe_dir_path hardcodes '--dir' in
error messages. validate_safe_file_path accepts the flag name, so errors
now correctly reference '--attachment'.

* refactor: make OriginalMessage.thread_id optional

The Gmail API does not guarantee threadId on all message resources
(e.g. drafts). Making it Option<String> prevents parse failures on
valid messages and avoids requiring thread_id in helpers like +read
that don't use it.

* fix: use canonicalized path for attachment file operations (TOCTOU)

validate_safe_file_path returns a canonicalized PathBuf. Use it for
exists/is_file checks and downstream file reads instead of the original
un-resolved path to prevent time-of-check/time-of-use races.

* feat(gmail): add --attach flag for file attachments

Add -a/--attach to +send, +reply, +reply-all, and +forward. Can be
specified multiple times for multiple attachments. MIME type is auto-
detected via mime_guess2. Closes #247.

Send via the Gmail API upload endpoint (multipart/related with
message/rfc822 media type) instead of base64-encoding into a JSON raw
field. This raises the size limit from ~5MB (metadata-only endpoint) to
35MB (upload endpoint, per discovery document).

Introduce UploadSource enum in the executor to consolidate upload_path,
upload_content_type, and upload_bytes into a single type-safe parameter.
File and Bytes variants make the two upload strategies (from disk vs.
from memory) mutually exclusive by construction.

Validates attachment paths (control characters, regular file, non-empty)
and total size (25MB raw limit, accounting for base64 expansion of
attachments within the MIME message against the 35MB API limit). Size
check uses actual bytes read to avoid TOCTOU race.

* chore: update changeset and fix integration with malob's attachment impl

Update changeset to reflect combined work. Fix thread_id type mismatches
in new tests from cherry-pick. Fix upload_path scope in main.rs. Make
reject_control_chars pub(crate) for attachment validation.

Co-authored-by: Malo Bourgon <mbourgon@gmail.com>

* chore: regenerate skills [skip ci]

* fix: restore MIME sanitization and terminal escape protection in executor

Restore two security features accidentally lost during the UploadSource
refactor:

1. resolve_upload_mime: restructure from early-returns to collect-then-
   sanitize pattern — strips control chars from user-supplied MIME types
   to prevent CRLF header injection.

2. Model Armor error path: restore sanitize_for_terminal on error messages
   to prevent terminal escape sequence injection from API responses.

Co-authored-by: Malo Bourgon <mbourgon@gmail.com>

* chore: remove duplicate changeset from cherry-pick

gmail-attach-flag.md duplicated content already in gmail-helpers-rollup.md.
Both were marked minor, which would cause a double version bump.

* fix: add path traversal protection to attachment validation

Replace reject_control_chars with validate_safe_file_path in
parse_attachments. All file operations (metadata, read, filename
extraction, MIME detection) now use the canonicalized path, preventing
path traversal attacks (e.g. ../../.ssh/id_rsa) and closing TOCTOU gaps.

Update tests to use CWD-relative temp directories (tempdir_in("."))
since validate_safe_file_path rejects paths outside the working directory.

Co-authored-by: Malo Bourgon <mbourgon@gmail.com>

* refactor: deduplicate terminal sanitizer in read.rs

Replace the local sanitize_terminal_output function with the existing
crate::error::sanitize_for_terminal via import alias. This eliminates
code duplication and provides consistent sanitization across the codebase.

The crate-wide sanitizer also correctly strips CR (carriage return) which
can be abused for terminal overwrite attacks.

---------

Co-authored-by: Malo Bourgon <mbourgon@gmail.com>
Co-authored-by: Rich Anderson <richanderson00@gmail.com>
Co-authored-by: jpoehnelt-bot <jpoehnelt-bot@users.noreply.github.com>
Co-authored-by: googleworkspace-bot <googleworkspace-bot@users.noreply.github.com>
2026-03-17 16:55:50 -06:00

13 KiB

Skills Index

Auto-generated by gws generate-skills. Do not edit manually.

Services

Core Google Workspace API skills.

Skill Description
gws-shared gws CLI: Shared patterns for authentication, global flags, and output formatting.
gws-drive Google Drive: Manage files, folders, and shared drives.
gws-sheets Google Sheets: Read and write spreadsheets.
gws-gmail Gmail: Send, read, and manage email.
gws-calendar Google Calendar: Manage calendars and events.
gws-admin-reports Google Workspace Admin SDK: Audit logs and usage reports.
gws-docs Read and write Google Docs.
gws-slides Google Slides: Read and write presentations.
gws-tasks Google Tasks: Manage task lists and tasks.
gws-people Google People: Manage contacts and profiles.
gws-chat Google Chat: Manage Chat spaces and messages.
gws-classroom Google Classroom: Manage classes, rosters, and coursework.
gws-forms Read and write Google Forms.
gws-keep Manage Google Keep notes.
gws-meet Manage Google Meet conferences.
gws-events Subscribe to Google Workspace events.
gws-modelarmor Google Model Armor: Filter user-generated content for safety.
gws-workflow Google Workflow: Cross-service productivity workflows.

Helpers

Shortcut commands for common operations.

Skill Description
gws-drive-upload Google Drive: Upload a file with automatic metadata.
gws-sheets-append Google Sheets: Append a row to a spreadsheet.
gws-sheets-read Google Sheets: Read values from a spreadsheet.
gws-gmail-send Gmail: Send an email.
gws-gmail-triage Gmail: Show unread inbox summary (sender, subject, date).
gws-gmail-reply Gmail: Reply to a message (handles threading automatically).
gws-gmail-reply-all Gmail: Reply-all to a message (handles threading automatically).
gws-gmail-forward Gmail: Forward a message to new recipients.
gws-gmail-read Gmail: Read a message and extract its body or headers.
gws-gmail-watch Gmail: Watch for new emails and stream them as NDJSON.
gws-calendar-insert Google Calendar: Create a new event.
gws-calendar-agenda Google Calendar: Show upcoming events across all calendars.
gws-docs-write Google Docs: Append text to a document.
gws-chat-send Google Chat: Send a message to a space.
gws-events-subscribe Google Workspace Events: Subscribe to Workspace events and stream them as NDJSON.
gws-events-renew Google Workspace Events: Renew/reactivate Workspace Events subscriptions.
gws-modelarmor-sanitize-prompt Google Model Armor: Sanitize a user prompt through a Model Armor template.
gws-modelarmor-sanitize-response Google Model Armor: Sanitize a model response through a Model Armor template.
gws-modelarmor-create-template Google Model Armor: Create a new Model Armor template.
gws-workflow-standup-report Google Workflow: Today's meetings + open tasks as a standup summary.
gws-workflow-meeting-prep Google Workflow: Prepare for your next meeting: agenda, attendees, and linked docs.
gws-workflow-email-to-task Google Workflow: Convert a Gmail message into a Google Tasks entry.
gws-workflow-weekly-digest Google Workflow: Weekly summary: this week's meetings + unread email count.
gws-workflow-file-announce Google Workflow: Announce a Drive file in a Chat space.

Personas

Role-based skill bundles.

Skill Description
persona-exec-assistant Manage an executive's schedule, inbox, and communications.
persona-project-manager Coordinate projects — track tasks, schedule meetings, and share docs.
persona-hr-coordinator Handle HR workflows — onboarding, announcements, and employee comms.
persona-sales-ops Manage sales workflows — track deals, schedule calls, client comms.
persona-it-admin Administer IT — monitor security and configure Workspace.
persona-content-creator Create, organize, and distribute content across Workspace.
persona-customer-support Manage customer support — track tickets, respond, escalate issues.
persona-event-coordinator Plan and manage events — scheduling, invitations, and logistics.
persona-team-lead Lead a team — run standups, coordinate tasks, and communicate.
persona-researcher Organize research — manage references, notes, and collaboration.

Recipes

Multi-step task sequences with real commands.

Skill Description
recipe-label-and-archive-emails Apply Gmail labels to matching messages and archive them to keep your inbox clean.
recipe-draft-email-from-doc Read content from a Google Doc and use it as the body of a Gmail message.
recipe-organize-drive-folder Create a Google Drive folder structure and move files into the right locations.
recipe-share-folder-with-team Share a Google Drive folder and all its contents with a list of collaborators.
recipe-email-drive-link Share a Google Drive file and email the link with a message to recipients.
recipe-create-doc-from-template Copy a Google Docs template, fill in content, and share with collaborators.
recipe-create-expense-tracker Set up a Google Sheets spreadsheet for tracking expenses with headers and initial entries.
recipe-copy-sheet-for-new-month Duplicate a Google Sheets template tab for a new month of tracking.
recipe-block-focus-time Create recurring focus time blocks on Google Calendar to protect deep work hours.
recipe-reschedule-meeting Move a Google Calendar event to a new time and automatically notify all attendees.
recipe-create-gmail-filter Create a Gmail filter to automatically label, star, or categorize incoming messages.
recipe-schedule-recurring-event Create a recurring Google Calendar event with attendees.
recipe-find-free-time Query Google Calendar free/busy status for multiple users to find a meeting slot.
recipe-bulk-download-folder List and download all files from a Google Drive folder.
recipe-find-large-files Identify large Google Drive files consuming storage quota.
recipe-create-shared-drive Create a Google Shared Drive and add members with appropriate roles.
recipe-log-deal-update Append a deal status update to a Google Sheets sales tracking spreadsheet.
recipe-collect-form-responses Retrieve and review responses from a Google Form.
recipe-post-mortem-setup Create a Google Docs post-mortem, schedule a Google Calendar review, and notify via Chat.
recipe-create-task-list Set up a new Google Tasks list with initial tasks.
recipe-review-overdue-tasks Find Google Tasks that are past due and need attention.
recipe-watch-drive-changes Subscribe to change notifications on a Google Drive file or folder.
recipe-create-classroom-course Create a Google Classroom course and invite students.
recipe-create-meet-space Create a Google Meet meeting space and share the join link.
recipe-review-meet-participants Review who attended a Google Meet conference and for how long.
recipe-create-presentation Create a new Google Slides presentation and add initial slides.
recipe-save-email-attachments Find Gmail messages with attachments and save them to a Google Drive folder.
recipe-send-team-announcement Send a team announcement via both Gmail and a Google Chat space.
recipe-create-feedback-form Create a Google Form for feedback and share it via Gmail.
recipe-sync-contacts-to-sheet Export Google Contacts directory to a Google Sheets spreadsheet.
recipe-share-event-materials Share Google Drive files with all attendees of a Google Calendar event.
recipe-create-vacation-responder Enable a Gmail out-of-office auto-reply with a custom message and date range.
recipe-create-events-from-sheet Read event data from a Google Sheets spreadsheet and create Google Calendar entries for each row.
recipe-plan-weekly-schedule Review your Google Calendar week, identify gaps, and add events to fill them.
recipe-share-doc-and-notify Share a Google Docs document with edit access and email collaborators the link.
recipe-backup-sheet-as-csv Export a Google Sheets spreadsheet as a CSV file for local backup or processing.
recipe-save-email-to-doc Save a Gmail message body into a Google Doc for archival or reference.
recipe-compare-sheet-tabs Read data from two tabs in a Google Sheet to compare and identify differences.
recipe-batch-invite-to-event Add a list of attendees to an existing Google Calendar event and send notifications.
recipe-forward-labeled-emails Find Gmail messages with a specific label and forward them to another address.
recipe-generate-report-from-sheet Read data from a Google Sheet and create a formatted Google Docs report.