关于 microsoft-outlook
通过 `curl + jq` 调用 Microsoft Graph 管理 Outlook 邮件和日历的 Shell 技能,适合需要处理 Microsoft 365 邮箱与日程的 Agent。它涵盖邮件搜索、草稿和附件操作、日历与空闲状态查询,并提示在发送或修改等重要操作前确认。
主要功能
- 01读取、筛选和搜索邮件
- 02创建和管理邮件草稿
- 03处理邮件与附件
- 04查看和更新日历事件
- 05查询空闲状态和邮箱设置
适用场景
- 01查找未读邮件或特定发件人的邮件
- 02发送前检查邮件草稿
- 03查看包含重复事件的每日安排
- 04为多人查找合适的会议时间
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ acedatacloud/ skills --skill microsoft-outlook安装后在 Claude Code 中输入/microsoft-outlook确认已加载。
详细介绍
通过 curl + jq 调用 Microsoft Graph,管理 Outlook / Microsoft 365 中的邮件和日历。用户的 OAuth bearer token 位于 $MICROSOFT_OUTLOOK_TOKEN;每次调用都需要在 Authorization 标头中传入 Bearer $MICROSOFT_OUTLOOK_TOKEN。该 token 已包含用户在安装时同意授予的作用域:Mail.Read、Mail.ReadWrite、Mail.Send、MailboxSettings.Read、MailboxSettings.ReadWrite、Calendars.Read、Calendars.ReadWrite 中的任意作用域,以及对应的 *.Shared 变体。邮件和日历整合到同一个连接器(和同一个 OAuth 授权)中,因为 Microsoft Graph 将它们视为同一邮箱的相邻功能——在技能层拆分它们没有意义。
Graph API 返回 JSON;失败时会显示为
{"error": {"code": "...", "message": "..."}}——请将该错误原样展示给用户。
始终从 /me 开始,确认连接可用,并了解当前操作的是哪个邮箱。处理日历时,还要获取 mailboxSettings.timeZone,以正确显示日期。
邮件 — 操作示例
验证身份验证(始终先运行)
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
https://graph.microsoft.com/v1.0/me \
| jq '{displayName, mail, userPrincipalName}'
列出最近的邮件
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/messages?\$top=10&\$select=id,subject,from,receivedDateTime,isRead,hasAttachments&\$orderby=receivedDateTime desc" \
| jq '.value[] | {subject, from: .from.emailAddress.address, received: .receivedDateTime, unread: (.isRead | not)}'
筛选条件:将筛选条件附加到 URL,使用 &(对空格进行 URL 编码)。
| 需求 | 附加内容 |
|---|---|
| 仅未读邮件 | &$filter=isRead eq false |
| 包含附件 | &$filter=hasAttachments eq true |
| 来自特定发件人 | &$filter=from/emailAddress/address eq '[email protected]' |
| 日期范围 | &$filter=receivedDateTime ge 2026-04-01T00:00:00Z and receivedDateTime lt 2026-05-01T00:00:00Z |
| 组合筛选 | 在筛选条件之间使用 and / or |
搜索邮件(对主题和正文进行全文搜索)
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
--data-urlencode '$search="quarterly report"' \
--data-urlencode '$top=10' \
--data-urlencode '$select=id,subject,from,receivedDateTime' \
--get https://graph.microsoft.com/v1.0/me/messages
$search不能与$filter或$orderby在同一查询中组合使用——请选择其中一个。$search会按相关性对结果排序。
读取邮件正文
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}?\$select=subject,body,from,toRecipients,receivedDateTime" \
| jq '{subject, from: .from.emailAddress.address, received: .receivedDateTime, body: .body.content}'
body.contentType 通常为 "HTML"。如果要获取原始 HTML,请使用 jq -r .body.content。
发送电子邮件
⚠️ 始终使用“草稿 → 确认 → 发送”流程。绝不要直接调用
/me/sendMail——它会立即发送,且无法撤回。
# Step 1: create draft
DRAFT=$(curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -nc \
--arg subj "Project update" \
--arg body "<p>Wanted to share the latest numbers.</p>" \
--arg to "[email protected]" \
'{subject:$subj, body:{contentType:"HTML", content:$body}, toRecipients:[{emailAddress:{address:$to}}]}')" \
https://graph.microsoft.com/v1.0/me/messages)
DRAFT_ID=$(echo "$DRAFT" | jq -r .id)
# Step 2: present the draft to the user — subject, recipients, body preview
echo "$DRAFT" | jq '{subject, to: .toRecipients[0].emailAddress.address, body: .body.content}'
# Step 3: ONLY after user confirms — send (returns 202 No Content)
curl -sS -X POST -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/messages/${DRAFT_ID}/send" \
-w "HTTP %{http_code}\n"
抄送 / 密送:在同一请求中加入 ccRecipients / bccRecipients 数组,格式与 toRecipients 相同。
回复 / 全部回复 / 转发
⚠️ 发送前,先向用户展示草稿内容和收件人。
# Quick reply (sends immediately on /reply — for explicit user-confirmed flow)
curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"comment":"Thanks for the update!"}' \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/reply"
# Or: createReply → review → /send (preferred for non-trivial replies)
DRAFT=$(curl -sS -X POST -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/createReply")
DRAFT_ID=$(echo "$DRAFT" | jq -r .id)
# PATCH body if needed, then /send
# Forward
curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -nc --arg to "[email protected]" \
'{comment:"FYI", toRecipients:[{emailAddress:{address:$to}}]}')" \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/forward"
标记为已读 / 未读
curl -sS -X PATCH \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"isRead": true}' \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}"
列出文件夹 + 读取指定文件夹
# Well-known folder names: Inbox, Drafts, SentItems, DeletedItems, Archive, JunkEmail
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/mailFolders('SentItems')/messages?\$top=5&\$select=subject,toRecipients,sentDateTime" \
| jq '.value[] | {subject, sent: .sentDateTime}'
列出 + 下载附件
# Metadata
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/attachments?\$select=id,name,size,contentType" \
| jq '.value[] | {id, name, size}'
# Download a single attachment
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/attachments/${ATT_ID}/\$value" \
-o "$SKILL_DIR/tmp/attachment.bin"
邮箱设置(时区、签名、自动回复)
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/mailboxSettings"
设置外出自动回复:
⚠️ 更改前先征得用户确认——自动回复会针对每封收到的邮件发送。
curl -sS -X PATCH \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"automaticRepliesSetting":{
"status":"scheduled",
"scheduledStartDateTime":{"dateTime":"2026-05-10T09:00:00","timeZone":"China Standard Time"},
"scheduledEndDateTime":{"dateTime":"2026-05-15T18:00:00","timeZone":"China Standard Time"},
"internalReplyMessage":"<p>I'm out this week, back Monday.</p>"}}' \
"https://graph.microsoft.com/v1.0/me/mailboxSettings"
需要 MailboxSettings.ReadWrite 作用域。
删除邮件
⚠️ 始终先获取主题,并向用户确认。
# 1) show what's about to be deleted
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}?\$select=subject,from,receivedDateTime" \
| jq '"Delete \"\(.subject)\" from \(.from.emailAddress.address) (\(.receivedDateTime))?"'
# 2) after user confirms (moves to Deleted Items, returns 204)
curl -sS -X DELETE -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}" \
-w "HTTP %{http_code}\n"
日历 — 操作示例
获取用户时区(开始处理任何日历任务时运行一次)
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/mailboxSettings" \
| jq '.timeZone'
# → e.g. "China Standard Time"
在每次日历调用的 Prefer: outlook.timezone 标头中传入该时区,这样返回的 start.dateTime / end.dateTime 就会按用户的本地时间显示:
TZ_HEADER='Prefer: outlook.timezone="China Standard Time"'
今日安排(calendarView)
calendarView 会将时间窗口内的重复系列展开为单独的实例,正适合查看日程安排。普通的 /events 只会返回重复系列的主事件。
START=$(date -u +'%Y-%m-%dT00:00:00Z')
END=$(date -u -v+1d +'%Y-%m-%dT00:00:00Z') # macOS; use -d on Linux
curl -sS \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Prefer: outlook.timezone=\"China Standard Time\"" \
--data-urlencode "startDateTime=$START" \
--data-urlencode "endDateTime=$END" \
--data-urlencode '$select=id,subject,start,end,location,attendees,onlineMeeting,isCancelled' \
--data-urlencode '$orderby=start/dateTime' \
--get https://graph.microsoft.com/v1.0/me/calendarView \
| jq '.value[] | {subject, start: .start.dateTime, end: .end.dateTime, location: .location.displayName, attendees: [.attendees[].emailAddress.address]}'
本周事件(周一至周日)
START=$(date -u -v-Mon +'%Y-%m-%dT00:00:00Z' 2>/dev/null || date -u -d 'last monday' +'%Y-%m-%dT00:00:00Z')
END=$(date -u -v+7d -v-Mon +'%Y-%m-%dT00:00:00Z' 2>/dev/null || date -u -d 'next monday' +'%Y-%m-%dT00:00:00Z')
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Prefer: outlook.timezone=\"China Standard Time\"" \
--data-urlencode "startDateTime=$START" \
--data-urlencode "endDateTime=$END" \
--data-urlencode '$select=subject,start,end' \
--data-urlencode '$orderby=start/dateTime' \
--get https://graph.microsoft.com/v1.0/me/calendarView
查找空闲 / 忙碌时段(getSchedule)
这是查找适合多人的时间段的最佳方式。它会返回指定时间窗口内以 30 分钟为单位的空闲 / 忙碌 / 暂定时段。
curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -nc '{
schedules: ["me", "[email protected]", "[email protected]"],
startTime: {dateTime: "2026-05-05T09:00:00", timeZone: "China Standard Time"},
endTime: {dateTime: "2026-05-05T18:00:00", timeZone: "China Standard Time"},
availabilityViewInterval: 30
}')" \
https://graph.microsoft.com/v1.0/me/calendar/getSchedule \
| jq '.value[] | {who: .scheduleId, view: .availabilityView}'
# availabilityView is a string of digits: 0=free 1=tentative 2=busy 3=oof 4=workingElsewhere
读取单个事件(包括与会者和正文)
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Prefer: outlook.timezone=\"China Standard Time\"" \
"https://graph.microsoft.com/v1.0/me/events/${EVENT_ID}?\$select=subject,start,end,location,attendees,body,organizer,onlineMeeting" \
| jq '{subject, start: .start.dateTime, attendees: [.attendees[] | {addr: .emailAddress.address, response: .status.response}], body: .body.content}'
创建事件
⚠️ 创建前,始终向用户展示主题 / 时间 / 与会者——事件一经 POST,邀请就会自动发出。
PAYLOAD=$(jq -nc \
--arg subj "Project sync" \
--arg body "<p>Quarterly review.</p>" \
--arg start "2026-05-06T10:00:00" \
--arg end "2026-05-06T10:30:00" \
--arg tz "China Standard Time" \
--arg loc "Meeting room 3F" \
--arg a1 "[email protected]" \
'{
subject: $subj,
body: {contentType:"HTML", content:$body},
start: {dateTime:$start, timeZone:$tz},
end: {dateTime:$end, timeZone:$tz},
location:{displayName:$loc},
attendees:[{emailAddress:{address:$a1}, type:"required"}],
isOnlineMeeting: true,
onlineMeetingProvider: "teamsForBusiness"
}')
curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
https://graph.microsoft.com/v1.0/me/events \
| jq '{id, subject, start: .start.dateTime, joinUrl: .onlineMeeting.joinUrl}'
isOnlineMeeting: true + onlineMeetingProvider: "teamsForBusiness" 会自动生成 Teams 会议链接。创建线下活动时,请移除这两个字段。
更新 / 重新安排(PATCH)
⚠️ 更新会向所有与会者发送“已更新”通知。请先征得确认。
curl -sS -X PATCH \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -nc \
--arg start "2026-05-06T14:00:00" \
--arg end "2026-05-06T14:30:00" \
--arg tz "China Standard Time" \
'{start:{dateTime:$start, timeZone:$tz}, end:{dateTime:$end, timeZone:$tz}}')" \
"https://graph.microsoft.com/v1.0/me/events/${EVENT_ID}"
取消会议(发送取消通知)
⚠️ 请与用户确认——所有参会者都会收到通知。
curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"comment":"Need to reschedule, sorry."}' \
"https://graph.microsoft.com/v1.0/me/events/${EVENT_ID}/cancel" \
-w "HTTP %{http_code}\n"
接受 / 拒绝 / 暂定接受收到的邀请
curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"comment":"See you there", "sendResponse":true}' \
"https://graph.microsoft.com/v1.0/me/events/${EVENT_ID}/accept"
# Or /decline, /tentativelyAccept
读取共享日历
需要 Calendars.Read.Shared。
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/users/${USER_UPN}/calendarView?startDateTime=${START}&endDateTime=${END}&\$select=subject,start,end" \
-G
使用时区
| 字段 | 含义 |
|---|---|
start.dateTime / end.dateTime | 本地挂钟时间。 |
start.timeZone / end.timeZone | 类似 IANA 的名称("Pacific Standard Time"、"China Standard Time"、"UTC")。 |
Prefer: outlook.timezone="..." 请求标头 | 将所有返回的 dateTime 值转换为此时区。 |
读取时始终设置 Prefer: outlook.timezone,这样 JSON 会使用用户预期的时区,而不是 UTC。
重复事件
使用 calendarView(它会为你展开各次事件),不要使用 ?$expand=。
要创建重复事件,请包含 recurrence:
{
"recurrence": {
"pattern": {"type":"weekly", "interval":1, "daysOfWeek":["monday","wednesday"]},
"range": {"type":"endDate", "startDate":"2026-05-06", "endDate":"2026-08-06"}
}
}
要修改系列中的单次事件,请 PATCH 该次事件的 id(由 calendarView 返回),而不是系列主事件。
OData 快速参考(邮件 + 日历)
| 参数 | 邮件示例 | 日历示例 |
|---|---|---|
$select | id,subject,from,receivedDateTime,isRead | subject,start,end,location,attendees |
$filter | isRead eq false | start/dateTime ge '2026-05-01T00:00:00' |
$orderby | receivedDateTime desc | start/dateTime |
$top | 浏览用 10,搜索用 25 | 浏览用 10 |
$search | "keyword"(仅限邮件——不能与 $filter / $orderby 组合) | 不适用 |
$expand | attachments | attendees、attachments |
使用 curl 时,通过 --data-urlencode "$key=$value" --get 避免对 $ 和空格进行 shell 引号转义。
规则
- 始终传入
$select——默认情况下每项会返回 30 多个字段。 - 浏览用
$top=10,搜索用$top=25。除非用户要求,否则不要翻页超过 50 项。 - 邮件仅使用 HTML 正文。
contentType: "Text"会压缩空白字符。 - 对于任何日程 /“我的日历上有什么”问题,都使用
calendarView。/events只会返回重复事件的主事件。 - 读取日历时设置
Prefer: outlook.timezone;否则dateTime会以 UTC 返回。 - 如果在路径中使用邮件 / 事件 / 附件 ID,请进行 URL 编码——ID 可能包含
+、/、=。使用jq -sRr @uri。 - 日期计算:macOS 上可使用
date -u -v+1d,Linux 上可使用date -u -d 'tomorrow'。
关键:执行破坏性操作 / 通知操作前须征得用户同意
已发送的邮件无法撤回。日历写入会向参会者发送邮件。已删除的邮件可能无法恢复。 流程:准备 → 呈现 → 执行。
| 操作 | 准备步骤 | 向用户展示 |
|---|---|---|
| 发送邮件 | POST /me/messages(草稿) | 主题、收件人、正文预览 |
| 回复 / 转发 | createReply / createForward | 引用片段 + 你的回复文本 |
| 删除邮件 | 先获取 subject | “要从 {sender} 删除“{subject}”吗?” |
| 外出办公 | 先展示当前设置 | 新日程 + 消息预览 |
| 创建事件 | 构建负载 | 主题、时间、参会者、是否开启在线会议 |
| 更新事件 | 与当前内容对比差异 | 将更改的内容、会收到通知的参会者人数 |
| 取消事件 | 先获取事件 | 主题、时间、参会者人数 |
| 接受 / 拒绝邀请 | 先获取事件 | 事件主题 + 组织者 |
| 批量操作 | 列出受影响的对象 | 数量 + 示例 |
绝不要调用 /me/sendMail——它会立即发送,且无法撤销。始终先创建草稿 → 确认 → /send。
错误
401 InvalidAuthenticationToken→ 令牌已过期;用户必须重新安装连接器。403 ErrorAccessDenied→ 缺少写入权限范围(例如,尝试使用未获授权的Mail.Send,或创建 / 取消事件时缺少Calendars.ReadWrite);请用户重新安装并勾选写入权限范围。429 TooManyRequests→ 遵循Retry-After标头。404 ErrorItemNotFound→ 邮件 / 事件 id 错误(或已被删除 / 取消)。
Reference
- Mail API: https://learn.microsoft.com/en-us/graph/api/resources/mail-api-overview
- Message resource: https://learn.microsoft.com/en-us/graph/api/resources/message
- Calendar resource: https://learn.microsoft.com/en-us/graph/api/resources/calendar
- Event resource: https://learn.microsoft.com/en-us/graph/api/resources/event
- calendarView: https://learn.microsoft.com/en-us/graph/api/calendar-list-calendarview
- getSchedule: https://learn.microsoft.com/en-us/graph/api/calendar-getschedule
- MailboxSettings: https://learn.microsoft.com/en-us/graph/api/resources/mailboxsettings