agentsclimarketplace

Gmail attachment

Skill eprouveze/claude-skills/skills/gmail-attachment

A collection of practical Claude Code skills — multi-LLM evaluation, domain management, planning, writing quality, and pair-session patterns. MIT licensed.

Install
npx -y skills add eprouveze/claude-skills --skill gmail-attachment

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Send (or draft) a Gmail message with one or more file attachments via the google-workspace MCP. Use whenever the user asks to email a file, attach a document, send a PDF / markdown / spreadsheet by mail. Trigger phrases — "email this file to X", "send by mail with the doc attached", "envoie ce fichier par mail", "joindre en pièce jointe". The MCP's documented `path` field is sandboxed and silently fails on host paths; this skill enforces the only working route (base64 `content` + `filename`) and documents the size envelope.

SKILL.md

10.1 KB, as published. Nobody here has run it

gmail-attachment — Send Gmail with attachments via google-workspace MCP

Why this skill exists

The google-workspace MCP runs in its own filesystem sandbox (typically /app/app/external/servers/). The attachments parameter accepts two shapes:

ShapeStatusWhy
{path: "/Users/.../file.pdf"}❌ Always failsThe MCP looks for the path inside its sandbox. Host paths don't exist there. The error message ("Path does not exist") is misleading because the path does exist — just not where the MCP can see it. Copying to /tmp doesn't help — /tmp isn't shared either. Project-relative paths fail too.
{content: "<base64>", filename: "..."}✅ WorksContent is sent inline; the MCP doesn't need to read host disk.

Without this skill, the natural reflex is to pass path (it's the documented field). It always fails, and the failure mode is misleading. This skill enforces the working route and documents the practical size envelope so you don't paste 80 KB of base64 into a tool call and watch it get truncated.

When to use

Trigger on any request that involves emailing a file:

  • "email this PDF to [email protected]"
  • "envoie ce fichier par mail à Y"
  • "send the report as an attachment"
  • "draft an email with the doc attached"

Use this skill before reaching for mcp__google-workspace__send_gmail_message or mcp__google-workspace__draft_gmail_message directly when an attachment is involved.

Do NOT use for: emails without attachments, attaching Drive files (use sharing instead), attaching content the user pasted inline (no file involved).

The procedure

1. Confirm intent

Before sending, confirm:

  • Recipient address(es)
  • Subject and body (or have the user provide them)
  • File(s) to attach — get absolute host path(s)
  • from_name if the message should appear from a persona

For irreversible actions (send vs draft), default to draft unless the user explicitly said "send". Show the prepared call before executing.

2. Encode each file to base64

base64 -i "<absolute-host-path>" | tr -d '\n' > /tmp/__attach_<slug>.b64
wc -c /tmp/__attach_<slug>.b64    # sanity-check size

tr -d '\n' strips the line wrapping that base64 adds by default — Gmail rejects wrapped base64 inside JSON.

3. Read the encoded content into context

Use the Read tool on the .b64 file. The Read tool returns the full content on one line with a 1\t line-number prefix that you must strip (the actual content starts after the tab character).

Size envelope. The base64 is ~1.37× the original size. The reliable ceiling is much lower than you'd think — empirically, a 34.5 KB encoded payload timed out mid-call ("API Error: The operation timed out"). Plan conservatively.

Original file sizeEncoded sizeRecommendation
≤ 15 KB≤ 20 KBInline content works reliably
15–30 KB20–40 KBInline content may time out — verify by checking sent mail
> 30 KB> 40 KBDon't try inline. Use the draft-and-attach-manually escape hatch (below) or share via Drive

Escape hatch — compose manually in Gmail web UI

When the file is too large for reliable inline send:

  1. Hand the user the prepared message: To, Subject, Body, attachment host path.
  2. Tell them to compose in Gmail web UI and attach the file there.
  3. Done. Costs ~30 seconds, avoids both the timeout and the truncation trap.

Note. The current google-workspace MCP exposes only mcp__google-workspace__send_gmail_message — there is no draft_gmail_message. So the previously-imagined "MCP-draft + manual attach" route does not work; full-manual compose is the actual escape hatch. Verified by attempting draft_gmail_message and getting "No such tool available".

This is often the right choice even when inline would work, because it keeps the human in the loop on the irreversible action (the actual send).

4. Build and execute the MCP call

mcp__google-workspace__send_gmail_message(
  to = "...",
  subject = "...",
  body = "...",
  from_name = "...",                     # optional, persona
  attachments = [{
    "filename":  "<original-filename-with-extension>",
    "content":   "<full base64 string, no line-number prefix, no wrapping>",
    "mime_type": "<correct mime>"        # see table below
  }]
)

No drafts in this MCP. The current google-workspace MCP version exposes only send_gmail_message. If you want a draft, use the manual-compose escape hatch above (the user composes in Gmail web UI directly).

5. Verify

After execution, check the returned message ID. If sending a corrected version of an earlier message, mention that the previous one should be ignored. For high-stakes sends, search sent mail to confirm delivery and, where possible, ask the recipient to confirm the attachment opened.

MIME type cheat sheet

ExtensionMIME
.pdfapplication/pdf
.mdtext/markdown
.txttext/plain
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.csvtext/csv
.pngimage/png
.jpg / .jpegimage/jpeg
.zipapplication/zip
(unknown)application/octet-stream

Multi-file pattern

Encode each file separately, then combine into the array:

attachments = [
  {"filename": "report.pdf", "content": "<b64-1>", "mime_type": "application/pdf"},
  {"filename": "data.csv",   "content": "<b64-2>", "mime_type": "text/csv"},
]

Don't zip silently — the user expects discrete files.

Known gotchas

  • The path field is a trap. It is documented in the MCP schema but always fails for host files. Treat it as nonexistent.
  • base64 macOS default wraps lines at 76 chars. Without tr -d '\n', the JSON-side base64 is invalid and the Gmail API rejects the attachment. Always strip newlines.
  • Read tool prefix. The tool prepends <line-number>\t to every line of file output. When you copy the content into a tool call, you must drop that prefix. Including it produces invalid base64 and the email gets sent with a corrupt attachment — silently.
  • Tool-call truncation by you, not the MCP. Above ~80 KB of inline content, the model is tempted to "summarize" or "truncate for safety". This is the most common failure mode. If the original file is large, draft rather than send, or share via Drive.

Anti-patterns

  • ❌ Falling back to path after a content failure. The MCP fails again the same way; you've just doubled the spend.
  • ❌ Pasting "<full base64 here, ~26 KB, omitted>" or any other placeholder into the content field. The recipient receives a truncated/garbled file. This actually happened in early use — the cost is a follow-up "correction" email and a small loss of credibility.
  • ❌ Using URL-safe base64 (-_ alphabet). The MCP expects standard base64. base64 -i on macOS produces standard.
  • ❌ Mixing path and content in the same attachment object. Pick one (always content).
  • Treating osascript exit true as "delivered". AppleScript Mail.app returns true from a successful send call, but that only means the script ran — the message may sit in Outbox indefinitely if the account auth is stale, the network is offline, or some other silent Mail.app condition fires. Verify by checking sent mail (or asking the user) before claiming success. Same general principle applies to any fire-and-forget send mechanism.
  • Sending from a personal account out of a work environment. When operating in a work session (e.g., Salesforce-managed laptop), do not propose AppleScript Mail.app routes that would send via a personal iCloud / Gmail / etc. account. Even when the recipient is the operator themselves, mixing personal-account egress with work-context content is a mandate-vs-campagne-style boundary violation. If the only Mail.app account configured is personal, that route is disqualified for work content — fall back to the manual-compose escape hatch in the work webmail.

Validated patterns

  • Encode → Read → Inline content. Verified via a successful send of a ~26 KB Markdown file that returned a Gmail message ID and arrived intact.
  • Failure recovery flow when the first send went out with a truncated attachment: send a brief follow-up titled "Correction — <original subject>", open with one line asking the recipient to ignore the previous mail, attach the correct file via this skill.
  • Persona sending via from_name = "Lex (pour Emmanuel Prouveze)" works as expected — the recipient sees the persona, replies route to the authenticated account.

Self-improvement

Append observations to learnings.md whenever:

  • A new MIME type is encountered
  • The size envelope shifts (different model, different runtime)
  • A new failure mode appears (e.g., unicode filenames, multi-recipient quirks)
  • The MCP schema changes

Consolidate weekly, or when learnings.md crosses ~100 bullets. On consolidation, each entry gets one of: apply (promote into the SKILL body), capture (keep in the log), dismiss.

See also

  • For Drive sharing instead of attaching: mcp__google-workspace__manage_drive_access.
  • For inline images in HTML body: not currently supported by the google-workspace MCP. Use a Drive link.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.