Outlook Access Skill is an AI Agent skill (SKILL.md + CLI tool) built on the Microsoft Graph API: after a one-time OAuth authorization, an AI agent can read, search, and send emails (plain text / styled HTML), auto-organize your inbox by rules, and manage folders — all with a zero-dependency Python CLI.
Keywords: Outlook Agent Skill · AI Email Automation · Microsoft Graph API · LLM Email Tool · Outlook Mail Organizer · Inbox Zero · Email Auto-Classification
A ready-to-install skill for AI agents (Reasonix / Claude Code / Codex and any
SKILL.md-compatible agent). It ships with a generic Graph API CLI
(outlook.py) plus an agent-facing playbook (SKILL.md).
Once the user completes a one-time OAuth authorization, the agent can do anything with the mailbox — organizing is just one use case:
- 📥 Read / search emails (by sender, keyword, time)
- ✉️ Send emails (plain text / styled HTML)
- 🗂️ Auto-organize emails by rules (multi-threaded, ~500 msgs/min)
- 📁 List / manage mail folders
- 🔐 Official OAuth 2.0 device-code flow, tokens auto-refresh — no repeated logins
- 🚀 Threaded concurrency + automatic 429 backoff + network retry
| Tech | Notes |
|---|---|
| Microsoft Graph API v1.0 | Official Microsoft mail / calendar / files API |
| Python 3.7+ | Standard library only (urllib / json / concurrent.futures) — zero third-party deps |
| OAuth 2.0 Device Code | Official flow, works with personal Microsoft accounts |
| SKILL.md | Standard agent-skill format, installable into mainstream agent toolchains |
git clone https://github.com/HanHan666666/outlook-access-skill.git
cd outlook-access-skillInstall it as an agent skill (Reasonix example):
reasonix skill install ./outlook-access-skill # or copy it into your skills dir# Phase 1: initiate, returns JSON immediately (non-blocking)
python3 outlook.py authorize --json
# → {"status":"pending_user_action","verification_uri":"https://www.microsoft.com/link",
# "user_code":"XXXX","expires_in":900,"poll_hint":"python3 outlook.py authorize --poll"}
# Show the user the code/link; after they confirm in the browser:
# Phase 2: poll once — loop until status=success
python3 outlook.py authorize --poll
# → {"status":"success",...} exit 0 (or {"status":"pending",...} exit 2, retry later)Exit codes: 0 = success, 2 = pending (retry), 1 = failed/declined/expired.
Humans can also just run python3 outlook.py authorize (blocking interactive mode).
python3 outlook.py folders # list mail folders
python3 outlook.py "/me/messages?$top=10&$select=subject,from,receivedDateTime" # recent emails
python3 outlook.py stats --top 20 # inbox sender-domain stats
python3 outlook.py organize --dry-run # preview organizing plan
python3 outlook.py organize --confirm --workers 8 # run organizing| Command | Description |
|---|---|
whoami |
Show the authorized account |
authorize [--json] [--poll] |
OAuth device-code authorization (AI-friendly JSON mode) |
folders |
List mail folders and message counts |
stats [--folder inbox] [--top 30] |
Stats by sender domain |
organize --dry-run / --confirm [--workers 8] |
Preview / run rule-based organizing |
move <message_id> <folder_name> |
Move a single message |
rules |
Show active rules |
"/me/..." |
Call any Graph v1.0 path directly |
[
{"keyword": "github.com", "folder": "GitHub"},
{"keyword": "stackoverflow", "folder": "GitHub"},
{"keyword": "newsletter", "folder": "Newsletters"}
]keywordis matched as a substring of the sender domain (e.g.hsbcmatchesnotification.hsbc.com.hk)folderis the destination folder name; template: rules.example.json
Requested scopes: Mail.Read, Mail.ReadWrite, Mail.Send, User.Read,
offline_access. The token is stored in a local .outlook-token.json (gitignored).
Never commit or share it.
MIT © 2026 HanHan666666