microsoft-outlook
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDrive Microsoft Graph for Outlook / Microsoft 365 — both mail and
calendar — via . The user's OAuth bearer token is in
; every call needs it as
. The token already
carries the scopes the user agreed to at install: any of ,
, , ,
, , ,
plus variants. Mail and calendar are unified into one
connector (and one OAuth grant) because Microsoft Graph treats them as
sibling features of the same mailbox — there is no value in splitting
them at the skill layer.
curl + jq$MICROSOFT_OUTLOOK_TOKENAuthorization: Bearer $MICROSOFT_OUTLOOK_TOKENMail.ReadMail.ReadWriteMail.SendMailboxSettings.ReadMailboxSettings.ReadWriteCalendars.ReadCalendars.ReadWrite*.SharedThe Graph API returns JSON; failures surface as
— show that error
verbatim to the user.
{"error": {"code": "...", "message": "..."}}Always start with to confirm the connection works AND learn
which mailbox you're operating against. For calendar work, also fetch
so dates render right.
/memailboxSettings.timeZone通过调用Microsoft Graph来操作Outlook/Microsoft 365的邮件和日历功能。用户的OAuth承载令牌存储在中;每次调用都需要在请求头中添加。该令牌已包含用户在安装时同意的权限范围:包括、、、、、、中的任意一项,以及变体。邮件和日历功能被整合到一个连接器(及一个OAuth授权)中,因为Microsoft Graph将它们视为同一邮箱的同级功能——在技能层拆分它们没有意义。
curl + jq$MICROSOFT_OUTLOOK_TOKENAuthorization: Bearer $MICROSOFT_OUTLOOK_TOKENMail.ReadMail.ReadWriteMail.SendMailboxSettings.ReadMailboxSettings.ReadWriteCalendars.ReadCalendars.ReadWrite*.SharedGraph API返回JSON格式数据;请求失败时会返回——需将该错误信息原封不动展示给用户。
{"error": {"code": "...", "message": "..."}}始终以接口开始,确认连接正常并了解当前操作的邮箱信息。处理日历相关操作时,还需获取以确保日期显示正确。
/memailboxSettings.timeZoneMail — Recipes
邮件操作示例
Verify auth (always run first)
验证授权(必须首先执行)
sh
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
https://graph.microsoft.com/v1.0/me \
| jq '{displayName, mail, userPrincipalName}'sh
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
https://graph.microsoft.com/v1.0/me \
| jq '{displayName, mail, userPrincipalName}'List recent messages
列出最近收到的邮件
sh
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)}'Filters: append to URL with (URL-encode the spaces).
&| Want | Append |
|---|---|
| Unread only | |
| With attachments | |
| From a specific sender | |
| Date range | |
| Combine | Use |
sh
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编码)。
&| 需求 | 拼接参数 |
|---|---|
| 仅显示未读邮件 | |
| 仅显示带附件的邮件 | |
| 来自特定发件人 | |
| 日期范围 | |
| 组合筛选 | 在筛选条件间使用 |
Search messages (full-text on subject + body)
搜索邮件(主题+正文全文检索)
sh
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/messagescannot be combined with$searchor$filterin the same query — pick one.$orderbyreturns relevance-ranked results.$search
sh
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
Read a message body
读取邮件正文
sh
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"jq -r .body.contentsh
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"jq -r .body.contentSend an email
发送邮件
⚠️ ALWAYS use draft → confirm → send. NEVER calldirectly — it sends immediately with no undo./me/sendMail
sh
undefined⚠️ 必须遵循“创建草稿→确认内容→发送”流程。禁止直接调用——该接口会立即发送邮件且无法撤销。/me/sendMail
sh
undefinedStep 1: create draft
步骤1:创建草稿
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 "alice@example.com"
'{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)
-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 "alice@example.com"
'{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)
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 "alice@example.com"
'{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)
-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 "alice@example.com"
'{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
步骤2:向用户展示草稿内容——主题、收件人、正文预览
echo "$DRAFT" | jq '{subject, to: .toRecipients[0].emailAddress.address, body: .body.content}'
echo "$DRAFT" | jq '{subject, to: .toRecipients[0].emailAddress.address, body: .body.content}'
Step 3: ONLY after user confirms — send (returns 202 No Content)
步骤3:仅在用户确认后发送(返回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"
"https://graph.microsoft.com/v1.0/me/messages/${DRAFT_ID}/send"
-w "HTTP %{http_code}\n"
CC / BCC: include `ccRecipients` / `bccRecipients` arrays in the same
shape as `toRecipients`.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"
"https://graph.microsoft.com/v1.0/me/messages/${DRAFT_ID}/send"
-w "HTTP %{http_code}\n"
抄送/密送:在请求体中添加与`toRecipients`格式相同的`ccRecipients` / `bccRecipients`数组即可。Reply / reply-all / forward
回复/全部回复/转发
⚠️ Show the user your draft text + recipients before sending.
sh
undefined⚠️ 发送前需向用户展示草稿内容及收件人信息。
sh
undefinedQuick reply (sends immediately on /reply — for explicit user-confirmed flow)
快速回复(调用/reply后立即发送——仅适用于用户明确确认的场景)
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"
-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"
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"
-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)
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/createReply") DRAFT_ID=$(echo "$DRAFT" | jq -r .id)
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)
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/createReply") DRAFT_ID=$(echo "$DRAFT" | jq -r .id)
PATCH body if needed, then /send
如需修改正文可调用PATCH接口,之后再发送
Forward
转发邮件
curl -sS -X POST
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN"
-H "Content-Type: application/json"
-d "$(jq -nc --arg to "bob@example.com"
'{comment:"FYI", toRecipients:[{emailAddress:{address:$to}}]}')"
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/forward"
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN"
-H "Content-Type: application/json"
-d "$(jq -nc --arg to "bob@example.com"
'{comment:"FYI", toRecipients:[{emailAddress:{address:$to}}]}')"
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/forward"
undefinedcurl -sS -X POST
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN"
-H "Content-Type: application/json"
-d "$(jq -nc --arg to "bob@example.com"
'{comment:"FYI", toRecipients:[{emailAddress:{address:$to}}]}')"
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/forward"
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN"
-H "Content-Type: application/json"
-d "$(jq -nc --arg to "bob@example.com"
'{comment:"FYI", toRecipients:[{emailAddress:{address:$to}}]}')"
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/forward"
undefinedMark read / unread
标记已读/未读
sh
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}"sh
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}"List folders + read a specific folder
列出文件夹并读取指定文件夹内容
sh
undefinedsh
undefinedWell-known folder names: Inbox, Drafts, SentItems, DeletedItems, Archive, JunkEmail
常见文件夹名称: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}'
"https://graph.microsoft.com/v1.0/me/mailFolders('SentItems')/messages?\$top=5&\$select=subject,toRecipients,sentDateTime"
| jq '.value[] | {subject, sent: .sentDateTime}'
undefinedcurl -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}'
"https://graph.microsoft.com/v1.0/me/mailFolders('SentItems')/messages?\$top=5&\$select=subject,toRecipients,sentDateTime"
| jq '.value[] | {subject, sent: .sentDateTime}'
undefinedList + download attachments
列出并下载附件
sh
undefinedsh
undefinedMetadata
获取附件元数据
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}'
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/attachments?\$select=id,name,size,contentType"
| jq '.value[] | {id, name, size}'
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}'
"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"
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/attachments/${ATT_ID}/\$value"
-o "$SKILL_DIR/tmp/attachment.bin"
undefinedcurl -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"
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}/attachments/${ATT_ID}/\$value"
-o "$SKILL_DIR/tmp/attachment.bin"
undefinedMailbox settings (timezone, signature, automatic replies)
邮箱设置(时区、签名、自动回复)
sh
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/mailboxSettings"Set an out-of-office reply:
⚠️ Confirm with user before changing — auto-reply will fire on every incoming mail.
sh
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"Requires scope.
MailboxSettings.ReadWritesh
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/mailboxSettings"设置外出自动回复:
⚠️ 修改前需与用户确认——自动回复会对所有 incoming 邮件生效。
sh
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.ReadWriteDelete a message
删除邮件
⚠️ Always fetch the subject first and confirm with the user.
sh
undefined⚠️ 必须先获取邮件主题并与用户确认后再执行删除操作。
sh
undefined1) show what's about to be deleted
1) 展示即将删除的邮件信息
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))?"'
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}?\$select=subject,from,receivedDateTime"
| jq '"Delete "(.subject)" from (.from.emailAddress.address) ((.receivedDateTime))?"'
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))?"'
"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)
2) 用户确认后执行删除(邮件会被移至已删除文件夹,返回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"
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}"
-w "HTTP %{http_code}\n"
---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"
"https://graph.microsoft.com/v1.0/me/messages/${MSG_ID}"
-w "HTTP %{http_code}\n"
---Calendar — Recipes
日历操作示例
Get user timezone (run once at start of any calendar work)
获取用户时区(处理任何日历操作前需执行一次)
sh
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/mailboxSettings" \
| jq '.timeZone'sh
curl -sS -H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
"https://graph.microsoft.com/v1.0/me/mailboxSettings" \
| jq '.timeZone'→ e.g. "China Standard Time"
→ 示例输出:"China Standard Time"
Pass that timezone in the `Prefer: outlook.timezone` header on every
calendar call so `start.dateTime` / `end.dateTime` come back rendered
in the user's local time:
```sh
TZ_HEADER='Prefer: outlook.timezone="China Standard Time"'
在每次日历调用中添加`Prefer: outlook.timezone`请求头,确保返回的`start.dateTime` / `end.dateTime`以用户本地时区显示:
```sh
TZ_HEADER='Prefer: outlook.timezone="China Standard Time"'Today's agenda (calendarView)
今日日程(calendarView)
calendarView/eventssh
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]}'calendarView/eventssh
START=$(date -u +'%Y-%m-%dT00:00:00Z')
END=$(date -u -v+1d +'%Y-%m-%dT00:00:00Z') # macOS系统;Linux系统使用-d参数
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]}'This week's events (Mon–Sun)
本周事件(周一至周日)
sh
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/calendarViewsh
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/calendarViewFind free / busy slots (getSchedule
)
getSchedule查找空闲/忙碌时段(getSchedule
)
getScheduleBest way to find a slot that works for multiple people. Returns
30-minute buckets of free / busy / tentative across the requested
window.
sh
curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -nc '{
schedules: ["me", "alice@example.com", "bob@example.com"],
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}'这是查找多人共同空闲时段的最佳方式。返回指定时间范围内每30分钟的空闲/忙碌/暂定状态。
sh
curl -sS -X POST \
-H "Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -nc '{
schedules: ["me", "alice@example.com", "bob@example.com"],
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
availabilityView是一串数字:0=空闲 1=暂定 2=忙碌 3=外出 4=异地办公
undefinedundefinedRead a single event (incl. attendees + body)
读取单个事件(包含参会者及正文)
sh
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}'sh
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}'Create an event
创建事件
⚠️ ALWAYS show subject / time / attendees to the user before creating — invitations fire automatically the moment the event is POSTed.
sh
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 "alice@example.com" \
'{
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: trueonlineMeetingProvider: "teamsForBusiness"⚠️ 创建前必须向用户展示主题、时间、参会者信息——事件创建完成后会立即向参会者发送邀请邮件。
sh
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 "alice@example.com" \
'{
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}'设置 + 会自动生成Teams会议链接。若为线下会议,可移除这两个参数。
isOnlineMeeting: trueonlineMeetingProvider: "teamsForBusiness"Update / reschedule (PATCH)
更新/重新安排事件(PATCH)
⚠️ Updating sends an "Updated" notice to all attendees. Confirm first.
sh
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}"⚠️ 更新操作会向所有参会者发送“事件已更新”通知。执行前需与用户确认。
sh
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}"Cancel a meeting (sends cancellation notice)
取消会议(发送取消通知)
⚠️ Confirm with the user — every attendee is notified.
sh
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"⚠️ 执行前需与用户确认——所有参会者都会收到通知。
sh
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"Accept / decline / tentative an incoming invite
接受/拒绝/暂定接受会议邀请
sh
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"sh
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
也可调用/decline(拒绝)或/tentativelyAccept(暂定接受)接口
undefinedundefinedRead a shared calendar
读取共享日历
Requires .
Calendars.Read.Sharedsh
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该操作需要权限。
Calendars.Read.Sharedsh
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" \
-GWorking with timezones
时区相关操作
| Field | Meaning |
|---|---|
| The local wall-clock time. |
| IANA-ish name ( |
| Re-renders all returned |
Always set on read calls so the JSON arrives
in the user's expected timezone instead of UTC.
Prefer: outlook.timezone| 字段 | 含义 |
|---|---|
| 本地时钟时间。 |
| IANA风格的时区名称(如 |
| 将返回的所有 |
读取日历数据时务必设置请求头,确保返回的JSON数据使用用户预期的时区而非UTC。
Prefer: outlook.timezoneRecurrence
重复事件
Use (it expands occurrences for you) — not .
To create a recurring event, include :
calendarView?$expand=recurrencejson
{
"recurrence": {
"pattern": {"type":"weekly", "interval":1, "daysOfWeek":["monday","wednesday"]},
"range": {"type":"endDate", "startDate":"2026-05-06", "endDate":"2026-08-06"}
}
}To modify a single occurrence of a series, PATCH that occurrence's id
(returned by ), NOT the series master.
calendarView使用接口(它会自动展开重复事件实例)——不要使用参数。创建重复事件时,需在请求体中包含字段:
calendarView?$expand=recurrencejson
{
"recurrence": {
"pattern": {"type":"weekly", "interval":1, "daysOfWeek":["monday","wednesday"]},
"range": {"type":"endDate", "startDate":"2026-05-06", "endDate":"2026-08-06"}
}
}若需修改重复事件系列中的单个实例,需PATCH该实例的ID(由返回),而非重复事件的主条目ID。
calendarViewOData quick reference (mail + calendar)
OData快速参考(邮件+日历)
| Param | Mail example | Calendar example |
|---|---|---|
| | |
| | |
| | |
| | |
| | n/a |
| | |
Use with curl to avoid
shell-quoting and spaces.
--data-urlencode "$key=$value" --get$| 参数 | 邮件示例 | 日历示例 |
|---|---|---|
| | |
| | |
| | |
| 浏览时设为 | 浏览时设为 |
| | 不适用 |
| | |
使用curl时,建议通过方式传递参数,避免shell对和空格的转义问题。
--data-urlencode "$key=$value" --get$Rules
规则
- Always pass — defaults return 30+ fields per item.
$select - for browse,
$top=10for search. Don't paginate past 50 unless asked.25 - HTML bodies only for mail. collapses whitespace.
contentType: "Text" - Use for any agenda / "what's on my calendar" question.
calendarViewreturns recurrence masters only./events - Set on calendar read calls; otherwise
Prefer: outlook.timezonecomes back in UTC.dateTime - URL-encode message / event / attachment IDs if using them in a
path — IDs can contain ,
+,/. Use=.jq -sRr @uri - Date math: works on macOS,
date -u -v+1don Linux.date -u -d 'tomorrow'
- 始终传递参数——默认返回每个条目包含30+个字段。
$select - 浏览时设,搜索时设
$top=10。除非用户要求,否则分页不要超过50条。$top=25 - 邮件正文仅使用HTML格式。会导致空格被压缩。
contentType: "Text" - 处理日程相关问题时使用接口。
calendarView仅返回重复事件的主条目。/events - 读取日历数据时设置请求头;否则返回的
Prefer: outlook.timezone值为UTC时区。dateTime - 若在路径中使用邮件/事件/附件ID,需进行URL编码——ID可能包含、
+、/字符。可使用=进行编码。jq -sRr @uri - 日期计算:macOS系统使用,Linux系统使用
date -u -v+1d。date -u -d 'tomorrow'
CRITICAL: User consent for destructive / notifying actions
重要提示:破坏性/通知类操作需用户确认
Sent emails cannot be unsent. Calendar writes fan out emails to
attendees. Deleted messages may be permanently lost.
Pattern: prepare → present → execute.
| Action | Prepare step | Show user |
|---|---|---|
| Send mail | | subject, recipients, body preview |
| Reply / forward | createReply / createForward | quote snippet + your reply text |
| Delete mail | fetch | "Delete '{subject}' from {sender}?" |
| Out-of-office | show current setting first | new schedule + message preview |
| Create event | build payload | subject, time, attendees, online-meeting on/off |
| Update event | diff with current | what's changing, attendee count being notified |
| Cancel event | fetch event first | subject, time, attendee count |
| Accept / decline invite | fetch event first | event subject + organizer |
| Bulk | list affected | count + sample |
Never call — it sends immediately with no undo. Always draft → confirm → .
/me/sendMail/send已发送的邮件无法撤回。日历写入操作会向所有参会者发送邮件通知。删除的邮件可能永久丢失。
操作流程:准备→展示→执行。
| 操作 | 准备步骤 | 展示给用户的内容 |
|---|---|---|
| 发送邮件 | 调用 | 主题、收件人、正文预览 |
| 回复/转发 | 调用createReply/createForward创建草稿 | 引用片段+回复内容 |
| 删除邮件 | 先获取邮件主题 | "是否删除来自{发件人}的'{主题}'邮件?" |
| 设置外出自动回复 | 先获取当前设置 | 新的时间安排+回复内容预览 |
| 创建事件 | 构建请求体 | 主题、时间、参会者、是否开启线上会议 |
| 更新事件 | 对比当前事件内容 | 变更内容、将收到通知的参会者数量 |
| 取消事件 | 先获取事件信息 | 主题、时间、参会者数量 |
| 接受/拒绝邀请 | 先获取事件信息 | 事件主题+组织者 |
| 批量操作 | 列出受影响的条目 | 数量+示例条目 |
禁止调用接口——该接口会立即发送邮件且无法撤销。必须遵循“创建草稿→确认→调用/send”流程。
/me/sendMailErrors
错误处理
- → token expired; user must reinstall the connector.
401 InvalidAuthenticationToken - → write scope missing (e.g. trying
403 ErrorAccessDeniedwithout it granted, orMail.Sendfor create / cancel); ask user to reinstall and tick the write scope.Calendars.ReadWrite - → respect
429 TooManyRequestsheader.Retry-After - → wrong message / event id (or it was already deleted / cancelled).
404 ErrorItemNotFound
- → 令牌过期;用户需重新安装连接器。
401 InvalidAuthenticationToken - → 缺少写入权限(例如尝试调用
403 ErrorAccessDenied但未获得该权限,或创建/取消事件时缺少Mail.Send权限);请用户重新安装并勾选对应的写入权限。Calendars.ReadWrite - → 需遵循
429 TooManyRequests头指定的时间重试。Retry-After - → 邮件/事件ID错误(或已被删除/取消)。
404 ErrorItemNotFound
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
- 邮件API:https://learn.microsoft.com/en-us/graph/api/resources/mail-api-overview
- 邮件资源:https://learn.microsoft.com/en-us/graph/api/resources/message
- 日历资源:https://learn.microsoft.com/en-us/graph/api/resources/calendar
- 事件资源: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