utoronto-outlook

Headless University of Toronto Outlook email access via IMAP/SMTP with OAuth2. Uses Thunderbird's pre-authorized client ID to bypass admin consent requirements (AADSTS65002). Device code flow for initial auth, macOS Keychain for token cache.

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 "utoronto-outlook" with this command: npx skills add plurigrid/asi/plurigrid-asi-utoronto-outlook

UofT Outlook Skill

Headless access to University of Toronto alumni/student Outlook via IMAP/SMTP with OAuth2.

Trit: -1 (MINUS - validator/consumer)
Principle: Thunderbird Client ID → Device Code Auth → Keychain Cache → IMAP/SMTP
Implementation: IMAP OAuth2 (XOAUTH2) + Thunderbird Pre-Authorized Client ID

The AADSTS65002 Problem

University tenants block third-party OAuth apps:

AADSTS65002: Consent between first party application and first party resource 
must be configured via preauthorization

Solution: Use Thunderbird's pre-authorized client ID 9e5f94bc-e8a4-4e73-b8be-63364c29d753 which Microsoft has pre-approved for IMAP/SMTP access on all tenants.

Authentication Architecture

┌─────────────────────────────────────────────────────────────────────┐
│               THUNDERBIRD CLIENT ID BYPASS                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  [Problem: Graph API blocked]                                       │
│  ┌──────────┐     Graph API      ┌───────────────┐                 │
│  │  Agent   │ ────────────────▶  │ MS Entra ID   │                 │
│  └──────────┘                    └───────────────┘                 │
│       │                                 │                           │
│       │                                 ▼                           │
│       │                    ❌ AADSTS65002 Error                     │
│       │                    "Admin consent required"                 │
│                                                                     │
│  [Solution: Thunderbird IMAP]                                       │
│  ┌──────────┐  Thunderbird ID    ┌───────────────┐                 │
│  │  Agent   │ ─────────────────▶ │ MS Entra ID   │                 │
│  └──────────┘  9e5f94bc-...      └───────────────┘                 │
│       │                                 │                           │
│       │ Device code flow                │ Pre-authorized ✓         │
│       ▼                                 ▼                           │
│  "Enter code XXXXXX at microsoft.com/devicelogin"                  │
│       │                                                             │
│       │ User authenticates (one-time)                               │
│       ▼                                                             │
│  ┌──────────────────────────────────────────────────┐              │
│  │           macOS Keychain (secure storage)        │              │
│  │  outlook-university: access + refresh tokens    │              │
│  └──────────────────────────────────────────────────┘              │
│       │                                                             │
│       │ XOAUTH2 authentication                                      │
│       ▼                                                             │
│  ┌───────────────────────────────────────────────┐                 │
│  │  outlook.office365.com:993 (IMAP)             │                 │
│  │  smtp.office365.com:587 (SMTP)                │                 │
│  └───────────────────────────────────────────────┘                 │
└─────────────────────────────────────────────────────────────────────┘

Key Constants

# Thunderbird's pre-authorized client ID (public, safe to commit)
THUNDERBIRD_CLIENT_ID = "9e5f94bc-e8a4-4e73-b8be-63364c29d753"

# IMAP OAuth2 scopes (NOT Graph API scopes!)
IMAP_SCOPES = [
    "https://outlook.office.com/IMAP.AccessAsUser.All",
    "https://outlook.office.com/SMTP.Send",
    "offline_access",
    "openid", "profile", "email"
]

# Servers
IMAP_SERVER = "outlook.office365.com"  # Port 993 SSL
SMTP_SERVER = "smtp.office365.com"      # Port 587 STARTTLS

Usage

Initial Authentication (One-Time)

cd ~/.claude/skills/utoronto-outlook
uv run python outlook_university.py auth

# Output:
# ============================================================
# OUTLOOK UNIVERSITY - DEVICE CODE AUTHENTICATION
# ============================================================
#   Code: XXXXXXXXX
#   Go to: https://microsoft.com/devicelogin
#   (Uses Thunderbird's pre-authorized client ID)
# ============================================================

Headless Operations

# Check login
uv run python outlook_university.py whoami
# Logged in as: yulia.zubak@alumni.utoronto.ca

# List messages
uv run python outlook_university.py list 10

# Read message
uv run python outlook_university.py read 42

# Search
uv run python outlook_university.py search "professor"

# List folders
uv run python outlook_university.py folders

Python API

from outlook_university import OutlookClient

client = OutlookClient()

# List recent emails
messages = client.list_messages(limit=10)

# Get unread
unread = client.get_unread()

# Read full message (body truncated to 2000 chars for context safety)
msg = client.get_message("42")

# Search
results = client.search("grades")

# Send email
client.send(
    to=["recipient@example.com"],
    subject="Test",
    body="Hello from headless Outlook!"
)

client.close()

XOAUTH2 Authentication

The critical implementation detail for IMAP OAuth2:

# Build XOAUTH2 string per RFC 7628
auth_string = f"user={email}\x01auth=Bearer {access_token}\x01\x01"

# IMAP authenticate callback returns raw bytes
conn.authenticate("XOAUTH2", lambda x: auth_string.encode())

GF(3) Verb Typing

OperationTritDescription
list_messages-1Consume/read inbox (MINUS)
get_message-1Read specific message (MINUS)
get_unread-1Query unread (MINUS)
search-1Query messages (MINUS)
list_folders0Metadata access (ERGODIC)
send+1Generate output (PLUS)

Security Notes

  • Thunderbird Client ID: Public, safe to commit (used by Mozilla Thunderbird)
  • Tokens: Stored in macOS Keychain (encrypted), never in files
  • Body Truncation: Email bodies truncated to 2000 chars to prevent context overflow
  • No Credentials: No passwords stored; OAuth2 refresh tokens only
  • Terminal Sanitization: ANSI escape codes stripped from output

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.

Web3

aptos-wallet-mcp

No summary provided by upstream source.

Repository SourceNeeds Review
Research

academic-research

No summary provided by upstream source.

Repository SourceNeeds Review
General

alife

No summary provided by upstream source.

Repository SourceNeeds Review
General

asi-integrated

No summary provided by upstream source.

Repository SourceNeeds Review