Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ npx skills add wondelai/skills/clean-architecture
npx skills add wondelai/skills/release-it
npx skills add wondelai/skills/high-perf-browser
npx skills add wondelai/skills/37signals-way
npx skills add wondelai/skills/microsoft-workspace
```

## Available Skills
Expand Down Expand Up @@ -121,6 +122,7 @@ npx skills add wondelai/skills/37signals-way
| [release-it](https://skills.wondel.ai/skills/release-it/) | Production-ready systems: circuit breakers, bulkheads, timeouts, retry logic | [Michael Nygard](https://x.com/mtnygard)'s [*"Release It!"*](https://www.amazon.com/Release-Design-Deploy-Production-Ready-Software/dp/1680502395?tag=wondelai00-20) |
| [high-perf-browser](https://skills.wondel.ai/skills/high-perf-browser/) | Web performance: network protocols, resource loading, browser rendering | [Ilya Grigorik](https://x.com/igrigorik)'s [*"High Performance Browser Networking"*](https://www.amazon.com/High-Performance-Browser-Networking-performance/dp/1449344763?tag=wondelai00-20) |
| [37signals-way](https://skills.wondel.ai/skills/37signals-way/) | Build less, shape work, ship in six-week cycles with small autonomous teams | [Jason Fried](https://x.com/jasonfried) & [DHH](https://x.com/dhh)'s [*"Getting Real"*](https://www.amazon.com/Getting-Real-Smarter-Successful-Application/dp/0578012812?tag=wondelai00-20), [*"Rework"*](https://www.amazon.com/Rework-Jason-Fried/dp/0307463745?tag=wondelai00-20) & [Ryan Singer](https://x.com/rjs)'s [*"Shape Up"*](https://www.amazon.com/Shape-Up-Circles-Ship-Work/dp/B09ZSY1MWP?tag=wondelai00-20) |
| [microsoft-workspace](https://skills.wondel.ai/skills/microsoft-workspace/) | Outlook integration for email, calendar, contacts via Microsoft Graph API | Community skill — [Andrew Girgis](https://github.com/Andrew-Girgis) |

> **Looking for real-world scenarios?** See [EXAMPLES.md](EXAMPLES.md) for 49 copy-pasteable prompts organized by persona (founders, PMs, marketers, designers, sales, copywriters, solopreneurs).

Expand Down Expand Up @@ -1130,3 +1132,23 @@ These skills were created without directly copying or reproducing content from t
- Common industry practices and terminology

We encourage users to purchase and read the original books for the complete, authoritative treatment of each methodology. The skills in this repository are intended as practical aids, not replacements for the source materials.

### [microsoft-workspace](https://skills.wondel.ai/skills/microsoft-workspace/)

Full Outlook/Hotmail integration via Microsoft Graph API. Email management, calendar operations, and contact lookup — all through a single skill with OAuth2 authentication.

**About the author:** [Andrew Girgis](https://github.com/Andrew-Girgis) — Data Scientist and open-source contributor. Built this skill to give AI agents full Microsoft workspace access with a focus on safe email sending (prevents shell `$` variable mangling).

**Use when you need to:**
- Send, read, search, reply to, or forward emails via Outlook/Hotmail
- Manage calendar events, check free/busy, find open time slots
- Look up contacts or user profile info
- Safely compose emails with dollar amounts or special characters

**Example prompts:**
- "Search my inbox for emails about the project report"
- "Check if I'm free tomorrow at 2pm and schedule a meeting"
- "Reply to that email saying I'll be there"
- "Forward this to my manager"

**Source:** [github.com/Andrew-Girgis/microsoft-workspace-skill](https://github.com/Andrew-Girgis/microsoft-workspace-skill)
204 changes: 204 additions & 0 deletions microsoft-workspace/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
name: microsoft-workspace
description: Outlook Calendar, Email, Contacts, and To-Do integration via Microsoft Graph API. Uses OAuth2 with automatic token refresh. Supports Hotmail/Outlook/Microsoft 365 accounts.
version: 1.2.0
author: hermes-community
license: MIT
required_credential_files:
- path: microsoft_token.json
description: Microsoft OAuth2 token (created by setup script)
- path: microsoft_client_secret.json
description: Microsoft app credentials (from Azure Portal)
metadata:
hermes:
tags: [Microsoft, Outlook, Calendar, Email, OneDrive, Graph API, OAuth, Hotmail]
---

# Microsoft Workspace (Outlook/Hotmail)

Outlook Calendar, Email, Contacts, and To-Do integration via Microsoft Graph API.

## Quick Setup

```bash
# Save credentials
./scripts/auth.sh --client-id "YOUR_CLIENT_ID" --client-secret "YOUR_CLIENT_SECRET"

# Get auth URL and authorize
python3 scripts/setup.py --auth-url
python3 scripts/setup.py --auth-code "PASTE_REDIRECT_URL"

# Verify
./scripts/auth.sh --check
```

See `README.md` for full Azure App Registration setup instructions.

## Scripts

- `scripts/microsoft_api.py` -- API wrapper CLI
- `scripts/setup.py` -- OAuth2 setup (run once to authorize)
- `scripts/auth.sh` -- Credential management and auth verification
- `scripts/safe_mail_send.sh` -- Preview emails before sending (prevents $ mangling and duplicates)

## Usage

```bash
GAPI="python3 ~/.hermes/skills/productivity/microsoft-workspace/scripts/microsoft_api.py"

# --- CALENDAR ---

# List upcoming events (default)
$GAPI calendar list
$GAPI calendar list --all
$GAPI calendar list --start 2026-04-10T00:00:00 --end 2026-04-10T23:59:59

# Create event (auto-adds Teams link)
$GAPI calendar create --summary "Meeting" --start "2026-04-10T15:00:00-04:00" --end "2026-04-10T15:30:00-04:00" --description "Syncing on ideas" --attendees "john@example.com"

# Create invite with video link (uses branded HTML template if configured)
$GAPI calendar invite --summary "Project Sync" --start "2026-04-11T14:00:00-04:00" --end "2026-04-11T14:30:00-04:00" --description "Let's discuss" --attendees "john@example.com" --meet

# Update an existing event (partial -- only update what you pass)
$GAPI calendar update EVENT_ID --summary "New Title"
$GAPI calendar update EVENT_ID --start "2026-04-11T16:00:00-04:00" --end "2026-04-11T16:30:00-04:00"

# Delete event
$GAPI calendar delete EVENT_ID

# Check free/busy status for people
$GAPI calendar freebusy --emails "user@example.com,other@example.com" --start "2026-04-14T09:00:00-04:00" --end "2026-04-14T17:00:00-04:00" --interval 30

# Find open slots where all attendees are free
$GAPI calendar findopen --emails "user@example.com" --start "2026-04-14T09:00:00-04:00" --end "2026-04-14T17:00:00-04:00" --duration 30 --interval 15

# --- EMAIL ---

# List emails (add --unread for unread only, --important for high importance)
$GAPI mail list --max 10
$GAPI mail list --unread
$GAPI mail list --important --folder archive

# Search emails by keyword
$GAPI mail search --query "invoice" --max 5
$GAPI mail search --query "project report" --folder sent

# Get full email content
$GAPI mail get MESSAGE_ID

# Send email
$GAPI mail send --to user@example.com --subject "Hello" --body "Message text"

# Send with attachment (max 3MB)
$GAPI mail send --to user@example.com --subject "Here's the file" --body "See attached" --attachment /path/to/file.png

# Reply to an email
$GAPI mail reply MESSAGE_ID --body "Thanks for the update!"

# Reply-all to an email
$GAPI mail replyall MESSAGE_ID --body "Sounds good, team."

# Forward an email
$GAPI mail forward MESSAGE_ID --to "forward@example.com" --body "FYI"

# List all mail folders
$GAPI mail folders

# Move an email to a different folder (get folder ID from 'mail folders')
$GAPI mail move MESSAGE_ID --folder FOLDER_ID

# --- CONTACTS ---

$GAPI contacts list --max 20

# --- USER PROFILE ---

$GAPI user profile
```

## Safe Email Sending

Use the `safe_mail_send.sh` script to preview before sending:

```bash
SAFE="~/.hermes/skills/productivity/microsoft-workspace/scripts/safe_mail_send.sh"

# Preview only (does not send)
$SAFE --to "user@example.com" --subject "Hello" --body-file /tmp/email_body.txt

# Preview + send
$SAFE --to "user@example.com" --subject "Hello" --body-file /tmp/email_body.txt --confirm

# With attachment
$SAFE --to "user@example.com" --subject "See attached" --body-file /tmp/email_body.txt --attachment /path/to/file.png --confirm
```

The script checks for `$` shell variable issues, large attachments, and missing files before sending.

## Configuration

Optional config at `~/.hermes/microsoft_config.json`:

```json
{
"sender_name": "Your Name",
"agent_name": "YourAgent"
}
```

When set, calendar invites include a branded sign-off. Without this config, invites use a clean template with no personal info.

Set via: `./scripts/auth.sh --config --name "Your Name" --agent "AgentName"`

## Output Format

All commands return JSON or structured text. Key fields:
- **Calendar list**: `[{id, subject, start, end, notes, meet, link}]`
- **Calendar create**: `{status, id, subject, start, end, link, meet, attendees}`
- **Calendar free/busy**: `[{email, status, availability}]`
- **Calendar find open**: `[{start, end, duration}]`
- **Mail list**: `[{id, from, subject, date, isRead, importance, preview}]`
- **Mail search**: `[{id, from, subject, date, preview}]`
- **Mail folders**: `[{id, name, total, unread}]`
- **Contacts list**: `[{displayName, emailAddresses, phones}]`
- **User profile**: `{displayName, email, jobTitle, office}`

## Sending Emails Safely (IMPORTANT)

**The `$` character is interpreted as a shell variable.** `$20` becomes empty (treated as `$2` + `0`). This causes mangled subjects and forces re-sends.

**NEVER do this:**
```bash
$GAPI mail send --to user@example.com --subject "Refund of $20" --body "I paid $50"
```

**ALWAYS do this:** Write the body to a temp file first:
```bash
cat > /tmp/email_body.txt << 'EOF'
Subject: Refund of $20

Hi, I was charged $20 and would like a refund.
EOF

# Preview
echo "To: user@example.com"
cat /tmp/email_body.txt

# Send
BODY=$(cat /tmp/email_body.txt)
$GAPI mail send --to "user@example.com" --subject "Refund of $20" --body "$BODY"
```

Or use `safe_mail_send.sh` which handles this automatically.

## Troubleshooting

| Problem | Fix |
|---------|-----|
| `NOT_AUTHENTICATED` | Run `auth.sh --check` then re-authorize |
| `REFRESH_FAILED` | Token expired -- re-run `setup.py --auth-url` |
| `AADSTS700016` | Wrong client_id or tenant_id |
| `AADSTS65001` | User not consented -- check API permissions |
| `Insufficient privileges` | Need Calendars.ReadWrite permission |
| `$20` becomes `0` | Use `safe_mail_send.sh` or temp file pattern |
| Attachment too large | Max 3MB -- compress or split the file |
Loading