microsoft-outlook について
`curl + jq` で Microsoft Graph を呼び出し、Outlook のメールとカレンダーを扱うシェルスキルです。メール検索や下書き・添付ファイルの操作、予定や空き時間の確認に対応し、送信や変更などの前に確認する手順も示します。
主な機能
- 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 を使って、Outlook / Microsoft 365 の Microsoft Graph(メールと
カレンダーの両方)を操作します。ユーザーの OAuth ベアラートークンは
$MICROSOFT_OUTLOOK_TOKEN に格納されています。各呼び出しで
Authorization: Bearer $MICROSOFT_OUTLOOK_TOKEN として指定する必要があります。
トークンには、インストール時にユーザーが同意したスコープのうち、
Mail.Read、Mail.ReadWrite、Mail.Send、MailboxSettings.Read、
MailboxSettings.ReadWrite、Calendars.Read、Calendars.ReadWrite、
および *.Shared バリアントが含まれています。
Microsoft Graph ではメールとカレンダーは同じメールボックスの兄弟機能として扱われるため、
両者をひとつのコネクター(ひとつの OAuth 許可)に統合しています。スキルレイヤーで
分割しても利点はありません。
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"
CC / BCC:toRecipients と同じ形式の配列を ccRecipients / bccRecipients に含めます。
返信 / 全員に返信 / 転送
⚠️ 送信前に、下書きの本文と宛先をユーザーに表示してください。
# 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"}
}
}
一連の予定の特定の回を変更するには、シリーズのマスターではなく、calendarView が返すその回の ID に対して PATCH してください。
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 を使用してください。
ルール
- 必ず
$selectを渡してください — デフォルトではアイテムごとに 30 個以上のフィールドが返されます。 - 閲覧では
$top=10、検索では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