A command-line interface for Microsoft 365 using Exchange Web Services (EWS). Manage your calendar and email directly from the terminal.
# Clone the repository
git clone https://github.com/foeken/clippy.git
cd clippy
# Install dependencies
bun install
# Run directly
bun run src/cli.ts <command>
# Or link globally
bun link
clippy <command>Clippy uses OAuth2 with a refresh token to authenticate against EWS. You need an Azure AD app registration with EWS permissions.
Create a .env file in the project root (or set environment variables):
EWS_CLIENT_ID=your-azure-app-client-id
EWS_REFRESH_TOKEN=your-refresh-token- Clippy uses the refresh token to obtain a short-lived access token via Microsoft's OAuth2 endpoint
- Access tokens are cached in
~/.config/clippy/token-cache.jsonand refreshed automatically when expired - Microsoft may rotate the refresh token on each use — the latest one is cached automatically
# Check who you're logged in as
clippy whoami# Today's events
clippy calendar
# Specific day
clippy calendar tomorrow
clippy calendar monday
clippy calendar 2024-02-15
# Date ranges
clippy calendar monday friday
clippy calendar 2024-02-15 2024-02-20
# Week views
clippy calendar week # This week (Mon-Sun)
clippy calendar lastweek
clippy calendar nextweek
# Include details (attendees, body preview, categories)
clippy calendar -v
clippy calendar week --verbose# Basic event
clippy create-event "Team Standup" 09:00 09:30
# With options
clippy create-event "Project Review" 14:00 15:00 \
--day tomorrow \
--description "Q1 review meeting" \
--attendees "alice@company.com,bob@company.com" \
--teams \
--room "Conference Room A"
# Find an available room automatically
clippy create-event "Workshop" 10:00 12:00 --find-room
# List available rooms
clippy create-event "x" 10:00 11:00 --list-rooms# Daily standup
clippy create-event "Daily Standup" 09:00 09:15 --repeat daily
# Weekly on specific days
clippy create-event "Team Sync" 14:00 15:00 \
--repeat weekly \
--days mon,wed,fri
# Monthly, 10 occurrences
clippy create-event "Monthly Review" 10:00 11:00 \
--repeat monthly \
--count 10
# Every 2 weeks until a date
clippy create-event "Sprint Planning" 09:00 11:00 \
--repeat weekly \
--every 2 \
--until 2024-12-31# List today's events
clippy update-event
# Update by event ID
clippy update-event --id <eventId> --title "New Title"
clippy update-event --id <eventId> --start 10:00 --end 11:00
clippy update-event --id <eventId> --add-attendee "new@company.com"
clippy update-event --id <eventId> --room "Room B"
clippy update-event --id <eventId> --location "Off-site"
clippy update-event --id <eventId> --teams # Add Teams meeting
clippy update-event --id <eventId> --no-teams # Remove Teams meeting
# Show events from a specific day
clippy update-event --day tomorrow# List your events
clippy delete-event
# Delete event by ID
clippy delete-event --id <eventId>
# With cancellation message
clippy delete-event --id <eventId> --message "Sorry, need to reschedule"
# Force delete without notification
clippy delete-event --id <eventId> --force-delete
# Search for events by title
clippy delete-event --search "standup"# List events needing response
clippy respond
# Accept/decline/tentative by event ID
clippy respond accept --id <eventId>
clippy respond decline --id <eventId> --comment "Conflict with another meeting"
clippy respond tentative --id <eventId>
# Don't send response to organizer
clippy respond accept --id <eventId> --no-notify
# Only show required invitations
clippy respond list --only-required# Find free slots next week for yourself and others
clippy findtime nextweek alice@company.com bob@company.com
# Specific date range
clippy findtime monday friday alice@company.com
# Custom duration and working hours
clippy findtime nextweek alice@company.com --duration 60 --start 10 --end 16
# Only check specified people (exclude yourself)
clippy findtime nextweek alice@company.com --solo# Inbox (default)
clippy mail
# Other folders
clippy mail sent
clippy mail drafts
clippy mail deleted
clippy mail archive
# Pagination
clippy mail -n 20 # Show 20 emails
clippy mail -p 2 # Page 2
# Filters
clippy mail --unread # Only unread
clippy mail --flagged # Only flagged
clippy mail -s "invoice" # Search
# Read an email
clippy mail -r 1 # Read email #1
# Download attachments
clippy mail -d 3 # Download from email #3
clippy mail -d 3 -o ~/Downloads# Simple email
clippy send \
--to "recipient@example.com" \
--subject "Hello" \
--body "This is the message body"
# Multiple recipients, CC, BCC
clippy send \
--to "alice@example.com,bob@example.com" \
--cc "manager@example.com" \
--bcc "archive@example.com" \
--subject "Team Update" \
--body "..."
# With markdown formatting
clippy send \
--to "user@example.com" \
--subject "Update" \
--body "**Bold text** and a [link](https://example.com)" \
--markdown
# With attachments
clippy send \
--to "user@example.com" \
--subject "Report" \
--body "Please find attached." \
--attach "report.pdf,data.xlsx"# Reply to an email
clippy mail --reply 1 --message "Thanks for your email!"
# Reply all
clippy mail --reply-all 1 --message "Thanks everyone!"
# Reply with markdown
clippy mail --reply 1 --message "**Got it!** Will do." --markdown
# Save reply as draft instead of sending
clippy mail --reply 1 --message "Draft reply" --draft
# Forward an email
clippy mail --forward 1 --to-addr "colleague@example.com"
clippy mail --forward 1 --to-addr "a@example.com,b@example.com" --message "FYI"# Mark as read/unread
clippy mail --mark-read 1
clippy mail --mark-unread 2
# Flag emails
clippy mail --flag 1
clippy mail --unflag 2
clippy mail --complete 3 # Mark flag as complete
# Move to folder
clippy mail --move 1 --to archive
clippy mail --move 2 --to deleted
clippy mail --move 3 --to "My Custom Folder"# List drafts
clippy drafts
# Read a draft
clippy drafts -r 1
# Create a draft
clippy drafts --create \
--to "recipient@example.com" \
--subject "Draft Email" \
--body "Work in progress..."
# Create with attachment
clippy drafts --create \
--to "user@example.com" \
--subject "Report" \
--body "See attached" \
--attach "report.pdf"
# Edit a draft
clippy drafts --edit 1 --body "Updated content"
clippy drafts --edit 1 --subject "New Subject"
# Send a draft
clippy drafts --send 1
# Delete a draft
clippy drafts --delete 1# List all folders
clippy folders
# Create a folder
clippy folders --create "Projects"
# Rename a folder
clippy folders --rename "Projects" --to "Active Projects"
# Delete a folder
clippy folders --delete "Old Folder"# Search for people
clippy find "john"
# Search for rooms
clippy find "conference" --rooms
# Only people (exclude rooms)
clippy find "smith" --peopleAll commands support:
--json # Output as JSON (for scripting)
--token <token> # Use a specific access token#!/bin/bash
echo "=== Today's Calendar ==="
clippy calendar
echo -e "\n=== Unread Emails ==="
clippy mail --unread -n 5
echo -e "\n=== Pending Invitations ==="
clippy respond# Find a time when everyone is free and create the meeting
clippy create-event "Project Kickoff" 14:00 15:00 \
--day tomorrow \
--attendees "team@company.com" \
--teams \
--find-room \
--description "Initial project planning session"clippy send \
--to "manager@company.com" \
--subject "Weekly Report - $(date +%Y-%m-%d)" \
--body "Please find this week's report attached." \
--attach "weekly-report.pdf"- Bun runtime
- Microsoft 365 account
- Azure AD app registration with EWS permissions (
EWS.AccessAsUser.All)
MIT