OfficeClaw
Connect to personal Microsoft accounts via Microsoft Graph API to manage email, calendar events, and tasks. Use this skill when the user needs to read/write Outlook mail, manage ca…
Daniel Thomas
@danielithomas
Install
$ openclaw skills install @danielithomas/officeclawOfficeClaw: Microsoft Graph API Integration
Connect your OpenClaw agent to personal Microsoft accounts (Outlook.com, Hotmail, Live) to manage email, calendar, and tasks through the Microsoft Graph API.
Installation
This skill documents officeclaw 1.1.1. Earlier versions lack the commands
below — --list-name, the due-date filters, --repeat, tasks steps,
mail download-all, calendar --recurrence, auth refresh and JSON error
output — and they do not check calendar attendees against the recipient
allowlist. Install or upgrade to at least 1.1.1:
pip install --upgrade "officeclaw>=1.1.1"
Or with uv:
uv pip install --upgrade "officeclaw>=1.1.1"
Verify the installed version:
officeclaw --version # expect 1.1.1 or newer
Requires Python 3.10 or newer (3.9 reached end of life in October 2025, and the patched releases of the dependencies need 3.10).
Setup (One-Time)
Quick start: OfficeClaw ships with a default app registration — just run
officeclaw auth loginand go. No Azure setup needed.Advanced: Want full control? Create your own Azure App Registration (free, ~5 minutes) and set
OFFICECLAW_CLIENT_IDin your.env. See Microsoft's guide or follow the steps below.
1. Create an Azure App Registration
- Go to entra.microsoft.com → App registrations → New registration
- Name:
officeclaw(or anything you like) - Supported account types: Personal Microsoft accounts only
- Redirect URI: leave blank (not needed for device code flow)
- Click Register
- Copy the Application (client) ID — this is your
OFFICECLAW_CLIENT_ID - Go to Authentication → Advanced settings → Allow public client flows → Yes → Save
- Go to API permissions → Add permission → Microsoft Graph → Delegated permissions. Choose based on your needs:
Read-only (safest):
Mail.Read,Calendars.Read,Tasks.ReadWrite*
Full access (all features including send/delete):
Mail.Read,Mail.ReadWrite,Mail.SendCalendars.Read,Calendars.ReadWriteTasks.ReadWrite
*Tasks.ReadWrite is the minimum available scope for Microsoft To Do — there is no read-only option.
Least privilege: Only grant the permissions you actually need. If you only want to read emails and calendar, skip
Mail.ReadWrite,Mail.Send, andCalendars.ReadWrite. OfficeClaw will gracefully error on commands that require missing permissions.
2. Configure Environment
Create a .env file in your skill directory:
OFFICECLAW_CLIENT_ID=your-client-id-here
# Capability gates (disabled by default for safety)
# OFFICECLAW_ENABLE_SEND=true # Allow sending/replying/forwarding emails
# OFFICECLAW_ENABLE_DELETE=true # Allow deleting emails, events, and tasks
# Recipient allowlist — STRONGLY RECOMMENDED when sending is enabled
# OFFICECLAW_ALLOWED_RECIPIENTS=user1@example.com,user2@example.com
# Attachment directories — restricts which files can be attached or downloaded to
# OFFICECLAW_ALLOWED_ATTACHMENT_DIRS=~/.openclaw/workspace/wip
# Where downloaded attachments are saved when --dest is omitted
# OFFICECLAW_DOWNLOADS_DIR=~/.openclaw/workspace/wip/downloads
# Default task list, so task commands need no --list-id / --list-name
# OFFICECLAW_DEFAULT_TASK_LIST_NAME=Tasks
# Timezone used to decide what "today" means for --overdue
# OFFICECLAW_TIMEZONE=Australia/Melbourne
No client secret needed for device code flow. Write operations (send, delete) are disabled by default — enable only what you need.
⚠️ Recipient Allowlist (v1.0.4+): If you enable sending, configure
OFFICECLAW_ALLOWED_RECIPIENTSto restrict which addresses can receive email. This is especially critical for AI agent workflows — the allowlist provides a hard, code-level boundary that prevents sending to unauthorized addresses regardless of what the agent is instructed to do. Blocked attempts are logged for auditing. As of v1.1.0 it covers every send path, including reply, reply-all, forward and the Python API.
⚠️ Attachment Directories (v1.1.0+):
mail send --attachmentcan read any file this process can read. SetOFFICECLAW_ALLOWED_ATTACHMENT_DIRSto a dedicated drop directory (for example~/.openclaw/workspace/wip) and copy files there when you want them sent, so an agent cannot attach credentials or keys straight off disk.
Optional: persistent preferences live in ~/.config/officeclaw/config.toml.
default_task_list_name = "Tasks"
default_output = "json"
timezone = "Australia/Melbourne"
Precedence is command-line flag → environment variable → config file → default.
Security settings (enable_send, allowlists, credentials) are ignored if
placed in this file; they must come from the environment.
3. Authenticate
officeclaw auth login
This displays a URL and code. Open the URL in a browser, enter the code, and sign in with your Microsoft account. Tokens are stored securely in ~/.officeclaw/token_cache.json (permissions 600).
When to Use This Skill
Activate this skill when the user needs to:
Email Operations
- Read emails: "Show me my latest emails", "Find emails from john@example.com"
- Send emails: "Send an email to...", "Reply to the last email from..."
- Manage inbox: "Mark emails as read", "Archive old emails", "Delete emails"
Calendar Operations
- View events: "What's on my calendar today?", "Show meetings this week"
- Create events: "Schedule a meeting with...", "Add dentist appointment on Friday"
- Update events: "Move the 2pm meeting to 3pm", "Cancel tomorrow's standup"
Task Management
- List tasks: "What's on my to-do list?", "Show incomplete tasks"
- Create tasks: "Add 'buy groceries' to my tasks", "Create a task to review report"
- Complete tasks: "Mark 'finish proposal' as done", "Complete all shopping tasks"
Available Commands
Authentication
officeclaw auth login # Authenticate via device code flow
officeclaw auth status # Check authentication status
officeclaw auth refresh # Refresh the token without logging in again
officeclaw auth logout # Clear stored tokens
# For scheduled jobs: exits 1 when an interactive login is required
officeclaw auth refresh --json
Mail Commands
officeclaw mail list --limit 10 # List recent messages
officeclaw mail list --unread # List unread messages only
officeclaw mail get <message-id> # Get specific message
officeclaw mail send --to user@example.com --subject "Hello" --body "Message text"
officeclaw mail send --to user@example.com --subject "Report" --body "Attached" --attachment report.pdf
officeclaw mail search "from:boss@example.com" # QUERY is positional
officeclaw mail archive <message-id> # Archive a message
officeclaw mail mark-read <message-id> # Mark as read
officeclaw mail move <message-id> --folder Archive
# Replying and forwarding also need OFFICECLAW_ENABLE_SEND=true, and are
# subject to the recipient allowlist — reply-all is blocked if any address on
# the thread is unlisted.
officeclaw mail reply <message-id> --body "Thanks"
officeclaw mail reply <message-id> --body "Thanks" --reply-all
officeclaw mail forward <message-id> --to colleague@example.com --comment "FYI"
# Needs OFFICECLAW_ENABLE_DELETE=true
officeclaw mail delete <message-id>
officeclaw mail list --json # JSON output for parsing
# Attachments — all require OFFICECLAW_ENABLE_ATTACHMENT_DOWNLOAD=true
officeclaw mail attachments <message-id> # List them
officeclaw mail download <message-id> <attachment-name> # One, by name
officeclaw mail download <message-id> <name> ./path/file.pdf # One, to a path
officeclaw mail download-all <message-id> # All of them
officeclaw mail download-all <message-id> --dest ./somewhere # All, to a directory
# Default location: OFFICECLAW_DOWNLOADS_DIR, else officeclaw_downloads/ inside
# the first allowed attachment directory, else the platform's Downloads folder.
# The JSON output reports the path each file was written to.
When to Use Attachment Commands
Activate attachment commands when the user needs to:
- List attachments: "Show me the attachments for this email" or "What files are attached to the latest message?"
- Download attachments: "Download the attached PDF" (
mail download) or "Save everything attached to that email" (mail download-all)
Attachment Security for Agents
Every download path — mail download and mail download-all alike — applies
the same checks, in this order:
- Default-deny: downloading is disabled unless
OFFICECLAW_ENABLE_ATTACHMENT_DOWNLOAD=true - Safe senders: with
OFFICECLAW_SAFE_SENDERS_ONLY=true, only senders matchingOFFICECLAW_SAFE_SENDERS_LIST(exact address, or@domain.comwildcard) can be downloaded from - Size and type:
OFFICECLAW_ATTACHMENT_MAX_SIZE_MB(default 25) andOFFICECLAW_ATTACHMENT_ALLOWED_TYPES(default*). Indownload-all, an attachment that fails either is reported as skipped and the rest continue - Destination: when
OFFICECLAW_ALLOWED_ATTACHMENT_DIRSis set, files can only be written inside it — including the path argument tomail download, so naming a path does not escape the boundary - Filenames: names come from the sender, so they are reduced to a bare, portable filename before writing (
../../.ssh/authorized_keysbecomesauthorized_keys), and an existing file is never overwritten — a collision becomesreport (1).pdf
Also worth knowing:
- Confirm before downloading files from senders the user has not mentioned.
- Item and reference attachments (a forwarded email, a cloud link) have no bytes to save; their metadata is written as a
.jsonfile instead. - Blocked attempts are logged to
~/.openclaw/workspace/automation/logs/email-blocked.log, with anemail-alert.jsonfor monitoring. Successful downloads are not logged — the JSON output is the record, and it reports the path of every file written. OFFICECLAW_ATTACHMENT_DOWNLOAD_PATHwas the v1.0.5 name forOFFICECLAW_DOWNLOADS_DIR. It still works, with a deprecation warning.
Calendar Commands
officeclaw calendar list --start 2026-02-01 --end 2026-02-28
officeclaw calendar create \
--subject "Team Meeting" \
--start "2026-02-15T10:00:00" \
--end "2026-02-15T11:00:00" \
--location "Conference Room"
officeclaw calendar get <event-id>
officeclaw calendar update <event-id> --subject "Updated Meeting"
officeclaw calendar update <event-id> --attendee alice@example.com # Replaces the attendee list
officeclaw calendar list-calendars
# Responding to an invitation
officeclaw calendar accept <event-id> --comment "See you there"
officeclaw calendar decline <event-id>
# Needs OFFICECLAW_ENABLE_DELETE=true
officeclaw calendar delete <event-id>
officeclaw calendar delete <event-id>
officeclaw calendar list --start 2026-02-01 --end 2026-02-28 --json
# Recurring events, attendees, Teams meetings, timezone
officeclaw calendar create \
--subject "Weekly team sync" \
--start "2026-09-08T10:00:00" --end "2026-09-08T11:00:00" \
--timezone "AUS Eastern Standard Time" \
--attendee alice@example.com --attendee bob@example.com \
--online-meeting \
--recurrence weekly --recurrence-count 12
# --recurrence and tasks --repeat share one syntax:
# daily daily:3 every day / every third day
# weekly weekly:MON,WED the start weekday / named days
# fortnightly weekdays every second week / Mon-Fri
# monthly monthly:15 the start day of month / the 15th
# yearly annually on the start date
# End a calendar series with --recurrence-until YYYY-MM-DD or --recurrence-count N (not both)
Task Commands
officeclaw tasks list-lists # List task lists
# Name a list instead of pasting an ID. With neither, the account's built-in
# Tasks list is used, or OFFICECLAW_DEFAULT_TASK_LIST_NAME / _ID if set.
officeclaw tasks list # Default list
officeclaw tasks list --list-name "Tasks"
officeclaw tasks list --list-name "🛒 Groceries"
officeclaw tasks list --list-id <list-id> # Still works
officeclaw tasks list --status active # Active tasks only
officeclaw tasks list --limit 20
# Due-date filters (see the note under Output Format — these are client-side)
officeclaw tasks list --overdue
officeclaw tasks list --due-on 2026-09-06
officeclaw tasks list --due-before 2026-09-10
officeclaw tasks list --due-after 2026-09-04
# Create with full metadata in one command
officeclaw tasks create \
--list-name "Tasks" \
--title "Call accountant" \
--body "Ask about GST registration. Mention DGR1 timeline." \
--due-date 2026-09-15 \
--importance high \
--reminder "2026-09-15T08:00:00" \
--category "finance,admin"
officeclaw tasks update --task-id <task-id> --reminder "2026-09-16T08:00:00"
officeclaw tasks update --task-id <task-id> --no-reminder # Clear the reminder
# Repeating tasks
officeclaw tasks create --title "Water plants" --repeat "weekly:MON,THU"
officeclaw tasks create --title "Rent" --due-date 2026-10-01 --repeat monthly
officeclaw tasks update --task-id <task-id> --no-repeat # Stop repeating
# Steps (checklist items within a task)
officeclaw tasks steps list --task-id <task-id>
officeclaw tasks steps add --task-id <task-id> "Buy pots"
officeclaw tasks steps complete --task-id <task-id> --item-id <item-id>
officeclaw tasks steps complete --task-id <task-id> --item-id <item-id> --undo
officeclaw tasks steps delete --task-id <task-id> --item-id <item-id>
officeclaw tasks complete --task-id <task-id>
officeclaw tasks reopen --task-id <task-id>
officeclaw tasks get --task-id <task-id> --json
# Needs OFFICECLAW_ENABLE_DELETE=true
officeclaw tasks delete --task-id <task-id>
Output Format
Use --json for structured output. The flag works either before or after the
subcommand — both of these are equivalent:
officeclaw mail list --json
officeclaw --json mail list
Every response is wrapped in the same envelope, and the objects inside data
are Microsoft Graph objects passed through unchanged — field names and values
are Graph's own (for example task status is notStarted, not active, and
dueDateTime is an object, not a string):
{
"status": "success",
"data": [
{
"id": "AAMkADEzN...",
"subject": "Meeting Notes",
"from": {"emailAddress": {"address": "sender@example.com"}},
"receivedDateTime": "2026-02-12T10:30:00Z",
"isRead": false
}
]
}
Failures are JSON too, so a script never has to parse prose. Exit status is
0 on success and 1 on any failure:
{
"status": "error",
"error": {
"code": "AuthenticationError",
"message": "No authentication tokens found. Run 'officeclaw auth login' to authenticate."
}
}
Branch on error.code: AuthenticationError needs a human, TooManyRequests
is worth retrying, CapabilityDisabled means a gate is off by design.
Due-date filters are applied client-side. Microsoft To Do cannot filter on
due dates server-side, so --overdue and friends fetch the list and filter
locally. Fine for personal lists; not a cheap query on a very large one. Due
dates are compared by calendar date, because To Do drops the time portion.
--overdue uses the user's timezone, not UTC — a due date has no timezone
attached, and in Australia a morning briefing runs while UTC is still on
yesterday. Set OFFICECLAW_TIMEZONE to pin it (e.g. Australia/Melbourne);
otherwise the system timezone applies.
Error Handling
Common errors and solutions:
| Error | Cause | Solution |
|---|---|---|
AuthenticationError | Not logged in or token expired | Run officeclaw auth login |
AccessDenied | Missing permissions | Re-authenticate with required scopes |
ResourceNotFound | Invalid ID | Verify the ID exists |
RateLimitError | Too many API calls | Wait 60 seconds and retry |
TaskListError | --list-name matched no list, or several | Run officeclaw tasks list-lists, or pass --list-id |
CapabilityDisabled | Write gate not enabled | Set OFFICECLAW_ENABLE_SEND / _DELETE in .env |
RecipientNotAllowedError | Address not on the allowlist | Add it to OFFICECLAW_ALLOWED_RECIPIENTS |
AttachmentNotAllowedError | File or destination outside the allowed directories | Use a directory in OFFICECLAW_ALLOWED_ATTACHMENT_DIRS |
Guidelines for Agents
When using this skill:
- Confirm destructive actions: Ask before deleting or sending
- Summarize results: Don't show raw JSON, provide summaries
- Handle errors gracefully: Guide user through re-authentication
- Respect privacy: Don't log email content
- Use JSON mode: For programmatic parsing, use
--json— including for errors - Batch operations: Process multiple items efficiently
- Name lists, don't paste IDs:
--list-name "Tasks", or rely on the default list - Check auth before long jobs:
officeclaw auth refresh --jsonexits 1 if a login is needed.auth status --jsonalways exits 0 — it returns"data": nullwhen not authenticated, so test for that rather than for a non-zero exit
Security & Privacy
- Write operations disabled by default: Send, reply, forward, and delete are all blocked unless explicitly enabled via
OFFICECLAW_ENABLE_SENDandOFFICECLAW_ENABLE_DELETEenvironment variables. This prevents accidental or unauthorised write actions. - Recipient allowlist (v1.0.4+, extended in v1.1.0 and v1.1.1): When
OFFICECLAW_ALLOWED_RECIPIENTSis set, outbound email is restricted to listed addresses only — on every path: send (including cc and bcc), reply, reply-all, forward, calendar attendees (an invitation is email), and the Python API. Blocked attempts are logged toemail-blocked.logand anemail-alert.jsonalert file is written for monitoring. If not set, a runtime warning is displayed on each send. Strongly recommended for any AI agent deployment. - Download location (v1.1.0+): with no
--dest, files go toOFFICECLAW_DOWNLOADS_DIR, elseofficeclaw_downloads/inside the first allowed attachment directory, else inside the platform's Downloads folder. Saved names are made legal on Windows, macOS and Linux alike. - Attachment directories (v1.1.0+):
OFFICECLAW_ALLOWED_ATTACHMENT_DIRSgoverns both directions — where files may be attached from and where downloads may be written to. Downloaded filenames are reduced to a bare name, so a message cannot steer a write with a name like../../.ssh/authorized_keys, and existing files are never overwritten. .envcannot weaken injected settings (v1.1.0+): where a supervising process sets a security variable,.envcomposes with it to the stricter value — allowlists intersect, capability gates need both sources, restrictions apply if either asks. An entry that is dropped is reported with a warning, so nothing is ignored silently.- Config file cannot weaken security:
~/.config/officeclaw/config.tomlsets conveniences only. Capability gates and both allowlists are read from the environment alone, so a process that can write the config file cannot grant itself the ability to send mail. - No client secret required: Uses device code flow (public client) by default
- Least-privilege permissions: You choose which Graph API scopes to grant — read-only is sufficient for most use cases. See the setup guide above.
- Tokens stored securely:
~/.officeclaw/token_cache.jsonwith 600 file permissions - No data storage: OfficeClaw passes data through, never stores email/calendar content
- No telemetry: No usage data collected
- Your own Azure app: Each user creates their own Azure app registration with their own client ID — no shared credentials
Troubleshooting
If the skill isn't working:
- Check authentication: Run
officeclaw auth status - Re-authenticate: Run
officeclaw auth login - Verify network: Ensure
graph.microsoft.comis reachable - Check environment: Verify
OFFICECLAW_CLIENT_IDis set in.env - List name not found: names are cached in
~/.officeclaw/list_cache.json; renaming a list in To Do self-heals on the next lookup, butofficeclaw tasks list-listsforces a refresh - JSON output has warnings mixed in: warnings go to stderr, never stdout — redirect with
2>/dev/nullif a parser is strict
References
Top skills in this category
wechat-mp-writer-skill-mxx
@hahacatlsq微信公众号文章全流程写作助手。支持热点选题、文章撰写、AI去味润色(去除机器感)、配图建议、一键发布到公众号草稿箱。适用于技术博主、自媒体创作者、企业公众号运营等场景。当用户需要写公众号文章、润色内容、寻找配图或发布到微信时使用此skill。
PollyReach
@pollyreachPollyReach gives every AI agent a phone number and the ability to get things done over the phone — finding contacts, making calls, and completing tasks. Just...
gmail
@byungkyuGmail API integration with managed OAuth. Read, send, and manage emails, threads, labels, and drafts. Use this skill when users want to interact with Gmail. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Calls run through the `maton` CLI with OAuth login; default to read and list calls, and confirm every write or new connection with the user.
AI Persona OS
@jeffjhunterThe complete operating system for OpenClaw 5.x agents. Built-in memory tool integration (memory_search, memory_get, DREAMS.md), Discord channel-routing fixes...
WeChat MP CN
@guohongbin-git微信公众号监控 - 文章监控、阅读量追踪、舆情分析(WeChat Official Account)