AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Outlook Graph

skill-dbhq-uk-outlook-graph-skill-outlook-graph · by dbhq-uk

Use for email and calendar operations - checking inbox, sending emails, viewing calendar, scheduling events. Trigger on phrases like "check email", "draft email", "my calendar", "schedule", "am I free".

No reviews yet
0 installs
17 views
0.0% view→install

Install

$ agentstack add skill-dbhq-uk-outlook-graph-skill-outlook-graph

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-dbhq-uk-outlook-graph-skill-outlook-graph)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
22d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Outlook Graph? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Outlook Email & Calendar

Access Microsoft 365 Outlook email and calendar via Microsoft Graph API.

CRITICAL: Replies preserve ALL original recipients (reply-all by default)

reply, mdreply, and followup use Microsoft Graph's createReplyAll endpoint. The new draft includes every To: and Cc: recipient from the original message — not just the sender.

Mandatory rules:

  1. Always read the original message's full To: and Cc: lists BEFORE creating a reply. Use a direct API call if read truncates: curl … "/me/messages/?$select=toRecipients,ccRecipients". Knowing who's on the thread is part of "reading the full body end-to-end" — do not skip it.
  2. After creating any reply draft, confirm the displayed To:, Cc:, and Bcc: lines match what you intended. All three reply commands now print every recipient (not just To[0]). If the list looks short, the original might have had CCs you missed — re-check before sending.
  3. If you genuinely want sender-only, create the reply, then run update to and update cc "" (or manually edit) to trim recipients. Default is "everyone stays in the loop".
  4. Never assume a single-recipient To: means a single-recipient thread. Estate agents, solicitors, accountants, and courts routinely Cc colleagues, assistants, and audit addresses. Dropping those CCs on reply is a real harm — they stop seeing the conversation.

This rule exists because a previous reply silently dropped two CCs (assistant addresses on an estate-agent thread); the recipients had to be looped back in via a follow-up email. Reply-all is now the default to make recipient loss impossible by accident.

CRITICAL: Reading email content

preview is a snippet (first ~200 chars of body), not the full message. NEVER use preview to analyse, summarise, respond to, or report on email content. A short preview does NOT mean a short message — the message can continue for many paragraphs and contain attachments, requests, deadlines, or substantive content not visible in the preview.

Mandatory rules:

  1. Use read for any substantive engagement with an email — analysis, summary, reply, decision-making, documentation. Always.
  2. Use preview only for navigation — finding the right message ID from a list, confirming a subject line, checking date/sender. Never for content.
  3. If the read output gets truncated by terminal/tool limits, extract the body via grep or jq with a wide enough regex to capture the whole message. Do not stop at the first match.
  4. Before replying to or reporting on a message, confirm internally: "Have I read the full body end-to-end, including any attachment list and request lines?"
  5. For long reply chains: the read output includes the quoted prior chain. Identify the body of the current message (between the headers --- separator and the start of the quoted chain) and ensure that body is fully captured before doing anything else.

This rule exists because trusting previews has led to missing critical content (attachments, action requests, deadlines, off-chain coordination signals). It is non-negotiable.

Time and date awareness

Email correspondence routinely uses relative times — "today", "yesterday", "by tomorrow", "this morning", "by EOD Tuesday". Each of those is ambiguous without an anchor.

Mandatory rules:

  1. At the start of any email work, run date via Bash to confirm the current date/time. Never assume the date from earlier in the conversation — the conversation may span days, and the system date can roll over.
  2. When computing deadlines or "ago" references, anchor against actual date output, not memory. Example: an email timestamped 2026-05-06T16:10:58Z is Wednesday 6 May at 17:10 BST (UTC+1 in summer), not yesterday.
  3. When an email is about to be sent, confirm the date in the planned send is correct (the date you're embedding in the body must match the date the email will actually arrive).
  4. Track timezone explicitly (BST vs UTC). UK summer time = UTC+1. Microsoft Graph timestamps are UTC.
  5. Check OUTLOOK_TZ before quoting any calendar time. All calendar commands report and accept wall-clock time in the configured timezone, which defaults to the system timezone. Servers, containers and CI boxes are almost always UTC while the mailbox owner is not — and then a 14:00 London meeting is reported as "13:00". Same instant, wrong wall-clock, missed meeting. The calendar script prints its active timezone and warns when it is UTC-by-default; if that zone is not the user's, export OUTLOOK_TZ (e.g. OUTLOOK_TZ=Europe/London) before trusting any time.

If unsure of the date or time, run date and date -u (UTC) before responding.

Email font and formatting preferences

The skill applies these inline styles to every markdown-converted email body, on every command (mddraft, mdreply, forward, followup, update mdbody):

| Property | Value | Why inline | |---|---|---| | Font family | 'Aptos', 'Aptos Display', 'Segoe UI', Roboto, sans-serif | Aptos is the Microsoft 365 default since 2024. Falls back to Segoe UI on older Outlook, Roboto / system sans on non-Microsoft clients. Inline style="" survives Outlook's `-block stripping. | | **Font size** | 14px | Readable, professional | | **Line height** | 1.5 (mddraft / update mdbody) or 1.6 (mdreply / forward / followup) | Comfortable spacing | | **Colour** | #333 | Soft black; avoids harsh #000 | | **Paragraph margin** | 0 0 14px 0 (inline on every tag) | Outlook ignores margins from ` blocks but respects inline. Without this, paragraphs collapse together until Outlook re-renders the draft after an edit. |

All of this is implemented in ONE place: the md_to_html helper (and its FONT_STACK variable) in scripts/outlook-graph-mail.sh. To change font preferences globally, edit that helper.

Multiple accounts

Each account stores credentials under ~/.outlook-graph//. The active account is selected by (in order of precedence): --account / -a flag, the OUTLOOK_ACCOUNT env var, then default.

# Default account
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh inbox

# Named account (flag)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh -a work inbox

# Named account (env var)
OUTLOOK_ACCOUNT=work ${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh inbox

# List configured accounts
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-token.sh list

# Add a new account (reuses existing Azure app registration if one exists)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-setup.sh --account work

An existing single-account install at ~/.outlook-graph/{config,credentials,id_cache}.json is auto-migrated to ~/.outlook-graph/default/ on the first run of any script.

Calendar timezone is auto-detected from the system. Override with OUTLOOK_TZ, e.g. OUTLOOK_TZ=America/New_York ${CLAUDE_SKILL_DIR}/scripts/outlook-graph-calendar.sh today.

Prerequisites

  • Credentials configured in ~/.outlook-graph// (run setup if not done)
  • Azure CLI, jq, curl installed

Note: Tokens are automatically refreshed when needed. No manual intervention required.

Email Operations

Reading Email

# List inbox (default 10 messages)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh inbox

# List more messages
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh inbox 25

# Unread only
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh unread

# Focused inbox only
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh focused

# List sent items (your sent emails)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh sent
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh sent 25

# List messages from any folder by name (searches recursively)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh folder "Projects" 20

# Filter by sender (newest first)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh from "john@example.com"

# Search emails. Free text searches across fields; add a count (default 10, max
# 1000, or "all"). Results come back ranked by Graph, then sorted newest-first.
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh search "project update"
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh search "invoice" 50

# Search with KQL for precision: field operators (subject:, from:, to:, body:)
# and booleans (AND/OR/NOT). The query is passed through to Graph's $search.
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh search 'subject:invoice AND from:jane@example.com'
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh search 'from:acme.com AND body:renewal' all

# Messages flagged for follow-up (newest first)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh flagged

# The whole conversation a message belongs to (oldest first) - use this to see
# a full back-and-forth thread across inbox and sent items
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh thread 

# Read full message (use ID from list)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh read 

# Quick preview (subject, from, date, body preview)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh preview 

Sending Email

# Create plain text draft
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh draft "recipient@example.com" "Subject" "Body text"

# Create markdown-formatted draft (converts to HTML)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh mddraft "recipient@example.com" "Subject" "**Bold** and _italic_ text"

# Send a draft (use draft ID)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh send 

# Reply to a message (plain text - creates draft, REPLY-ALL: includes original To: + Cc:)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh reply  "Reply body"

# Reply with markdown formatting (converts to HTML - creates draft, REPLY-ALL: includes original To: + Cc:)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh mdreply  "**Bold** reply with _formatting_"

# (For sender-only reply, create the draft then trim recipients via `update to`/`update cc`.)

# Send reply draft
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh send 

# Forward a message (creates a DRAFT with the quoted message + its attachments).
# Recipients are comma/semicolon-separated; the optional comment is markdown.
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh forward  "to@example.com"
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh forward  "a@x.com, b@y.com" "FYI - see the thread below, **deadline is Friday**."

# Follow up on your own sent email (chaser)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh followup 
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh followup  "Custom follow-up body in **markdown**"

# Update an existing draft
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  subject "New subject line"
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  body "Plain text body"
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  mdbody "**Markdown** body"
# to: replaces the To line. cc/bcc: append to existing (deduped, case-insensitive).
# All three accept a comma/semicolon-separated list of addresses.
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  to "new-recipient@example.com"
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  cc "one@example.com, two@example.com"
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  bcc "bcc@example.com"
# Pass an empty string to clear all CC/BCC recipients (e.g. to trim a reply-all to sender-only):
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  cc ""
# Mark a draft high/low importance:
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  importance high
# Send as an alias (see "Sending as an alias" below):
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  from "alias@example.com"

# List drafts
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh drafts

Note: mddraft, mdreply, and update mdbody require pandoc for markdown conversion. Install with brew install pandoc (macOS) or apt install pandoc (Linux).

Sending as an alias

A mailbox can send as its primary address or any of its aliases (proxy addresses). List them first — never guess an alias:

${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh aliases

Set the From address on any draft with update from. This works on every draft — including those made by reply, mdreply, forward, and followup — so it is the way to send as an alias:

# Draft, set the alias, confirm, then send
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh draft "recipient@example.com" "Subject" "Body"
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  from "alias@example.com"
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh send 

# Replies work the same way - create the reply, then set the alias
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh mdreply  "**Thanks** - see below."
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh update  from "alias@example.com"

To default every new draft / mddraft to an alias, set OUTLOOK_FROM_ADDRESS (these apply only to the two create commands, not to replies — use update from for those):

OUTLOOK_FROM_ADDRESS="alias@example.com" ${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh draft "to@example.com" "Subject" "Body"

Rules and behaviour:

  1. Always confirm the From line with the user before sending as an alias. Which identity a message goes out as is as consequential as who receives it — update from and send both print the From address, so check it.
  2. Tenant support is required. Send-from-alias only works when the tenant has SendFromAliasEnabled set (Set-OrganizationConfig -SendFromAliasEnabled $true). Without it, Exchange silently rewrites the From back to the primary address — so verify a test send actually arrived as the alias before relying on it.
  3. An unrecognised address warns rather than blocks, because SendAs rights on a shared mailbox are real but never appear in this mailbox's alias list. If the address genuinely is not permitted, send fails with ErrorSendAsDenied and nothing is sent — a wrong alias cannot leak out.
  4. OUTLOOK_FROM_NAME is usually ignored. Exchange overrides the display name with the mailbox's own for addresses it owns; the address is what changes.
  5. Check the alias domain's DNS before sending externally. An alias on a domain with no DKIM signing or DMARC record may be spam-filtered by strict receivers even though the send itself succeeds.

IMPORTANT: Always prefer mdreply over reply for professional emails - plain text replies look poorly formatted in Outlook.

Reply-chain preservation: update mdbody automatically preserves the quoted reply chain on drafts created via mdreply or followup (an invisible ` marker is injected when the reply is created, and update mdbody splits on it). The plain update body command does NOT preserve the chain - if you need to edit a reply draft body, use update mdbody`.

Attachments

Reading attachments:

# List attachments on a message
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh attachments 

# Download ALL attachments to ./inbox/
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh download 

# Download specific attachment
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh download  

Adding attachments to drafts:

# Add attachment to a draft (supports files up to 150MB)
${CLAUDE_SKILL_DIR}/scripts/outlook-graph-mail.sh attach  

Upload method is automatic based on file size:

  • **Small files (

Mark as unread

${CLAUDESKILLDIR}/scripts/outlook-graph-mail.sh markunread

Flag / unflag for follow-up (list flagged messages with flagged)

${CLAUDESKILLDIR}/scripts/outlook-graph-mail.sh flag ${CLAUDESKILLDIR}/scripts/outlook-graph-mail.sh unflag

Categories: list the mailbox's master category names, then apply them.

Comma-separated list replaces the message's categories; "" clears them.

${CLAUDESKILLDIR}/scripts/out

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.