Skip to content
Back to skills

Mail Assistant

ASecurity

Find, summarize, and act on emails safely with sensible defaults. Supports sending emails with file attachments.

  • 29 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added June 11, 2026
businessgosqlperformance

Security analysis

A100/100

Scanned June 11, 2026

npx -y skills add spamsch/son-of-simon --skill mail_assistant --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Mail Assistant?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Mail Assistant
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/spamsch-mail-assistant/badge)](https://www.skillsdirectory.com/skills/spamsch-mail-assistant)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
id: mail_assistant
name: Mail Assistant
description: Find, summarize, and act on emails safely with sensible defaults. Supports sending emails with file attachments.
apps:
  - Mail
tasks:
  - search_emails
  - send_email
  - move_email
  - download_attachments
  - get_unread_emails
  - mark_emails_read
essential_tasks:
  - search_emails
  - get_unread_emails
  - send_email
keywords: ["e-mail", "e-mails", "mail", "mails", "posteingang", "nachricht", "anhang", "anhänge"]
examples:
  - "Summarize unread emails from today"
  - "Find emails from UPS and show tracking numbers"
  - "Show me emails from the waas.rent account"
  - "Archive all read newsletters"
  - "Download attachments from the last email from Bob"
  - "Reply to John's email about the meeting"
  - "Send a draft to Frank with the invoice PDF attached"
safe_defaults:
  days: 7
  limit: 20
  with_content: false
confirm_before_write:
  - send email
  - delete email
  - move to trash
requires_permissions:
  - Automation:Mail
---

## Behavior Notes

### Performance: Two-Phase Search Pattern
Email metadata search (headers, sender, subject, date) is fast (~50ms via SQLite index).
**The two-phase approach remains important for reading email content:**

1. **Phase 1 — Find (headers only):** Search with filters, `with_content=false` (default).
   Returns in milliseconds via SQLite. Falls back to AppleScript if needed.
2. **Phase 2 — Read (by message_id):** Fetch content with `message_id` + `with_content=true`.
   Takes ~3-5s per email (AppleScript required for email body). Add `with_links=true` only when the user needs URLs from HTML emails (adds ~5s extra).

**Bad:** `search_emails(subject="Ferien", days=30, with_content=True)` → slow (30s+, fetches all bodies)
**Good:** `search_emails(subject="Ferien", sender="mom", days=7, limit=5)` → fast headers → then `search_emails(message_id="<id>", with_content=True)` → ~3-5s

### Search Optimization Rules
- **Combine filters:** Use both `sender` + `subject` in one call instead of two separate searches
- **Narrow date range:** Use `days=7` by default, only widen if nothing found
- **Small limit:** Use `limit=5` for targeted searches (default 20 is too many for exploration)
- **Specify account:** If the user context implies which account, use the `account` parameter to halve search time
- **Never use `with_content=true` on broad searches** — it adds seconds per result

### Search Strategy: Escalation Ladder
When a search returns nothing, systematically escalate through these steps before giving up:

1. **Start specific:** sender + subject + narrow days (e.g., days=7)
2. **Vary the keyword:** try alternative spellings, partial names, or the domain (e.g., "huk24" → "huk24-service.de")
3. **Change the search field:** try subject instead of sender, or vice versa
4. **Widen the time range:** increase days (7 → 30 → 90 → 365)
5. **Broaden mailbox scope:** use `all_mailboxes=True` — the email may be in Sent, Junk, a custom folder, or Gmail's All Mail
6. **Remove filters one at a time:** drop subject, then sender, keeping only the date range

**Important:** Each retry should change something meaningful. Don't just repeat the same search with a synonym — vary the dimension (keyword → field → time → scope).

Additional tips:
- Use `today_only=true` for "today's emails" requests
- Use the `account` parameter when user says "from X account" (not sender)

### Critical: Never Iterate Over Accounts
- `search_emails` WITHOUT an `account` parameter already searches ALL accounts' Inbox + Archive in a single call
- NEVER loop through individual accounts one by one — this is wasteful and slow
- For "today's emails": `search_emails(today_only=true, limit=20)` — one call, all accounts
- For "unread emails": `get_unread_emails` — one call, all accounts
- Only use the `account` parameter when the user specifically asks about ONE account

### Email Actions
- Always confirm before sending, deleting, or moving emails
- Show a preview of what will be sent/changed before confirming
- For bulk operations, show count and ask for confirmation

### Reading Email Content
- **Never use `with_content=true` on the initial search** — search headers first, then read by message_id
- For tracking numbers or specific content, use the two-phase pattern above
- **Handling `unknown-*` Message-IDs:** If a search result returns a Message-ID starting with `unknown-` (e.g., `unknown-36784`), this is a placeholder — NOT a real RFC Message-ID. Do NOT pass it to `search_emails(message_id=...)` — it will always fail. Instead, retry the content lookup using sender/subject filters with `with_content=True` and a narrow date range or `limit=1`.

### Follow up on the web when email isn't enough
When an email doesn't contain the information the user needs (e.g., price, invoice, order status) but references a website or account page:
- **Proactively offer to navigate there** and extract the information using browser automation
- Check memory for a saved web recipe for that domain (`memory_list`)
- If a recipe exists, follow it directly. If not, open the site and navigate using snapshots/JS
- Don't just tell the user "go check Settings → Billing" — do it for them

### Handling Multiple Accounts
- "emails from X account" means emails RECEIVED BY that account (any sender)
- "emails from X sender" means emails FROM that person/address
- Always clarify if the user mentions an account name vs sender name

### Common Request Patterns
- **"today's emails"** → use today_only=true parameter
- **"recent emails"** → use days parameter (e.g., days=7 for last week)
- **"all emails" or "read and unread"** → the search includes both by default
- **"read this email"** → search_emails with message_id AND with_content=True
- **"archive this email"** → move_email with to="archive" and message_id
- **"delete this email"** → move_email with to="trash" and message_id

### Moving and Archiving Emails
When processing emails and the user wants them archived or deleted:
1. Use search_emails to find the email and get its Message-ID
2. Use move_email with the message_id and to="archive" or to="trash"
3. The email will be moved to the account's Archive/Trash mailbox

### Sending Emails with Attachments
When the user wants to send an email with file attachments:
1. Find the file using `spotlight_search` or use the absolute path provided by the user
2. Call `send_email` with `attachments=["/absolute/path/to/file"]` — paths must be absolute
3. Multiple files: pass multiple paths in the list, e.g. `attachments=["/path/a.pdf", "/path/b.pdf"]`
4. Always use `draft=True` or `draft_visible=True` when attachments are involved so the user can review before sending

### Downloading Attachments
When the user wants to download email attachments:
1. Use search_emails to find the email and get its Message-ID
2. Use download_attachments with the message_id and output folder path
3. Attachments will be saved with their original filenames (duplicates auto-renamed)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.