email-agent

Drop this in ~/.claude/skills/email-agent/SKILL.md and Claude Code becomes your email assistant.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "email-agent" with this command: npx skills add atrislabs/atris/atrislabs-atris-email-agent

Email Agent

Drop this in ~/.claude/skills/email-agent/SKILL.md and Claude Code becomes your email assistant.

Bootstrap (ALWAYS Run First)

Before any email operation, run this bootstrap to ensure everything is set up:

#!/bin/bash set -e

1. Check if atris CLI is installed

if ! command -v atris &> /dev/null; then echo "Installing atris CLI..." npm install -g atris fi

2. Check if logged in to AtrisOS

if [ ! -f ~/.atris/credentials.json ]; then echo "Not logged in to AtrisOS." echo "" echo "Option 1 (interactive): Run 'atris login' and follow prompts" echo "Option 2 (non-interactive): Get token from https://atris.ai/auth/cli" echo " Then run: atris login --token YOUR_TOKEN" echo "" exit 1 fi

3. Extract token (try node first, then python3, then jq)

if command -v node &> /dev/null; then TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)") elif command -v python3 &> /dev/null; then TOKEN=$(python3 -c "import json,os; print(json.load(open(os.path.expanduser('~/.atris/credentials.json')))['token'])") elif command -v jq &> /dev/null; then TOKEN=$(jq -r '.token' ~/.atris/credentials.json) else echo "Error: Need node, python3, or jq to read credentials" exit 1 fi

4. Check Gmail connection status (also validates token)

STATUS=$(curl -s "https://api.atris.ai/api/integrations/gmail/status"
-H "Authorization: Bearer $TOKEN")

Check for token expiry

if echo "$STATUS" | grep -q "Token expired|Not authenticated"; then echo "Token expired. Please re-authenticate:" echo " Run: atris login --force" echo " Or get new token from: https://atris.ai/auth/cli" exit 1 fi

Parse connected status

if command -v node &> /dev/null; then CONNECTED=$(node -e "console.log(JSON.parse('$STATUS').connected || false)") elif command -v python3 &> /dev/null; then CONNECTED=$(echo "$STATUS" | python3 -c "import sys,json; print(json.load(sys.stdin).get('connected', False))") else CONNECTED=$(echo "$STATUS" | jq -r '.connected // false') fi

if [ "$CONNECTED" != "true" ] && [ "$CONNECTED" != "True" ]; then echo "Gmail not connected. Getting authorization URL..." AUTH=$(curl -s -X POST "https://api.atris.ai/api/integrations/gmail/start"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{}')

if command -v node &> /dev/null; then URL=$(node -e "console.log(JSON.parse('$AUTH').auth_url || '')") elif command -v python3 &> /dev/null; then URL=$(echo "$AUTH" | python3 -c "import sys,json; print(json.load(sys.stdin).get('auth_url', ''))") else URL=$(echo "$AUTH" | jq -r '.auth_url // empty') fi

echo "" echo "Open this URL to connect your Gmail:" echo "$URL" echo "" echo "After authorizing, run your email command again." exit 0 fi

echo "Ready. Gmail is connected." export ATRIS_TOKEN="$TOKEN"

Important: Run this script ONCE before email operations. If it exits with instructions, follow them, then run again.

API Reference

Base: https://api.atris.ai/api/integrations/gmail

All requests require: -H "Authorization: Bearer $TOKEN"

Get Token (after bootstrap)

TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")

List Emails

curl -s "https://api.atris.ai/api/integrations/gmail/messages?query=in:inbox&max_results=20"
-H "Authorization: Bearer $TOKEN"

Query syntax (Gmail search):

  • in:inbox — inbox only

  • in:inbox newer_than:1d — today's emails

  • is:unread — unread only

  • from:someone@example.com — from specific sender

  • subject:invoice — subject contains word

  • has:attachment — emails with attachments

Read Single Email

curl -s "https://api.atris.ai/api/integrations/gmail/messages/{message_id}"
-H "Authorization: Bearer $TOKEN"

Send Email

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{ "to": "recipient@example.com", "subject": "Subject line", "body": "Email body text" }'

With CC/BCC:

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{ "to": "recipient@example.com", "cc": "copy@example.com", "bcc": ["hidden1@example.com", "hidden2@example.com"], "subject": "Subject line", "body": "Email body text" }'

Reply in thread (IMPORTANT — use this for all replies):

To reply within an existing email thread, you MUST pass thread_id and reply_to_message_id . Without these, Gmail creates a new thread.

1. First, get the message you're replying to (extract thread_id and id)

curl -s "https://api.atris.ai/api/integrations/gmail/messages/{message_id}"
-H "Authorization: Bearer $TOKEN"

Response includes: id, thread_id, subject, from, etc.

2. Send reply in the same thread

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{ "to": "original-sender@example.com", "subject": "Re: Original Subject", "body": "Your reply text here", "thread_id": "THREAD_ID_FROM_STEP_1", "reply_to_message_id": "MESSAGE_ID_FROM_STEP_1" }'

  • thread_id — The thread ID from the original message. Tells Gmail which thread to add this to.

  • reply_to_message_id — The message ID you're replying to. The backend uses this to set In-Reply-To and References headers so Gmail threads it correctly.

  • subject — Must match the original subject with "Re: " prefix.

With attachments:

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{ "to": "recipient@example.com", "subject": "With attachment", "body": "See attached.", "attachments": [{"filename": "report.txt", "content": "base64-encoded-content", "mime_type": "text/plain"}] }'

Drafts

List drafts:

curl -s "https://api.atris.ai/api/integrations/gmail/drafts?max_results=20"
-H "Authorization: Bearer $TOKEN"

Read a draft:

curl -s "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}"
-H "Authorization: Bearer $TOKEN"

Create a draft:

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{ "to": "recipient@example.com", "subject": "Subject line", "body": "Draft body text" }'

Supports same fields as send: cc , bcc , attachments , plus thread_id to attach to an existing thread.

Update a draft:

curl -s -X PUT "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{ "to": "recipient@example.com", "subject": "Updated subject", "body": "Updated body" }'

Send a draft:

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}/send"
-H "Authorization: Bearer $TOKEN"

Delete a draft:

curl -s -X DELETE "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}"
-H "Authorization: Bearer $TOKEN"

Mark as Read / Unread

Mark as read

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/read"
-H "Authorization: Bearer $TOKEN"

Mark as unread

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/unread"
-H "Authorization: Bearer $TOKEN"

Archive Email

Single message

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/archive"
-H "Authorization: Bearer $TOKEN"

Batch archive

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/batch-archive"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"message_ids": ["id1", "id2", "id3"]}'

Trash Email

Single message

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/trash"
-H "Authorization: Bearer $TOKEN"

Batch trash

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/batch-trash"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"message_ids": ["id1", "id2", "id3"]}'

Check Status

curl -s "https://api.atris.ai/api/integrations/gmail/status"
-H "Authorization: Bearer $TOKEN"

Disconnect Gmail

curl -s -X DELETE "https://api.atris.ai/api/integrations/gmail"
-H "Authorization: Bearer $TOKEN"

Workflows

"Check my emails"

  • Run bootstrap

  • List messages: GET /messages?query=in:inbox%20newer_than:1d&max_results=20

  • Display: sender, subject, snippet for each

"Send email to X about Y"

  • Run bootstrap

  • Draft email content

  • Show user the draft for approval

  • On approval: POST /send with {to, subject, body}

  • Confirm: "Email sent!"

"Reply to this email"

  • Run bootstrap

  • Read the message: GET /messages/{message_id} — extract id , thread_id , from , subject

  • Draft reply content

  • Show user the reply for approval

  • On approval: POST /send with {to, subject: "Re: ...", body, thread_id, reply_to_message_id}

  • Verify: response thread_id matches original thread_id (if it doesn't, something went wrong)

"Clean up my inbox"

  • Run bootstrap

  • List: GET /messages?query=in:inbox&max_results=50

  • Identify archivable emails (see rules below)

  • Show user what will be archived, get approval

  • Batch archive: POST /batch-archive

"Show my drafts"

  • Run bootstrap

  • List drafts: GET /gmail/drafts?max_results=20

  • Display: to, subject, snippet for each

"Draft an email to X about Y"

  • Run bootstrap

  • Compose email content

  • Show user the draft for review

  • On approval: POST /gmail/drafts with {to, subject, body}

  • Confirm: "Draft saved! You can find it in Gmail."

"Send draft about X"

  • Run bootstrap

  • List drafts: GET /gmail/drafts

  • Find matching draft by subject/recipient

  • Show user the draft content, confirm they want to send it

  • Send: POST /gmail/drafts/{draft_id}/send

"Archive all from [sender]"

  • Run bootstrap

  • Search: GET /messages?query=from:{sender}

  • Collect message IDs

  • Confirm with user: "Found N emails from {sender}. Archive all?"

  • Batch archive

Auto-Archive Rules

Safe to suggest archiving:

  • From: noreply@ , notifications@ , newsletter@ , no-reply@

  • Subject contains: digest, newsletter, notification, weekly update, daily summary

  • Marketing: promotional, unsubscribe link present

NEVER auto-archive (always keep):

  • Subject contains: invoice, receipt, payment, urgent, action required, password, verification, security

  • From known contacts (check if user has replied to them)

  • Flagged/starred messages

Always ask before archiving. Never archive without explicit user approval.

Error Handling

Error Meaning Solution

Token expired

AtrisOS session expired Run atris login

Gmail not connected

OAuth not completed Re-run bootstrap, complete OAuth flow

401 Unauthorized

Invalid/expired token Run atris login

400 Gmail not connected

No Gmail credentials Complete OAuth via bootstrap

429 Rate limited

Too many requests Wait 60s, retry

Invalid grant

Google revoked access Re-connect Gmail via bootstrap

Security Model

Local token (~/.atris/credentials.json ): Your AtrisOS auth token, stored locally with 600 permissions. Same model as AWS CLI, GitHub CLI.

Gmail credentials: Your Gmail refresh token is stored server-side in AtrisOS encrypted vault. Never stored on your local machine.

Access control: AtrisOS API enforces that you can only access your own email. No cross-user access possible.

OAuth scopes: Only requests necessary Gmail permissions (read, send, modify labels).

HTTPS only: All API communication encrypted in transit.

Quick Reference

Setup (one time)

npm install -g atris && atris login

Get token

TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")

Check connection

curl -s "https://api.atris.ai/api/integrations/gmail/status" -H "Authorization: Bearer $TOKEN"

List inbox

curl -s "https://api.atris.ai/api/integrations/gmail/messages?query=in:inbox&max_results=10" -H "Authorization: Bearer $TOKEN"

Send new email

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send"
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"
-d '{"to":"email@example.com","subject":"Hi","body":"Hello!"}'

Reply in thread (pass thread_id + reply_to_message_id)

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send"
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"
-d '{"to":"sender@example.com","subject":"Re: Original","body":"Reply text","thread_id":"THREAD_ID","reply_to_message_id":"MSG_ID"}'

List drafts

curl -s "https://api.atris.ai/api/integrations/gmail/drafts" -H "Authorization: Bearer $TOKEN"

Create draft

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts"
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"
-d '{"to":"email@example.com","subject":"Hi","body":"Draft text"}'

Mark as read

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/read" -H "Authorization: Bearer $TOKEN"

Trash an email

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/trash" -H "Authorization: Bearer $TOKEN"

Send a draft

curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}/send"
-H "Authorization: Bearer $TOKEN"

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

meta

No summary provided by upstream source.

Repository SourceNeeds Review
General

autopilot

No summary provided by upstream source.

Repository SourceNeeds Review
General

copy-editor

No summary provided by upstream source.

Repository SourceNeeds Review