Agent Skills: Gmail fetch

Fetch recent emails from Gmail with sender, subject, body, and thread context

UncategorizedID: sofer/.agents/gmail-fetch

Install this agent skill to your local

pnpm dlx add-skill https://github.com/sofer/.agents/tree/HEAD/skills/gmail-fetch

Skill Files

Browse the full folder contents for gmail-fetch.

Download Skill

Loading file tree…

skills/gmail-fetch/SKILL.md

Skill Metadata

Name
"gmail-fetch"
Description
"Fetch recent emails from Gmail with sender, subject, body, and thread context"

Gmail fetch

Purpose

Fetch emails from Gmail so that other skills (particularly the email drafter twin) can work with inbox data. This skill is read-only; it never modifies, sends, or deletes emails.

Prerequisites

This skill uses the Gmail API via existing OAuth credentials at ~/code/airmail/. The following files must exist:

  • ~/code/airmail/client_secret.json — Google OAuth client credentials
  • ~/code/airmail/gmail_token.json — OAuth token (auto-refreshes)

Instructions

1. Authenticate with Gmail

Load the OAuth credentials and build a Gmail API client:

from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
from googleapiclient.discovery import build

TOKEN_FILE = os.path.expanduser("~/code/airmail/gmail_token.json")
CLIENT_SECRET = os.path.expanduser("~/code/airmail/client_secret.json")

creds = Credentials.from_authorized_user_file(TOKEN_FILE)
if creds.expired and creds.refresh_token:
    creds.refresh(Request())
    with open(TOKEN_FILE, "w") as f:
        f.write(creds.to_json())

service = build("gmail", "v1", credentials=creds)

If the token file is missing, stop and report:

"Gmail token not found at ~/code/airmail/gmail_token.json. Run the OAuth flow in the airmail project first."

If authentication fails after refresh, stop and report:

"Gmail authentication failed. The token may be expired or revoked. Re-authenticate in ~/code/airmail/."

2. Parse the input parameters

Accept the following optional parameters. Apply defaults where not provided:

| Parameter | Default | Description | |---|---|---| | query | is:unread | Gmail search query (same syntax as the Gmail search bar) | | max_results | 20 | Maximum number of emails to return | | include_threads | true | Whether to fetch prior messages in each thread |

3. Fetch emails

  1. List messages:

    results = service.users().messages().list(
        userId="me", q=query, maxResults=max_results
    ).execute()
    messages = results.get("messages", [])
    
  2. For each message ID returned, fetch full details:

    msg = service.users().messages().get(
        userId="me", id=msg_id, format="full"
    ).execute()
    
  3. If include_threads is true, fetch the thread:

    thread = service.users().threads().get(
        userId="me", id=thread_id, format="full"
    ).execute()
    

4. Normalise the results

For each email, extract and normalise:

  • id: Gmail message ID
  • thread_id: Gmail thread ID
  • from: Sender name and email (from the From header)
  • to: Recipient addresses (from the To header)
  • cc: CC addresses (from the Cc header, if present)
  • subject: Subject line (from the Subject header)
  • body: Email body as plain text. If the email has a text/plain part, use it. If it only has text/html, strip the HTML tags to produce plain text. Truncate to 10,000 characters if longer, appending "[truncated]".
  • date: Date sent (from the Date header), formatted as ISO 8601
  • labels: Gmail labels (e.g. INBOX, UNREAD, IMPORTANT)
  • snippet: Short preview of the body (first 200 characters)

If include_threads is true, for each thread include up to 10 of the most recent prior messages (excluding the current message) with:

  • id: Message ID
  • from: Sender
  • date: Date sent (ISO 8601)
  • body: Plain text body (truncated to 5,000 characters if longer)

5. Return the output

Present the results as a structured list of emails ordered by date (most recent first), along with:

  • result_count: Number of emails returned
  • query_used: The Gmail query that was executed

Error handling

  • Token file missing: Stop and report: "Gmail token not found at ~/code/airmail/gmail_token.json"
  • Authentication failure (401 or 403): Stop and report: "Gmail authentication failed. Re-authenticate in ~/code/airmail/."
  • Rate limit exceeded (429): Stop and report: "Gmail API rate limit exceeded. Wait a few minutes before retrying."
  • No results: Not an error. Return an empty list with result_count of 0.

Output format

result_count: 3
query_used: "is:unread"
emails:
  - id: "msg_abc123"
    thread_id: "thread_xyz789"
    from: "Alice Smith <alice@example.com>"
    to: ["user@example.com"]
    cc: []
    subject: "Re: Partnership proposal"
    body: "Hi, thanks for sending over the details..."
    date: "2026-02-25T09:30:00Z"
    labels: ["INBOX", "UNREAD"]
    snippet: "Hi, thanks for sending over the details..."
    thread_messages:
      - id: "msg_prev456"
        from: "user@example.com"
        date: "2026-02-24T16:00:00Z"
        body: "Hi Alice, please find attached..."