关于 email-agent
通过 Atris CLI 和 API 管理 Gmail 的 Claude Code 技能,支持处理邮件和草稿,并要求发送或归档前先获批准。
主要功能
- 01搜索和读取 Gmail 邮件
- 02发送邮件及在线程中回复
- 03创建和管理草稿
- 04标记、归档和移至垃圾箱
- 05发送与归档前征求批准
- 06初始化与连接故障排查
适用场景
- 01查看近期或未读收件箱邮件
- 02准备回复并等待批准
- 03保存并发送草稿
- 04经确认后整理邮件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ atrislabs/ atris --skill email-agent安装后在 Claude Code 中输入/email-agent确认已加载。
详细介绍
邮件 Agent
将此文件放入
~/.claude/skills/email-agent/SKILL.md,Claude Code 就会成为你的邮件助手。
初始化(务必先运行)
执行任何邮件操作前,先运行此初始化脚本,确保一切准备就绪:
#!/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"
重要:邮件操作前只需运行此脚本一次。如果脚本退出时给出了操作说明,请按说明操作,然后再次运行。
API 参考
基础 URL:https://api.atris.ai/api/integrations/gmail
所有请求都需要:-H "Authorization: Bearer $TOKEN"
获取令牌(初始化后)
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
列出邮件
curl -s "https://api.atris.ai/api/integrations/gmail/messages?query=in:inbox&max_results=20" \
-H "Authorization: Bearer $TOKEN"
查询语法(Gmail 搜索):
in:inbox— 仅收件箱in:inbox newer_than:1d— 今天的邮件is:unread— 仅未读邮件from:[email protected]— 来自特定发件人的邮件subject:invoice— 主题包含指定词语has:attachment— 带附件的邮件
阅读单封邮件
curl -s "https://api.atris.ai/api/integrations/gmail/messages/{message_id}" \
-H "Authorization: Bearer $TOKEN"
发送邮件
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Subject line",
"body": "Email body text"
}'
添加抄送/密送:
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"cc": "[email protected]",
"bcc": ["[email protected]", "[email protected]"],
"subject": "Subject line",
"body": "Email body text"
}'
在邮件会话中回复(重要——所有回复都使用此方式):
要在现有邮件会话中回复,必须传入 thread_id 和 reply_to_message_id。否则,Gmail 会创建新的会话。
# 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": "[email protected]",
"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— 原始邮件的会话 ID。告知 Gmail 将邮件添加到哪个会话。reply_to_message_id— 你要回复的邮件 ID。后端会用它设置In-Reply-To和References标头,让 Gmail 正确归入同一会话。subject— 必须与原主题一致,并添加 "Re: " 前缀。
添加附件:
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "With attachment",
"body": "See attached.",
"attachments": [{"filename": "report.txt", "content": "base64-encoded-content", "mime_type": "text/plain"}]
}'
草稿
列出草稿:
curl -s "https://api.atris.ai/api/integrations/gmail/drafts?max_results=20" \
-H "Authorization: Bearer $TOKEN"
阅读草稿:
curl -s "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}" \
-H "Authorization: Bearer $TOKEN"
创建草稿:
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Subject line",
"body": "Draft body text"
}'
支持与发送邮件相同的字段:cc、bcc、attachments,以及用于关联到现有会话的 thread_id。
更新草稿:
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": "[email protected]",
"subject": "Updated subject",
"body": "Updated body"
}'
发送草稿:
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}/send" \
-H "Authorization: Bearer $TOKEN"
删除草稿:
curl -s -X DELETE "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}" \
-H "Authorization: Bearer $TOKEN"
标记为已读/未读
# 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"
归档邮件
# 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"]}'
将邮件移至垃圾箱
# 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"]}'
检查状态
curl -s "https://api.atris.ai/api/integrations/gmail/status" \
-H "Authorization: Bearer $TOKEN"
断开 Gmail
curl -s -X DELETE "https://api.atris.ai/api/integrations/gmail" \
-H "Authorization: Bearer $TOKEN"
工作流
“检查我的邮件”
- 运行初始化脚本
- 列出邮件:
GET /messages?query=in:inbox%20newer_than:1d&max_results=20 - 显示每封邮件的发件人、主题和摘要
“给 X 发一封关于 Y 的邮件”
- 运行初始化脚本
- 起草邮件内容
- 向用户展示草稿以供审批
- 获得批准后:使用
{to, subject, body}调用POST /send - 确认:“邮件已发送!”
“回复这封邮件”
- 运行初始化脚本
- 阅读邮件:
GET /messages/{message_id}— 提取id、thread_id、from、subject - 起草回复内容
- 向用户展示回复以供审批
- 获得批准后:使用
{to, subject: "Re: ...", body, thread_id, reply_to_message_id}调用POST /send - 验证:响应中的
thread_id与原始thread_id相同(若不同,则表示出现问题)
“整理我的收件箱”
- 运行初始化脚本
- 列出邮件:
GET /messages?query=in:inbox&max_results=50 - 找出可归档的邮件(见下方规则)
- 向用户展示将要归档的邮件,并征求批准
- 批量归档:
POST /batch-archive
“显示我的草稿”
- 运行初始化脚本
- 列出草稿:
GET /gmail/drafts?max_results=20 - 显示每封草稿的收件人、主题和摘要
“起草一封给 X 的关于 Y 的邮件”
- 运行初始化脚本
- 撰写邮件内容
- 向用户展示草稿以供审核
- 获得批准后:使用
{to, subject, body}调用POST /gmail/drafts - 确认:“草稿已保存!你可以在 Gmail 中找到它。”
“发送关于 X 的草稿”
- 运行初始化脚本
- 列出草稿:
GET /gmail/drafts - 按主题/收件人查找匹配的草稿
- 向用户展示草稿内容,并确认是否要发送
- 发送:
POST /gmail/drafts/{draft_id}/send
“归档所有来自 [发件人] 的邮件”
- 运行初始化脚本
- 搜索:
GET /messages?query=from:{sender} - 收集邮件 ID
- 向用户确认:“找到来自 {sender} 的 N 封邮件。全部归档吗?”
- 批量归档
自动归档规则
可以安全地建议归档:
- 发件人:
noreply@、notifications@、newsletter@、no-reply@ - 主题包含:摘要、新闻简报、通知、每周更新、每日摘要
- 营销邮件:促销内容,且包含退订链接
绝不自动归档(始终保留):
- 主题包含:发票、收据、付款、紧急、需要采取行动、密码、验证、安全
- 来自已知联系人的邮件(检查用户是否回复过对方)
- 已加旗标或星标的邮件
归档前始终询问。 未经用户明确批准,绝不归档。
错误处理
| 错误 | 含义 | 解决方案 |
|---|---|---|
Token expired | AtrisOS 会话已过期 | 运行 atris login |
Gmail not connected | 尚未完成 OAuth | 重新运行 bootstrap,完成 OAuth 流程 |
401 Unauthorized | 令牌无效或已过期 | 运行 atris login |
400 Gmail not connected | 没有 Gmail 凭据 | 通过 bootstrap 完成 OAuth |
429 Rate limited | 请求过多 | 等待 60s 后重试 |
Invalid grant | Google 已撤销访问权限 | 通过 bootstrap 重新连接 Gmail |
安全模型
-
本地令牌(
~/.atris/credentials.json):你的 AtrisOS 身份验证令牌,以 600 权限存储在本地。与 AWS CLI、GitHub CLI 使用相同的模型。 -
Gmail 凭据:你的 Gmail 刷新令牌存储在 AtrisOS 加密保管库的服务端。绝不会存储在本地计算机上。
-
访问控制:AtrisOS API 确保你只能访问自己的电子邮件。无法跨用户访问。
-
OAuth 权限范围:仅请求必要的 Gmail 权限(读取、发送、修改标签)。
-
仅使用 HTTPS:所有 API 通信均在传输过程中加密。
快速参考
# 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 protected]","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":"[email protected]","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 protected]","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"