Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Locate a specific email when the obvious searches fail. Use when the user is confident an email exists but a targeted query returned nothing.
.claude/skills/sonichi-email-find/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 809% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 24% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 77% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 168% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 67% | 0% |
A playbook for finding a specific email through the Gmail MCP (claude.ai Gmail) when the obvious search query returns nothing. Optimized for the case where the user describes an email and the agent must not give up easily.
Usage: /email-find <description>
ARGUMENTS: $ARGUMENTS
get_thread with MINIMAL format returns metadata + snippets for every message but omits the message bodies. If you've identified the candidate thread and need to read what was actually written, fetch it again with FULL_CONTENT. The search-result preview in the UI may also truncate long threads; FULL_CONTENT exposes everything.In the queries below, me is Gmail's reserved keyword for the authenticated user's primary address — works for everyone regardless of which account is connected.
Run one broad query first to anchor on what's actually in the inbox in the relevant time window:
search_threads query="(to:me OR from:me) newer_than:Nd" pageSize=15Where N covers the window the user cited (default 2; cite-driven). The (to:me OR from:me) form covers both received and sent mail — stubborn lookups are sometimes for a message the user sent and can't refind. Look at the actual returned threads — note senders, subjects, dates. Often the email is already in the top 10 results, just with a subject you wouldn't have guessed.
If Phase 1 didn't surface it, run one query per partner domain the user may have meant. Look up known partner domains for the named entity in ## Per-user partner-domain memory below. For each, format:
search_threads query="from:DOMAIN OR from:NAMED-ADDRESS" pageSize=10DOMAIN here is the bare domain (e.g. acmecorp.com), not a wildcard like *@acmecorp.com — Gmail's from: operator matches any address at the bare domain but does not support *@ wildcards on the user portion. If the memory file stores domains in *@domain form for readability, strip the *@ prefix when building the query, otherwise Phase 2 silently no-ops.
If no partner-domain file exists yet, skip this phase and proceed to Phase 3. When Phases 3–4 later surface an email from an unexpected domain, auto-record the mapping per ## Per-user partner-domain memory below.
If Phase 2 didn't surface it, list threads where the named contact appears anywhere on the message (To/CC/BCC), not just as sender:
search_threads query="DOMAIN OR NAMED-ADDRESS"Gmail q-syntax treats a bare email as an any-position match — covers from:, to:, and cc:.
If you've spotted a candidate thread (e.g. one whose subject matches a related topic, or whose participants overlap), fetch it again with messageFormat: "FULL_CONTENT" and scan ALL messages, not just the snippet on the search hit. The actual answer is often inside a thread you've already seen but truncated.
If all four phases came up empty, then ask the user for one of:
When you ask, include the actual list of senders + subjects you saw, so the user can spot the email and tell you which one.
Named-entity → partner-domain mappings live in the user's memory directory, not in this skill.
Resolve SUTANDO_MEMORY_DIR (default: $CLAUDE_CONFIG_DIR/projects/<project-id>/memory/). Look for reference_partner_domains.md, partner_domains*.md, or a ## Partner domains section in user_profile.md. If none exist, the skill remains fully functional — Phase 2 just no-ops.
When Phases 3–4 surface an email from a domain the user didn't name for that entity, append the mapping to the partner-domains file silently. Do not ask for confirmation; do not narrate the save in the reply. If the file doesn't exist, create it on first discovery. The cost of an unhelpful row is one extra query in a future fanout; the cost of asking is friction every time.
markdown--- name: partner-domains description: Named entities → associated email domains. Auto-maintained by /email-find. metadata: type: reference --- | Named entity | Associated email domains | |---|---| | Acme Corp | `acmecorp.com`, `acme-data-ops.com` | | Foo Foundation | `foo.org`, `programs@foo.org` |
Store bare domains (e.g. acmecorp.com) — Phase 2 uses them verbatim in from:DOMAIN. Specific addresses (e.g. programs@foo.org) are fine alongside bare domains. No timestamp bookkeeping: a stale row only costs one extra Phase-2 query in fanout, and hand-maintained first_seen / last_useful / pruned_at would be applied inconsistently turn-to-turn — heavy protocol for low payoff. Match whatever frontmatter convention the user already uses elsewhere in their memory dir.
A reply about Topic-X frequently rides on an existing operational thread whose subject is about something entirely different. The most common cases:
Fwd: Fwd: ...) carries the original subject forever.Implication: never subject-filter on the named entity in Phases 1–3. Subject keywords go in Phase 5 only, after the user provides them. Trust sender / recipient / date scoping; let the subjects be whatever Gmail kept on the thread.
After running the workflow, reply with:
If nothing was found after Phase 4, reply with:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-05 | pass→pass | 5,454 | 3,486 | -36% | 1 | 1 | 0% | 944 | 2,435 | +158% | 0 | 0 | — |
case-01 | fail→pass | 8,354 | 37,489 | +349% | 1 | 1 | 0% | 571 | 5,190 | +809% | 0 | 0 | — |
case-02 | fail→fail | 10,638 | 9,465 | -11% | 1 | 1 | 0% | 1,595 | 2,451 | +54% | 0 | 0 | — |
case-03 | fail→fail | 9,527 | 8,754 | -8% | 1 | 1 | 0% | 1,674 | 2,422 | +45% | 0 | 0 | — |
case-04 | pass→pass | 3,595 | 4,325 | +20% | 1 | 1 | 0% | 606 | 2,520 | +316% | 0 | 0 | — |
case-06 | pass→pass | 4,645 | 4,824 | +4% | 1 | 1 | 0% | 876 | 2,658 | +203% | 0 | 0 | — |
case-07 | fail→pass | 10,693 | 2,085 | -81% | 1 | 1 | 0% | 1,816 | 2,260 | +24% | 0 | 0 | — |
case-08 | fail→pass | 7,527 | 2,015 | -73% | 1 | 1 | 0% | 1,208 | 2,137 | +77% | 0 | 0 | — |
case-09 | fail→fail | 9,611 | 3,919 | -59% | 1 | 1 | 0% | 1,570 | 2,543 | +62% | 0 | 0 | — |
case-10 | fail→pass | 5,786 | 2,152 | -63% | 1 | 1 | 0% | 789 | 2,118 | +168% | 0 | 0 | — |
case-11 | fail→fail | 5,799 | 2,629 | -55% | 1 | 1 | 0% | 847 | 2,294 | +171% | 0 | 0 | — |
case-12 | fail→pass | 9,898 | 3,807 | -62% | 1 | 1 | 0% | 1,485 | 2,474 | +67% | 0 | 0 | — |
case-13 | pass→fail | 5,042 | 3,048 | -40% | 1 | 1 | 0% | 771 | 2,343 | +204% | 0 | 0 | — |
case-14 | pass→pass | 8,247 | 4,274 | -48% | 1 | 1 | 0% | 1,421 | 2,476 | +74% | 0 | 0 | — |
case-19 | fail→fail | 15,183 | 6,516 | -57% | 1 | 1 | 0% | 2,035 | 2,633 | +29% | 0 | 0 | — |
case-15 | fail→pass | 9,811 | 7,514 | -23% | 1 | 1 | 0% | 1,454 | 3,220 | +121% | 0 | 0 | — |
case-16 | fail→pass | 9,882 | 6,200 | -37% | 1 | 1 | 0% | 1,487 | 2,847 | +91% | 0 | 0 | — |
case-17 | fail→pass | 17,885 | 4,404 | -75% | 1 | 1 | 0% | 2,519 | 2,553 | +1% | 0 | 0 | — |
case-18 | fail→fail | 7,765 | 2,709 | -65% | 1 | 1 | 0% | 1,067 | 2,222 | +108% | 0 | 0 | — |
case-20 | pass→pass | 10,254 | 3,207 | -69% | 1 | 1 | 0% | 1,540 | 2,337 | +52% | 0 | 0 | — |
case-21 | fail→fail | 13,631 | 2,865 | -79% | 1 | 1 | 0% | 1,908 | 2,251 | +18% | 0 | 0 | — |
case-22 | pass→pass | 2,448 | 1,809 | -26% | 1 | 1 | 0% | 370 | 2,056 | +456% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 19 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +32 percentage points is the difference between those two pass rates over the 19 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.