SkillHub

microsoft-365-graph-openclaw

v0.2.2

Microsoft 365 Graph for OpenClaw with webhook-based wake signals. Reduce recurring LLM cost from inbox polling while managing Outlook mail, calendar, OneDrive, and contacts via Microsoft Graph.

Sourced from ClawHub, Authored by draeden79

Installation

Please help me install the skill `microsoft-365-graph-openclaw` from SkillHub official store. npx skills add draeden79/microsoft-365-graph-openclaw

Microsoft 365 Graph for OpenClaw Skill

1. Quick prerequisites

  1. Python 3 with requests installed.
  2. Default auth values:
  3. Client ID (personal-account default): 952d1b34-682e-48ce-9c54-bac5a96cbd42
  4. Tenant (personal-account default): consumers
  5. Default scopes: Mail.ReadWrite Mail.Send Calendars.ReadWrite Files.ReadWrite.All Contacts.ReadWrite offline_access
  6. For work/school accounts, use --tenant-id organizations (or tenant GUID) and a tenant-approved --client-id.
  7. The public default client ID is for quick testing. For production, prefer your own App Registration.
  8. Tokens are stored in state/graph_auth.json (ignored by git).
  9. Push-mode runtime values (service-level):
  10. These values are loaded by systemd services from /etc/default/graph-mail-webhook (usually written by setup scripts).
  11. OPENCLAW_HOOK_URL (required)
  12. OPENCLAW_HOOK_TOKEN (required)
  13. GRAPH_WEBHOOK_CLIENT_STATE (required; auto-generated in minimal e2e setup when omitted)
  14. OPENCLAW_SESSION_KEY (optional; default hook:graph-mail)

Permission profiles (least privilege by use case) are documented in docs/permission-profiles.md.

2. Assisted OAuth flow (Device Code)

  1. Run: bash python scripts/graph_auth.py device-login --client-id 952d1b34-682e-48ce-9c54-bac5a96cbd42 --tenant-id consumers
  2. The script prints a URL and device code.
  3. Open https://microsoft.com/devicelogin, enter the code, and approve with the target account.
  4. Check and manage auth state:
  5. python scripts/graph_auth.py status
  6. python scripts/graph_auth.py refresh
  7. python scripts/graph_auth.py clear
  8. Other scripts call utils.get_access_token(), which refreshes tokens automatically when needed.
  9. Scope override is disabled in graph_auth.py; the skill always uses DEFAULT_SCOPES.

Detailed reference: references/auth.md.

3. Email operations

  • List/filter: python scripts/mail_fetch.py --folder Inbox --top 20 --unread
  • Fetch specific message: ... --id <messageId> --include-body --mark-read
  • Move message: add --move-to <folderId> to the command above.
  • Send email (saveToSentItems enabled by default): bash python scripts/mail_send.py --to [email protected] --subject "Update" --body-file replies/thais.html --html --cc [email protected] --attachment docs/proposal.pdf
  • Use --no-save-copy only when you intentionally do not want Sent Items storage.

More examples and filters: references/mail.md.

4. Calendar operations

  • List custom date window: bash python scripts/calendar_sync.py list --start 2026-03-03T00:00Z --end 2026-03-05T23:59Z --top 50
  • Create Teams or in-person event: use create; add --online for Teams link.
  • For personal Microsoft accounts (tenant=consumers), Teams meeting provisioning via Graph might not return a join URL; create the Teams meeting in Outlook/Teams first and add the resulting link to the event body when needed.
  • Update/cancel events by event_id returned in JSON output.

Full examples: references/calendar.md.

5. OneDrive / Files

  • List folders/files: python scripts/drive_ops.py list --path /
  • Upload: ... upload --local notes/briefing.docx --remote /Clients/briefing.docx
  • Download: ... download --remote /Clients/briefing.docx --local /tmp/briefing.docx
  • Move / share links: use move and share subcommands.
  • The script resolves localized/special-folder aliases (for example Documents and Documentos).

More details: references/drive.md.

6. Contacts

  • List/search: python scripts/contacts_ops.py list --top 20
  • Create: ... create --given-name Jane --surname Doe --email [email protected]
  • Update/Delete: ... update <contactId> ... / ... delete <contactId>
  • Contacts are part of the default scope set and supported as a first-class workflow.

More details: references/contacts.md.

7. Mail push mode (Webhook Adapter)

  • Adapter server (Graph handshake + clientState validation + enqueue): bash python scripts/mail_webhook_adapter.py serve --host 0.0.0.0 --port 8789 --path /graph/mail --client-state "$GRAPH_WEBHOOK_CLIENT_STATE"
  • Subscription lifecycle (create/status/renew/delete/list): bash python scripts/mail_subscriptions.py create --notification-url "https://graph-hook.example.com/graph/mail" --client-state "$GRAPH_WEBHOOK_CLIENT_STATE" --minutes 4200
  • Default resource is me/messages (recommended for better delivery coverage). Override with --resource only for advanced/scoped scenarios.
  • Async worker (dedupe + default wake signal to OpenClaw /hooks/wake): bash python scripts/mail_webhook_worker.py loop --session-key "$OPENCLAW_SESSION_KEY" --hook-url "$OPENCLAW_HOOK_URL" --hook-token "$OPENCLAW_HOOK_TOKEN"
  • Default mode is wake (/hooks/wake, mode=now). Use --hook-action agent only when you explicitly need per-message rich payload delivery.
  • Worker queue files:
  • state/mail_webhook_queue.jsonl
  • state/mail_webhook_dedupe.json
  • Automated EC2 bootstrap (Caddy + systemd + renew timer): bash sudo bash scripts/setup_mail_webhook_ec2.sh --domain graphhook.example.com --hook-url http://127.0.0.1:18789/hooks/wake --hook-token "<OPENCLAW_HOOK_TOKEN>" --session-key "hook:graph-mail" --client-state "<GRAPH_WEBHOOK_CLIENT_STATE>" --repo-root "$(pwd)"
  • Use --dry-run to preview all privileged writes and service actions before applying changes.
  • One-command setup (steps 2..6): bash sudo bash scripts/run_mail_webhook_e2e_setup.sh --domain graphhook.example.com --hook-token "<OPENCLAW_HOOK_TOKEN>" --hook-url "http://127.0.0.1:18789/hooks/wake" --session-key "hook:graph-mail" --test-email "[email protected]"
  • Use --dry-run for a no-mutation execution plan (no /etc writes, no systemctl, no subscription create, no email send).
  • Output ends with READY_FOR_PUSH: YES when setup is fully validated.
  • Include OpenClaw hook config in automation: bash sudo bash scripts/run_mail_webhook_e2e_setup.sh --domain graphhook.example.com --hook-token "<OPENCLAW_HOOK_TOKEN>" --configure-openclaw-hooks --openclaw-config "/home/ubuntu/.openclaw/openclaw.json" --openclaw-service-name "auto" --openclaw-hooks-path "/hooks" --openclaw-allow-request-session-key true --test-email "[email protected]"
  • Minimal-input smoke tests: bash sudo bash scripts/run_mail_webhook_smoke_tests.sh --domain graphhook.example.com --create-subscription --test-email [email protected]
  • Output ends with READINESS VERDICT: READY_FOR_PUSH only after all critical checks pass.
  • Setup and runbook: references/mail_webhook_adapter.md.

8. Privileged operations boundary

The core Graph scripts are unprivileged (graph_auth.py, mail_fetch.py, mail_send.py, calendar_sync.py, drive_ops.py, contacts_ops.py).

The setup scripts below are privileged and should be manually reviewed before execution: - scripts/setup_mail_webhook_ec2.sh - scripts/run_mail_webhook_e2e_setup.sh

When run without --dry-run, they can: - Write /etc/default/graph-mail-webhook - Write /etc/caddy/Caddyfile - Write /etc/systemd/system/*.service and *.timer - Enable/restart services via systemctl - Optionally patch OpenClaw config and restart OpenClaw services

Recommended safety sequence: 1. Run with --dry-run 2. Review emitted actions and target files 3. Run on a non-production host first 4. Apply to production only after approval

9. Logging and conventions

  • Each script appends one JSON line to state/graph_ops.log with timestamp, action, and key parameters.
  • Tokens and logs must never be committed.
  • Commands assume execution from the repository root. Adjust paths if running elsewhere.

10. Troubleshooting

Symptom Action
401/invalid_grant Run graph_auth.py refresh; if it fails, run clear and repeat device login.
403/AccessDenied Missing scope or licensing/policy issue. Re-run device login with required scope(s).
429/Throttled Scripts do basic retry; wait a few seconds and retry.
requests.exceptions.SSLError Verify local system date/time and TLS trust chain.

This skill provides OAuth-driven workflows for email, calendar, files, contacts, and push-based mail automation via Microsoft Graph.