Microsoft Graph skill: Outlook & OneDrive access for mikpar@outlook.dk
This commit is contained in:
parent
b777ac65a1
commit
388f3256a3
4 changed files with 318 additions and 125 deletions
110
SKILL.md
110
SKILL.md
|
|
@ -1,81 +1,77 @@
|
||||||
---
|
---
|
||||||
name: microsoft-graph
|
name: microsoft-graph
|
||||||
description: Microsoft Graph API access for Mikkel's Outlook and OneDrive (mikpar@outlook.dk). Use for email, calendar, and file operations via Graph API. Triggers on Outlook, OneDrive, or Microsoft 365 tasks.
|
description: Microsoft Graph API access for Mikkel's Outlook (mikpar@outlook.dk) and OneDrive. Use for reading/writing emails, calendar, and files. Triggers on Outlook, OneDrive, Microsoft 365 tasks.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Microsoft Graph Skill
|
# Microsoft Graph Skill
|
||||||
|
|
||||||
Microsoft Graph API client for Mikkel's personal Microsoft account (mikpar@outlook.dk).
|
Access to Mikkel's Microsoft 365 account (mikpar@outlook.dk) via Graph API.
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
- 📧 **Mail** — Read, send, organize emails
|
||||||
|
- 📁 **OneDrive** — Read/write files
|
||||||
|
- 📅 **Calendar** — Read events (if permitted)
|
||||||
|
- 👤 **Profile** — User info
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Uses OAuth 2.0 device code flow with delegated permissions.
|
||||||
|
|
||||||
|
**Credentials:**
|
||||||
|
- **Account:** mikpar@outlook.dk
|
||||||
|
- **Client ID:** 14d82eec-204b-4c2f-b7e8-296a70dab67e
|
||||||
|
- **Tenant:** consumers
|
||||||
|
- **Token file:** `~/.config/microsoft-graph-tokens.json`
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Authenticate (first time / token expired)
|
# List mail folders
|
||||||
python3 scripts/graph_client.py auth
|
python3 ~/.openclaw/skills/microsoft-graph/scripts/graph_api.py folders
|
||||||
|
|
||||||
# List recent emails
|
# List emails in Inbox
|
||||||
python3 scripts/graph_client.py mail list --limit 10
|
python3 ~/.openclaw/skills/microsoft-graph/scripts/graph_api.py emails --folder Indbakke --limit 10
|
||||||
|
|
||||||
# Read specific email
|
# Get email by ID
|
||||||
python3 scripts/graph_client.py mail read --id <message_id>
|
python3 ~/.openclaw/skills/microsoft-graph/scripts/graph_api.py email --id <message_id>
|
||||||
|
|
||||||
# Send email
|
|
||||||
python3 scripts/graph_client.py mail send --to "to@example.com" --subject "Test" --body "Hello"
|
|
||||||
|
|
||||||
# List OneDrive root
|
# List OneDrive root
|
||||||
python3 scripts/graph_client.py drive list
|
python3 ~/.openclaw/skills/microsoft-graph/scripts/graph_api.py onedrive
|
||||||
|
|
||||||
# List folder contents
|
# Refresh token (when expired)
|
||||||
python3 scripts/graph_client.py drive list --path "Documents/Parlobyg"
|
python3 ~/.openclaw/skills/microsoft-graph/scripts/graph_api.py refresh
|
||||||
|
|
||||||
# Download file
|
|
||||||
python3 scripts/graph_client.py drive download --path "file.pdf" --output ./file.pdf
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Credentials
|
## Token Refresh
|
||||||
|
|
||||||
- **Account:** mikpar@outlook.dk
|
Tokens expire after ~1 hour. Use refresh command or re-authenticate:
|
||||||
- **Client ID:** 96861287-203e-4d84-ad3b-379d63ba5eb2
|
|
||||||
- **Tenant ID:** 3a22994f-512f-447e-b8fa-19bbc849bd0c
|
|
||||||
- **Client Secret:** kiB8Q~TmhWDKHRdLqBi_RqRIIAjTkljyL6xE0aHU
|
|
||||||
|
|
||||||
## Authentication
|
```bash
|
||||||
|
python3 ~/.openclaw/skills/microsoft-graph/scripts/auth.py
|
||||||
|
```
|
||||||
|
|
||||||
Uses **device code flow** for personal Microsoft accounts:
|
## Folder Structure (mikpar@outlook.dk)
|
||||||
1. Run `python3 scripts/graph_client.py auth`
|
|
||||||
2. Open the URL shown (https://microsoft.com/devicelogin)
|
|
||||||
3. Enter the code displayed
|
|
||||||
4. Sign in with mikpar@outlook.dk
|
|
||||||
5. Token is saved to `~/.config/microsoft-graph/token.json`
|
|
||||||
|
|
||||||
Token auto-refreshes. Re-auth only needed if refresh token expires (~90 days).
|
```
|
||||||
|
📥 Indbakke
|
||||||
## Capabilities
|
├─ Aftaler og bookinger (99)
|
||||||
|
├─ CHRISTIAN - ADMINISTRATION (1915)
|
||||||
### Outlook Email
|
├─ JOAKIM - PROJEKT (3)
|
||||||
- 📧 List/search inbox
|
├─ MESTER MANUALEN (8)
|
||||||
- 📖 Read messages
|
├─ MICHELLE - SUPPORT (2813)
|
||||||
- ✉️ Send emails
|
├─ Online Handel (1022)
|
||||||
- 📝 Create drafts
|
├─ ERHVERV
|
||||||
- 📁 Manage folders
|
│ ├─ PARLO BYG ApS
|
||||||
|
│ └─ Parlo Holding ApS
|
||||||
### OneDrive
|
├─ ROUND TABLE
|
||||||
- 📂 Browse folders
|
│ ├─ Frederik Stenild
|
||||||
- 🔍 Search files
|
│ └─ Lasse Olsen
|
||||||
- ⬇️ Download files
|
└─ PRIVAT (+ subfolders)
|
||||||
- ⬆️ Upload files
|
```
|
||||||
- 🔗 Create sharing links
|
|
||||||
|
|
||||||
### Calendar (if needed)
|
|
||||||
- 📅 List events
|
|
||||||
- ➕ Create events
|
|
||||||
- 🔔 Check availability
|
|
||||||
|
|
||||||
## API Reference
|
|
||||||
|
|
||||||
- Base URL: `https://graph.microsoft.com/v1.0`
|
|
||||||
- Scopes: `Mail.Read Mail.Send Files.ReadWrite User.Read offline_access`
|
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- [Graph API Docs](references/graph-api.md)
|
- [Graph API Reference](references/graph-api.md)
|
||||||
|
- [Mail API](https://learn.microsoft.com/en-us/graph/api/resources/mail-api-overview)
|
||||||
|
- [OneDrive API](https://learn.microsoft.com/en-us/graph/api/resources/onedrive)
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,31 @@
|
||||||
# Microsoft Graph API Reference
|
# Microsoft Graph API Reference
|
||||||
|
|
||||||
## Base URL
|
## Base URL
|
||||||
`https://graph.microsoft.com/v1.0`
|
```
|
||||||
|
https://graph.microsoft.com/v1.0
|
||||||
|
```
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
Bearer token in Authorization header:
|
||||||
|
```
|
||||||
|
Authorization: Bearer {access_token}
|
||||||
|
```
|
||||||
|
|
||||||
Uses OAuth 2.0 device code flow for personal Microsoft accounts.
|
## Mail Endpoints
|
||||||
|
|
||||||
### Endpoints
|
### List folders
|
||||||
- Device code: `https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode`
|
```
|
||||||
- Token: `https://login.microsoftonline.com/consumers/oauth2/v2.0/token`
|
GET /me/mailFolders
|
||||||
|
GET /me/mailFolders/{id}/childFolders
|
||||||
### Scopes
|
```
|
||||||
- `Mail.Read` — Read emails
|
|
||||||
- `Mail.Send` — Send emails
|
|
||||||
- `Files.ReadWrite` — OneDrive access
|
|
||||||
- `User.Read` — User profile
|
|
||||||
- `offline_access` — Refresh tokens
|
|
||||||
|
|
||||||
## Mail API
|
|
||||||
|
|
||||||
### List messages
|
### List messages
|
||||||
```
|
```
|
||||||
GET /me/mailFolders/inbox/messages?$top=10&$orderby=receivedDateTime desc
|
GET /me/mailFolders/{folder_id}/messages
|
||||||
|
GET /me/messages?$filter=...
|
||||||
```
|
```
|
||||||
|
|
||||||
### Read message
|
### Get message
|
||||||
```
|
```
|
||||||
GET /me/messages/{id}
|
GET /me/messages/{id}
|
||||||
```
|
```
|
||||||
|
|
@ -35,24 +35,26 @@ GET /me/messages/{id}
|
||||||
POST /me/sendMail
|
POST /me/sendMail
|
||||||
{
|
{
|
||||||
"message": {
|
"message": {
|
||||||
"subject": "Subject",
|
"subject": "...",
|
||||||
"body": {"contentType": "Text", "content": "Body"},
|
"body": {"contentType": "Text", "content": "..."},
|
||||||
"toRecipients": [{"emailAddress": {"address": "to@example.com"}}]
|
"toRecipients": [{"emailAddress": {"address": "..."}}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Search messages
|
### Move message
|
||||||
```
|
```
|
||||||
GET /me/messages?$search="from:sender@example.com"
|
POST /me/messages/{id}/move
|
||||||
|
{"destinationId": "{folder_id}"}
|
||||||
```
|
```
|
||||||
|
|
||||||
### List folders
|
### Copy message
|
||||||
```
|
```
|
||||||
GET /me/mailFolders
|
POST /me/messages/{id}/copy
|
||||||
|
{"destinationId": "{folder_id}"}
|
||||||
```
|
```
|
||||||
|
|
||||||
## OneDrive API
|
## OneDrive Endpoints
|
||||||
|
|
||||||
### List root
|
### List root
|
||||||
```
|
```
|
||||||
|
|
@ -64,58 +66,25 @@ GET /me/drive/root/children
|
||||||
GET /me/drive/root:/{path}:/children
|
GET /me/drive/root:/{path}:/children
|
||||||
```
|
```
|
||||||
|
|
||||||
### Get file metadata
|
### Get file content
|
||||||
```
|
```
|
||||||
GET /me/drive/root:/{path}
|
GET /me/drive/items/{item_id}/content
|
||||||
```
|
```
|
||||||
|
|
||||||
### Download file
|
### Upload file
|
||||||
Get the `@microsoft.graph.downloadUrl` from file metadata.
|
|
||||||
|
|
||||||
### Upload small file (<4MB)
|
|
||||||
```
|
```
|
||||||
PUT /me/drive/root:/{path}:/content
|
PUT /me/drive/root:/{path}:/content
|
||||||
Content-Type: application/octet-stream
|
|
||||||
|
|
||||||
<file bytes>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create folder
|
## Useful Query Parameters
|
||||||
```
|
|
||||||
POST /me/drive/root/children
|
|
||||||
{
|
|
||||||
"name": "New Folder",
|
|
||||||
"folder": {}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Calendar API
|
- `$top=N` - Limit results
|
||||||
|
- `$skip=N` - Pagination offset
|
||||||
### List events
|
- `$select=field1,field2` - Select specific fields
|
||||||
```
|
- `$filter=field eq 'value'` - Filter results
|
||||||
GET /me/events?$top=10&$orderby=start/dateTime
|
- `$orderby=field desc` - Sort results
|
||||||
```
|
|
||||||
|
|
||||||
### Create event
|
|
||||||
```
|
|
||||||
POST /me/events
|
|
||||||
{
|
|
||||||
"subject": "Meeting",
|
|
||||||
"start": {"dateTime": "2026-03-24T10:00:00", "timeZone": "Europe/Copenhagen"},
|
|
||||||
"end": {"dateTime": "2026-03-24T11:00:00", "timeZone": "Europe/Copenhagen"}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
Common errors:
|
|
||||||
- `401 Unauthorized` — Token expired, need to refresh or re-auth
|
|
||||||
- `403 Forbidden` — Missing permissions
|
|
||||||
- `404 NotFound` — Resource doesn't exist
|
|
||||||
- `429 TooManyRequests` — Rate limited, back off
|
|
||||||
|
|
||||||
## Rate Limits
|
## Rate Limits
|
||||||
|
|
||||||
- Per-app: ~10,000 requests / 10 minutes
|
- 10,000 requests per 10 minutes per app
|
||||||
- Per-mailbox: ~10,000 requests / 10 minutes
|
- Throttled requests return 429 Too Many Requests
|
||||||
- Throttled responses include `Retry-After` header
|
|
||||||
|
|
|
||||||
59
scripts/auth.py
Executable file
59
scripts/auth.py
Executable file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Microsoft Graph OAuth authentication (device code flow)."""
|
||||||
|
|
||||||
|
import msal
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
TOKEN_FILE = os.path.expanduser("~/.config/microsoft-graph-tokens.json")
|
||||||
|
CLIENT_ID = "14d82eec-204b-4c2f-b7e8-296a70dab67e"
|
||||||
|
SCOPES = [
|
||||||
|
"https://graph.microsoft.com/Mail.Read",
|
||||||
|
"https://graph.microsoft.com/Mail.ReadWrite",
|
||||||
|
"https://graph.microsoft.com/Mail.Send",
|
||||||
|
"https://graph.microsoft.com/Files.Read",
|
||||||
|
"https://graph.microsoft.com/Files.ReadWrite",
|
||||||
|
"https://graph.microsoft.com/User.Read"
|
||||||
|
]
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = msal.PublicClientApplication(CLIENT_ID, authority="https://login.microsoftonline.com/consumers")
|
||||||
|
|
||||||
|
flow = app.initiate_device_flow(scopes=SCOPES)
|
||||||
|
|
||||||
|
if "user_code" not in flow:
|
||||||
|
print(f"❌ Failed to create device flow: {flow}")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\n🔐 Microsoft Sign-In Required\n")
|
||||||
|
print(f"1. Go to: {flow['verification_uri']}")
|
||||||
|
print(f"2. Enter code: {flow['user_code']}")
|
||||||
|
print("3. Sign in with your Microsoft account\n")
|
||||||
|
print("Waiting for authorization...")
|
||||||
|
|
||||||
|
result = app.acquire_token_by_device_flow(flow)
|
||||||
|
|
||||||
|
if "access_token" in result:
|
||||||
|
tokens = {
|
||||||
|
"access_token": result["access_token"],
|
||||||
|
"refresh_token": result.get("refresh_token"),
|
||||||
|
"id_token": result.get("id_token"),
|
||||||
|
"expires_in": result.get("expires_in"),
|
||||||
|
"client_id": CLIENT_ID,
|
||||||
|
"scopes": SCOPES,
|
||||||
|
"account": result.get("id_token_claims", {}).get("preferred_username", "unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True)
|
||||||
|
with open(TOKEN_FILE, "w") as f:
|
||||||
|
json.dump(tokens, f, indent=2)
|
||||||
|
|
||||||
|
print(f"\n✅ Authorization successful!")
|
||||||
|
print(f"Account: {tokens['account']}")
|
||||||
|
print(f"Token saved to: {TOKEN_FILE}")
|
||||||
|
else:
|
||||||
|
print(f"\n❌ Error: {result.get('error')}")
|
||||||
|
print(f"Description: {result.get('error_description')}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
169
scripts/graph_api.py
Executable file
169
scripts/graph_api.py
Executable file
|
|
@ -0,0 +1,169 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Microsoft Graph API client for Outlook and OneDrive."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import requests
|
||||||
|
|
||||||
|
TOKEN_FILE = os.path.expanduser("~/.config/microsoft-graph-tokens.json")
|
||||||
|
GRAPH_BASE = "https://graph.microsoft.com/v1.0"
|
||||||
|
|
||||||
|
def load_tokens():
|
||||||
|
"""Load access tokens from file."""
|
||||||
|
if not os.path.exists(TOKEN_FILE):
|
||||||
|
print(f"❌ Token file not found: {TOKEN_FILE}")
|
||||||
|
print("Run: python3 ~/.openclaw/skills/microsoft-graph/scripts/auth.py")
|
||||||
|
sys.exit(1)
|
||||||
|
with open(TOKEN_FILE, "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
def get_headers():
|
||||||
|
"""Get authorization headers."""
|
||||||
|
tokens = load_tokens()
|
||||||
|
return {"Authorization": f"Bearer {tokens['access_token']}"}
|
||||||
|
|
||||||
|
def api_get(endpoint, params=None):
|
||||||
|
"""Make GET request to Graph API."""
|
||||||
|
url = f"{GRAPH_BASE}{endpoint}"
|
||||||
|
response = requests.get(url, headers=get_headers(), params=params)
|
||||||
|
if response.status_code == 401:
|
||||||
|
print("❌ Token expired. Run: python3 ~/.openclaw/skills/microsoft-graph/scripts/graph_api.py refresh")
|
||||||
|
sys.exit(1)
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def list_folders(parent_id=None):
|
||||||
|
"""List mail folders."""
|
||||||
|
if parent_id:
|
||||||
|
data = api_get(f"/me/mailFolders/{parent_id}/childFolders", {"$top": 100})
|
||||||
|
else:
|
||||||
|
data = api_get("/me/mailFolders", {"$top": 100})
|
||||||
|
|
||||||
|
folders = data.get("value", [])
|
||||||
|
for f in folders:
|
||||||
|
name = f["displayName"]
|
||||||
|
count = f["totalItemCount"]
|
||||||
|
children = f["childFolderCount"]
|
||||||
|
print(f"📁 {name} ({count} items, {children} subfolders) [id: {f['id'][:20]}...]")
|
||||||
|
return folders
|
||||||
|
|
||||||
|
def list_emails(folder_name="Inbox", limit=10):
|
||||||
|
"""List emails in a folder."""
|
||||||
|
# Get folder ID
|
||||||
|
data = api_get("/me/mailFolders", {"$top": 100})
|
||||||
|
folder_id = None
|
||||||
|
for f in data.get("value", []):
|
||||||
|
if f["displayName"].lower() == folder_name.lower():
|
||||||
|
folder_id = f["id"]
|
||||||
|
break
|
||||||
|
|
||||||
|
if not folder_id:
|
||||||
|
print(f"❌ Folder not found: {folder_name}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get messages
|
||||||
|
messages = api_get(f"/me/mailFolders/{folder_id}/messages", {
|
||||||
|
"$top": limit,
|
||||||
|
"$select": "id,subject,from,receivedDateTime,isRead",
|
||||||
|
"$orderby": "receivedDateTime desc"
|
||||||
|
})
|
||||||
|
|
||||||
|
for msg in messages.get("value", []):
|
||||||
|
read = "✓" if msg["isRead"] else "○"
|
||||||
|
sender = msg.get("from", {}).get("emailAddress", {}).get("address", "?")
|
||||||
|
date = msg["receivedDateTime"][:10]
|
||||||
|
subject = msg.get("subject", "(no subject)")[:50]
|
||||||
|
print(f"{read} [{date}] {sender}: {subject}")
|
||||||
|
|
||||||
|
return messages.get("value", [])
|
||||||
|
|
||||||
|
def get_email(message_id):
|
||||||
|
"""Get full email content."""
|
||||||
|
msg = api_get(f"/me/messages/{message_id}")
|
||||||
|
print(f"Subject: {msg.get('subject')}")
|
||||||
|
print(f"From: {msg.get('from', {}).get('emailAddress', {}).get('address')}")
|
||||||
|
print(f"Date: {msg.get('receivedDateTime')}")
|
||||||
|
print(f"\n{msg.get('body', {}).get('content', '')[:2000]}")
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def list_onedrive(path="/"):
|
||||||
|
"""List OneDrive files."""
|
||||||
|
if path == "/":
|
||||||
|
data = api_get("/me/drive/root/children", {"$top": 50})
|
||||||
|
else:
|
||||||
|
data = api_get(f"/me/drive/root:/{path}:/children", {"$top": 50})
|
||||||
|
|
||||||
|
items = data.get("value", [])
|
||||||
|
for item in items:
|
||||||
|
icon = "📁" if "folder" in item else "📄"
|
||||||
|
size = item.get("size", 0)
|
||||||
|
name = item["name"]
|
||||||
|
print(f"{icon} {name} ({size} bytes)")
|
||||||
|
return items
|
||||||
|
|
||||||
|
def refresh_token():
|
||||||
|
"""Refresh the access token."""
|
||||||
|
import msal
|
||||||
|
|
||||||
|
tokens = load_tokens()
|
||||||
|
client_id = tokens.get("client_id", "14d82eec-204b-4c2f-b7e8-296a70dab67e")
|
||||||
|
|
||||||
|
app = msal.PublicClientApplication(client_id, authority="https://login.microsoftonline.com/consumers")
|
||||||
|
|
||||||
|
# Try to refresh
|
||||||
|
accounts = app.get_accounts()
|
||||||
|
if accounts:
|
||||||
|
result = app.acquire_token_silent(tokens.get("scopes", []), account=accounts[0])
|
||||||
|
if result and "access_token" in result:
|
||||||
|
tokens["access_token"] = result["access_token"]
|
||||||
|
with open(TOKEN_FILE, "w") as f:
|
||||||
|
json.dump(tokens, f, indent=2)
|
||||||
|
print("✅ Token refreshed!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Need re-auth
|
||||||
|
print("❌ Cannot refresh. Please re-authenticate:")
|
||||||
|
print("python3 ~/.openclaw/skills/microsoft-graph/scripts/auth.py")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Microsoft Graph API client")
|
||||||
|
subparsers = parser.add_subparsers(dest="command", help="Commands")
|
||||||
|
|
||||||
|
# folders
|
||||||
|
folders_p = subparsers.add_parser("folders", help="List mail folders")
|
||||||
|
folders_p.add_argument("--parent", help="Parent folder ID")
|
||||||
|
|
||||||
|
# emails
|
||||||
|
emails_p = subparsers.add_parser("emails", help="List emails")
|
||||||
|
emails_p.add_argument("--folder", default="Indbakke", help="Folder name")
|
||||||
|
emails_p.add_argument("--limit", type=int, default=10, help="Number of emails")
|
||||||
|
|
||||||
|
# email
|
||||||
|
email_p = subparsers.add_parser("email", help="Get email content")
|
||||||
|
email_p.add_argument("--id", required=True, help="Message ID")
|
||||||
|
|
||||||
|
# onedrive
|
||||||
|
od_p = subparsers.add_parser("onedrive", help="List OneDrive files")
|
||||||
|
od_p.add_argument("--path", default="/", help="Path")
|
||||||
|
|
||||||
|
# refresh
|
||||||
|
subparsers.add_parser("refresh", help="Refresh access token")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.command == "folders":
|
||||||
|
list_folders(args.parent)
|
||||||
|
elif args.command == "emails":
|
||||||
|
list_emails(args.folder, args.limit)
|
||||||
|
elif args.command == "email":
|
||||||
|
get_email(args.id)
|
||||||
|
elif args.command == "onedrive":
|
||||||
|
list_onedrive(args.path)
|
||||||
|
elif args.command == "refresh":
|
||||||
|
refresh_token()
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in a new issue