# Outlook Plugin — Operator Guide

The `outlook` plugin gives the admin agent read-only access to Microsoft 365 / Outlook.com via Microsoft Graph. Per-account OAuth (Auth Code + PKCE), encrypted token storage, automatic refresh.

## Quickstart

1. **Register an Entra app once per Maxy install** — see `platform/plugins/outlook/references/auth.md` for full steps. Set `OUTLOOK_CLIENT_ID` (and `OUTLOOK_TENANT_ID`, default `common`) in the operator's environment.
2. **Per account: register the Outlook account** — in admin chat, ask the agent to "register my Outlook account". The agent runs `outlook-account-register`, which prints an authorization URL.
3. **Open the URL in the VNC browser** — sign in to your Microsoft account, consent to the requested scopes (`offline_access`, `User.Read`, `Mail.Read`, `Calendars.Read`, `Contacts.Read`).
4. **Done.** Subsequent tool calls (mail, calendar, contacts) use the persisted refresh token transparently.

## Tools

| Tool | Purpose |
|------|---------|
| `outlook-account-register` | Run the PKCE flow for this account. One-time per account; re-run if tokens expire (90 days) or consent is revoked. |
| `outlook-mail-list` | Recent mail. Default top=25, folder=Inbox. |
| `outlook-mail-search` | Microsoft Graph `$search` over the mailbox. |
| `outlook-calendar-list` | Calendar events in next rangeDays days (default 7, max 365). |
| `outlook-calendar-event` | Full detail of a single event by id. |
| `outlook-contacts-list` | Top contacts. Default top=50. |
| `outlook-mailbox-info` | Health probe — auth state, refresh-window, folder count. |

## Observability

All log lines start with `[outlook-mcp]` and write to `server.log`. They are key=value, account-scoped:

| Event | Line shape |
|-------|------------|
| Auth init | `auth-init account=<id> codeChallenge=<sha256-prefix-8> redirectPath=<callback-path>` |
| Auth callback | `auth-callback account=<id> elapsedMs=<N>` |
| Auth ok | `auth-ok account=<id> graphUserId=<id> scopes=<csv> tokenExpSec=<N>` |
| Token refreshed | `token-refreshed account=<id> oldExpSec=<N> newExpSec=<N>` |
| Refresh failed | `token-refresh-failed account=<id> reason=<err>` (terminal) |
| Mail list | `mail-list account=<id> folder=<id-or-Inbox> count=<N> elapsedMs=<N>` |
| Mail search | `mail-search account=<id> query=<trunc-32> count=<N> elapsedMs=<N>` |
| Calendar list | `calendar-list account=<id> rangeDays=<N> count=<N> elapsedMs=<N>` |
| Calendar event | `calendar-event account=<id> eventId=<trunc-12> elapsedMs=<N>` |
| Contacts list | `contacts-list account=<id> count=<N> elapsedMs=<N>` |
| Mailbox info | `mailbox-info account=<id> tokenWithinRefreshWindow=<bool> folderCount=<N>` |
| Graph error | `graph-error account=<id> status=<N> code=<graphErrorCode> retryAfterMs=<N-or-null>` |
| On-prem rejected | `on-prem-rejected account=<id> mailServer=<host>` (terminal) |

## Diagnostic paths

```bash
# All outlook lines for one account, last 50
ssh laptop 'grep -E "^\[outlook-mcp\]" ~/.maxy/logs/server.log | grep "account=<id>" | tail -50'

# Token-leak audit — must always return zero
grep -rn -iE "Bearer |access_token=" ~/.maxy/logs/server.log | head
```

Latency triage: `mail-list count=0 elapsedMs<200` consistent → permissions issue; `elapsedMs > 5000` → Graph slowness or DNS.

## Failure modes

| Operator-visible message | Cause | Fix |
|---|---|---|
| `Outlook not connected for account=X; run outlook-account-register` | Tokens never saved | Run register tool |
| `Outlook refresh token expired for account=X; run outlook-account-register` | >90 days since last refresh, or consent revoked | Run register tool |
| `Outlook token refresh failed for account=X; re-auth required` | Network down at refresh time, or refresh token invalidated | Verify network; re-register |
| `Outlook auth expired for account=X; run outlook-account-register` | Refresh-then-retry still got 401 | Re-register |
| `Outlook rate-limited without Retry-After hint` | Graph 429 with no backoff guidance | Wait + retry; if persistent, file bug |
| `Microsoft Graph does not support on-premises Exchange. Use earlier platform fixes (IMAP).` | Mailbox is on hybrid Exchange | Use the `email` plugin |

## Out of scope

Write tools (send, draft, move, flag), OneDrive / Files, push notifications, on-premises Exchange, M365 admin scopes (`User.Read.All`, `AuditLog.Read.All`), public-agent exposure, multi-tenant federation. See `platform/plugins/outlook/PLUGIN.md` for the full out-of-scope list.
