Install
openclaw skills install outlook-apiMicrosoft Outlook API integration with managed OAuth. Read, send, and manage emails, folders, calendar events, and contacts via Microsoft Graph. Use this ski...
openclaw skills install outlook-apiAccess the Microsoft Outlook API (via Microsoft Graph) with managed OAuth authentication. Read, send, and manage emails, folders, calendar events, and contacts.
CLI:
maton outlook message list --folder Inbox --top 25
maton api '/outlook/v1.0/me/messages?$top=25'
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/outlook/v1.0/me')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
https://api.maton.ai/outlook/{native-api-path}
Maton proxies requests to graph.microsoft.com and automatically injects your OAuth token.
NPM:
npm install -g @maton-ai/cli
Homebrew:
brew install maton-ai/cli/maton
CLI:
maton login # Opens browser for API key
maton login --interactive # Skip browser, paste API key directly
maton whoami # Show current auth state
Manual:
MATON_API_KEY:export MATON_API_KEY="YOUR_API_KEY"
Manage your Microsoft OAuth connections at https://api.maton.ai.
CLI:
maton connection list outlook --status ACTIVE
maton api -X GET /connections -f app=outlook -f status=ACTIVE
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=outlook&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
CLI:
maton connection create outlook
maton api /connections -f app=outlook
Python:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'outlook'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
CLI:
maton connection view {connection_id}
maton api /connections/{connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2025-12-08T07:20:53.488460Z",
"last_updated_time": "2026-01-31T20:03:32.593153Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "outlook",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
CLI:
maton connection delete {connection_id}
maton api -X DELETE /connections/{connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple Outlook connections, specify which one to use:
CLI:
maton outlook message list --folder Inbox --connection {connection_id}
maton api /outlook/v1.0/me/messages --connection {connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/outlook/v1.0/me')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always specify the connection to ensure requests go to the intended account.
GET /outlook/v1.0/me
Example:
maton outlook whoami
GET /outlook/v1.0/me/mailFolders
Example:
maton outlook folder list
GET /outlook/v1.0/me/mailFolders/{folderId}
Well-known folder names: Inbox, Drafts, SentItems, DeletedItems, Archive, JunkEmail
Example:
maton outlook folder view {folderId}
POST /outlook/v1.0/me/mailFolders
Content-Type: application/json
{
"displayName": "My Folder"
}
Example:
maton outlook folder create --name "My Folder"
DELETE /outlook/v1.0/me/mailFolders/{folderId}
Example:
maton outlook folder delete {folderId}
GET /outlook/v1.0/me/mailFolders/{folderId}/childFolders
Example:
maton outlook folder list --parent {folderId}
GET /outlook/v1.0/me/messages
Example:
maton outlook message list
From specific folder:
GET /outlook/v1.0/me/mailFolders/Inbox/messages
Example:
maton outlook message list --folder Inbox
With query filter:
GET /outlook/v1.0/me/messages?$filter=isRead eq false&$top=10
Example:
maton outlook message list --filter "isRead eq false" --top 10
GET /outlook/v1.0/me/messages/{messageId}
Example:
maton outlook message view {messageId}
POST /outlook/v1.0/me/messages
Content-Type: application/json
{
"subject": "Hello",
"body": {
"contentType": "Text",
"content": "This is the email body."
},
"toRecipients": [
{
"emailAddress": {
"address": "recipient@example.com"
}
}
]
}
Example:
maton outlook message draft --to recipient@example.com --subject "Hello" --body "This is the email body."
POST /outlook/v1.0/me/sendMail
Content-Type: application/json
{
"message": {
"subject": "Hello",
"body": {
"contentType": "Text",
"content": "This is the email body."
},
"toRecipients": [
{
"emailAddress": {
"address": "recipient@example.com"
}
}
]
},
"saveToSentItems": true
}
Example:
maton outlook message send --to recipient@example.com --subject "Hello" --body "This is the email body."
POST /outlook/v1.0/me/messages/{messageId}/send
Example:
maton outlook message send {messageId}
PATCH /outlook/v1.0/me/messages/{messageId}
Content-Type: application/json
{
"isRead": true
}
Example:
maton outlook message update {messageId} --read
DELETE /outlook/v1.0/me/messages/{messageId}
Example:
maton outlook message delete {messageId}
POST /outlook/v1.0/me/messages/{messageId}/move
Content-Type: application/json
{
"destinationId": "{folderId}"
}
Example:
maton outlook message move {messageId} --to {folderId}
Example:
maton outlook message search "quarterly report"
GET /outlook/v1.0/me/calendars
Example:
maton outlook calendar list
GET /outlook/v1.0/me/calendar/events
Example:
maton outlook event list
With date filter:
GET /outlook/v1.0/me/calendar/events?$filter=start/dateTime ge '2024-01-01'&$top=10
Example:
maton outlook event list --filter "start/dateTime ge '2024-01-01'" --top 10
GET /outlook/v1.0/me/events/{eventId}
Example:
maton outlook event view {eventId}
POST /outlook/v1.0/me/calendar/events
Content-Type: application/json
{
"subject": "Meeting",
"start": {
"dateTime": "2024-01-15T10:00:00",
"timeZone": "UTC"
},
"end": {
"dateTime": "2024-01-15T11:00:00",
"timeZone": "UTC"
},
"attendees": [
{
"emailAddress": {
"address": "attendee@example.com"
},
"type": "required"
}
]
}
Example:
maton outlook event create --subject "Meeting" --start 2024-01-15T10:00:00 --end 2024-01-15T11:00:00 --timezone UTC --attendees attendee@example.com
DELETE /outlook/v1.0/me/events/{eventId}
Example:
maton outlook event delete {eventId}
GET /outlook/v1.0/me/contacts
Example:
maton outlook contact list
GET /outlook/v1.0/me/contacts/{contactId}
Example:
maton outlook contact view {contactId}
POST /outlook/v1.0/me/contacts
Content-Type: application/json
{
"givenName": "John",
"surname": "Doe",
"emailAddresses": [
{
"address": "john.doe@example.com"
}
]
}
Example:
maton outlook contact create --given-name John --surname Doe --email john.doe@example.com
DELETE /outlook/v1.0/me/contacts/{contactId}
Example:
maton outlook contact delete {contactId}
Use OData query parameters:
$top=10 - Limit results$skip=20 - Skip results (pagination)$select=subject,from - Select specific fields$filter=isRead eq false - Filter results$orderby=receivedDateTime desc - Sort results$search="keyword" - Search contentOutlook uses cursor-based pagination. The CLI automatically paginates with '--paginate'.
Example:
maton outlook message list --folder Inbox --paginate
# List recent inbox messages
maton outlook message list --folder Inbox --top 25
# Send an email
maton outlook message send --to alice@example.com --subject hi --body "hello"
# Search for messages
maton outlook message search "quarterly report"
const response = await fetch(
'https://api.maton.ai/outlook/v1.0/me/messages?$top=10',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
import os
import requests
response = requests.get(
'https://api.maton.ai/outlook/v1.0/me/messages',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
params={'$top': 10, '$filter': 'isRead eq false'}
)
me as the user identifier for the authenticated userText or HTMLInbox, Drafts, SentItems, etc.curl -g when URLs contain brackets (fields[], sort[], records[]) to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.| Status | Meaning |
|---|---|
| 400 | Missing Outlook connection |
| 401 | Invalid or missing Maton API key |
| 429 | Rate limited (10 req/sec per account) |
| 4xx/5xx | Passthrough error from Microsoft Graph API |
CLI:
maton whoami
maton connection list
Manual:
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
outlook. For example:https://api.maton.ai/outlook/v1.0/me/messageshttps://api.maton.ai/v1.0/me/messages