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 skill when users want to interact with Outlook. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
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