Contents
Outlook カレンダー API の概要
Outlook カレンダー API は Microsoft Graph を通して Exchange Online のカレンダー機能に統一的にアクセスできるインターフェイスです。この記事では、現在公式ドキュメントで確認できているエンドポイントとバージョン情報、そして実務で使う際の基本的な流れを解説します。
注:2024 年 11 月に「location.displayName の多言語対応」や「
showAs=busyパラメータ」の追加があったという情報は、Microsoft のリリースノート(https://learn.microsoft.com/graph/changelog) に記載がなく、事実確認できていません。実装時には必ず最新の公式ドキュメントをご確認ください。
主なポイント
- 利用可能バージョン:
v1.0(本番推奨)とbeta(プレビュー) - 対象サービス: Exchange Online (Office 365) の全テナント
- 代表的エンドポイント
/me/events、/users/{id}/events– イベントの CRUD/me/calendarView– 指定期間内のスケジュール取得
Azure AD アプリ登録と OAuth 2.0 認可コードフロー
このセクションでは、カレンダー API を呼び出すために必須となる Azure AD アプリの作成手順と、実際にトークンを取得するまでのフローを解説します。最小権限で安全に運用できるように設計しています。
必要なアプリ登録手順
- Azure ポータル → Azure AD > アプリ登録 を開く
- 「新規登録」ボタンを押し、以下を入力
- 名前(例:
MyCalendarApp) - リダイレクト URI(Web アプリの場合は HTTPS のエンドポイント)
- 登録完了後、アプリ (クライアント) ID と ディレクトリ (テナント) ID をメモしておく
- API のアクセス許可 → Microsoft Graph → 委任された権限 で以下を選択
Calendars.ReadWrite(必須)offline_access(リフレッシュトークン取得のため推奨)- 必要に応じて 管理者同意 を実行し、権限が有効になるのを待つ
ポイント:最小権限の原則に従い、
Calendars.ReadWrite以外は付与しないことを推奨します。
認可コードフロー(完全版)
認可コードフローは以下 5 ステップで完了します。スコープ指定とリフレッシュトークン取得手順を含めて記載しています。
| ステップ | 内容 |
|---|---|
| 1. 認可リクエスト | ユーザーにサインインさせ、同意画面で Calendars.ReadWrite offline_access を要求する URL をブラウザへリダイレクトします。 |
| 2. 同意取得 & コード受領 | ユーザーが許可すると、認可コード (code) が リダイレクト URI にクエリパラメータとして付与されます。 |
| 3. トークンエンドポイントへ POST(アクセストークン + リフレッシュトークン取得) | grant_type=authorization_code、scope=https://graph.microsoft.com/.default offline_access を含めて送信します。 |
| 4. アクセストークン使用 | 取得した access_token を Authorization: Bearer <token> ヘッダーに設定し、Graph API を呼び出します。 |
| 5. リフレッシュトークンでアクセストークン更新(有効期限切れ時) | grant_type=refresh_token と取得した refresh_token を送信し、新しい access token と refresh token を受け取ります。 |
認可リクエスト例(URL エンコード済み)
|
1 2 3 4 5 6 7 8 |
https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize? client_id={client-id} &response_type=code &redirect_uri={encoded-redirect-uri} &scope=https%3A%2F%2Fgraph.microsoft.com%2FCalendars.ReadWrite%20offline_access &response_mode=query &state=12345 |
トークン取得(Node.js)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const axios = require('axios'); require('dotenv').config(); async function getToken(authCode) { const params = new URLSearchParams(); params.append('client_id', process.env.CLIENT_ID); params.append('scope', 'https://graph.microsoft.com/.default offline_access'); params.append('code', authCode); params.append('redirect_uri', process.env.REDIRECT_URI); params.append('grant_type', 'authorization_code'); params.append('client_secret', process.env.CLIENT_SECRET); const tokenUrl = `https://login.microsoftonline.com/${process.env.TENANT_ID}/oauth2/v2.0/token`; const res = await axios.post(tokenUrl, params); return res.data; // { access_token, refresh_token, expires_in, ... } } |
リフレッシュトークン取得例(Python)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import os, requests def refresh_access(refresh_token): url = f"https://login.microsoftonline.com/{os.getenv('TENANT_ID')}/oauth2/v2.0/token" data = { 'client_id': os.getenv('CLIENT_ID'), 'scope': 'https://graph.microsoft.com/.default offline_access', 'refresh_token': refresh_token, 'grant_type': 'refresh_token', 'client_secret': os.getenv('CLIENT_SECRET') } resp = requests.post(url, data=data) resp.raise_for_status() return resp.json() # 新しい access_token と refresh_token が含まれる |
イベントの CRUD 操作とサンプルコード
ここでは実際にカレンダー上でイベントを 作成・取得・更新・削除 する方法を示します。タイムゾーンや繰り返し設定など、よくある落とし穴にも触れます。
イベント作成(POST /me/events)
結論:必要最低限のプロパティだけ送ればすぐに予定が登録できます。
必要なヘッダー
Authorization: Bearer {access_token}Content-Type: application/json
サンプル(Node.js)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const axios = require('axios'); async function createEvent(token) { const event = { subject: "プロジェクトキックオフ", start: { dateTime: "2026-06-01T10:00:00", timeZone: "Asia/Tokyo" }, end: { dateTime: "2026-06-01T11:30:00", timeZone: "Asia/Tokyo" }, location: { displayName: "会議室 A" }, attendees: [ { emailAddress: { address: "alice@example.com", name: "Alice" }, type: "required" } ] }; const res = await axios.post( 'https://graph.microsoft.com/v1.0/me/events', event, { headers: { Authorization: `Bearer ${token}` } } ); return res.data; } |
サンプル(Python)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import os, requests def create_event(token): url = "https://graph.microsoft.com/v1.0/me/events" payload = { "subject": "プロジェクトキックオフ", "start": {"dateTime":"2026-06-01T10:00:00","timeZone":"Asia/Tokyo"}, "end": {"dateTime":"2026-06-01T11:30:00","timeZone":"Asia/Tokyo"}, "location":{"displayName":"会議室 A"}, "attendees":[ {"emailAddress":{"address":"alice@example.com","name":"Alice"},"type":"required"} ] } headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } resp = requests.post(url, json=payload, headers=headers) resp.raise_for_status() return resp.json() |
イベント取得(GET /me/events/{id})
ポイント:
$selectクエリで取得項目を絞ると、レートリミットの影響が軽減できます。
サンプル(Node.js)
|
1 2 3 4 5 6 |
async function getEvent(token, eventId) { const url = `https://graph.microsoft.com/v1.0/me/events/${eventId}?$select=subject,start,end,location`; const res = await axios.get(url, { headers: { Authorization: `Bearer ${token}` } }); return res.data; } |
イベント更新(PATCH /me/events/{id})
結論:変更したいフィールドだけを送信すれば部分的に上書きできます。
サンプル(Python)
|
1 2 3 4 5 6 7 8 9 10 11 |
def update_event(token, event_id): url = f"https://graph.microsoft.com/v1.0/me/events/{event_id}" payload = {"location": {"displayName": "会議室 B"}} headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } resp = requests.patch(url, json=payload, headers=headers) resp.raise_for_status() return resp.json() |
イベント削除(DELETE /me/events/{id})
ポイント:成功時は HTTP 204 が返ります。エラーハンドリングは必須です。
サンプル(Node.js)
|
1 2 3 4 5 6 7 |
async function deleteEvent(token, eventId) { await axios.delete( `https://graph.microsoft.com/v1.0/me/events/${eventId}`, { headers: { Authorization: `Bearer ${token}` } } ); } |
タイムゾーン・繰り返し設定の注意点
- timeZone は IANA 名(例:
Asia/Tokyo)を必ず指定してください。 - 繰り返しイベントは
recurrenceオブジェクトで定義します。現行 API ではpattern.type = "weekly"の場合、daysOfWeek配列が省略できない点に注意(公式ドキュメント参照)【1】。
リアルタイム通知と Webhook 設定方法
カレンダーの変更を即時に取得したい場合は Microsoft Graph Subscription を作成し、Webhook エンドポイントで通知を受け取ります。以下ではサブスクリプション作成手順と、Azure Functions / Flask での受信実装例を示します。
サブスクリプション作成(POST /subscriptions)
結論:有効期限は最大 4230 分(約 3 日) です。7 日という情報は公式に掲載されていませんので、実装時には 3 日以内に自動更新するロジックが必要です【2】。
必要フィールド概要
| フィールド | 説明 |
|---|---|
changeType |
"created,updated,deleted"(取得したい変更種別) |
notificationUrl |
HTTPS で公開されたエンドポイント(例: Azure Function の URL) |
resource |
"me/events" または "users/{id}/events" |
expirationDateTime |
ISO 8601 形式。最大 4230 分先まで設定可能 |
clientState |
任意文字列。通知受信時の検証に利用 |
サンプル(Node.js)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
async function createSubscription(token) { const body = { changeType: "created,updated,deleted", notificationUrl: "https://myapp.azurewebsites.net/api/graphWebhook", resource: "me/events", expirationDateTime: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString(), // 3日後 clientState: "mySecretValue" }; const res = await axios.post( 'https://graph.microsoft.com/v1.0/subscriptions', body, { headers: { Authorization: `Bearer ${token}` } } ); return res.data; } |
Webhook エンドポイント実装のポイント
- HTTPS 必須:自己署名証明書でも構わないが、信頼できる CA の証明書を推奨
- 検証リクエスト (
validationTokenクエリ) に対しては、受け取った文字列だけをステータス 200 で返す必要があります【3】
Flask(Python)実装例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
from flask import Flask, request, jsonify app = Flask(__name__) @app.route("/api/graphWebhook", methods=["GET", "POST"]) def webhook(): # 1️⃣ 検証リクエスト対応 if "validationToken" in request.args: return request.args["validationToken"], 200, {"Content-Type": "text/plain"} # 2️⃣ 本番通知受信 data = request.get_json() client_state = "mySecretValue" # サブスク作成時に設定したもの # 署名検証(Authorization ヘッダーは "Bearer <signature>") signature = request.headers.get("authorization", "").replace("Bearer ", "") import hmac, hashlib, base64, json expected = base64.b64encode( hmac.new(client_state.encode(), json.dumps(data).encode(), hashlib.sha256).digest() ).decode() if not hmac.compare_digest(signature, expected): return "Invalid signature", 401 # ビジネスロジック(例: DB 更新)をここに実装 print("Received Graph notification:", data) return jsonify({"status": "ok"}), 202 if __name__ == "__main__": app.run(host="0.0.0.0", port=443, ssl_context=("cert.pem", "key.pem")) |
Azure Functions(Node.js)実装例(署名検証付き)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
const crypto = require("crypto"); module.exports = async function (context, req) { // 検証リクエスト const token = req.query.validationToken; if (token) { context.res = { status: 200, body: token }; return; } const clientState = process.env.CLIENT_STATE; // サブスク作成時に設定した文字列 const receivedSig = (req.headers["authorization"] || "").replace("Bearer ", ""); const expectedSig = crypto .createHmac("sha256", clientState) .update(JSON.stringify(req.body)) .digest("base64"); if (!crypto.timingSafeEqual(Buffer.from(receivedSig), Buffer.from(expectedSig))) { context.res = { status: 401, body: "Invalid signature" }; return; } // 正常な通知処理 context.log("Graph notification:", req.body); context.res = { status: 202 }; }; |
サブスクリプション自動更新のベストプラクティス
- タイマー トリガー(Azure Functions の Timer)で有効期限が残り 12 時間以内になったら
PATCH /subscriptions/{id}を呼び出す - 同一テナント・同一ユーザーにつき、1 日あたり作成可能なサブスクリプション数は上限があります(公式: 100 件/アプリ)【4】。必要に応じて削除 (
DELETE) も併用してください。
ビジネス活用シナリオとベストプラクティス
ここでは Outlook カレンダー API を実際の業務プロセスに組み込む具体例を示します。数値的な効果は 「参考情報」 とし、出典が明示できない場合は記載しません。
1️⃣ 社内会議室予約システムとの双方向同期
- 目的:二重予約や空き情報の遅延を防ぎ、運用コストを削減する
- フロー
- 社内システムで予約が作成 →
POST /me/eventsで Outlook に同時登録 - Graph のサブスクリプション通知 → Azure Function が社内 DB を更新
-
キャンセルや変更は両方向に API 呼び出しを行い、整合性を保つ
-
ポイント
location.displayNameと社内の会議室コードをマッピング(例:"R001"↔︎"会議室 A")- 変更通知は 3 秒以内 に処理することで、ユーザー体感的な遅延を最小化
2️⃣ CRM(Salesforce 等)とのスケジュール連携
- 目的:営業担当者のカレンダーと商談情報を同期し、顧客対応漏れを防止
- 実装概要
- Azure AD アプリに
Calendars.ReadWriteとUser.Readを付与 - Salesforce の Apex から HTTP 呼び出しで Graph
/users/{id}/eventsを取得(バッチは 15 分ごと) -
新規商談作成時に
POST /me/eventsで Outlook に自動登録 -
留意点
- GDPR 適合のため、送信する属性は「件名・開始日時・終了日時」のみとし、顧客情報は暗号化して別途保存
- API 呼び出し回数が上限を超えないよう、
$filterと$selectを活用
3️⃣ Power Automate / RPA での定例会議自動生成
- 目的:コード不要で毎週・毎月の定例会議を自動作成し、手作業を削減
- フロー(Power Automate)
- 「スケジュール – 繰り返し実行」トリガー(例: 毎週月曜 9 時)
- 「HTTP」アクションで Graph
POST /me/eventsを呼び出す(アクセストークンは Azure Key Vault から取得) -
作成されたイベント ID を変数に保存し、続くステップで参加者追加や会議室変更を実施
-
RPA 補完例:UiPath ロボットが社内ファイルサーバーから資料を取得し、
PUT /me/events/{id}/attachmentsで添付
ベストプラクティス総括
| 項目 | 推奨アクション |
|---|---|
| レートリミット | 1 秒あたり最大 10 リクエストを上限にし、Retry-After ヘッダーで指数バックオフ |
| エラーハンドリング | 4xx 系は入力・権限チェック、5xx 系は再試行+監視アラート |
| 最小権限 | 必要なスコープだけ付与し、offline_access はリフレッシュトークンが必要な場合に限定 |
| コンプライアンス | データは暗号化保存、アクセスログを Azure Monitor に送出 |
| テスト環境の分離 | 開発用・本番用で別々の Azure AD アプリとテナントを使用し、誤操作による本番データ汚染を防止 |
まとめ
- Outlook カレンダー API は Microsoft Graph の公式エンドポイントとして安定提供されており、
v1.0とbetaが利用可能です。2024 年 11 月に「多言語対応」や「showAs=busy」等の機能追加があるという情報は、現時点では公式に確認できませんので実装前に必ず最新ドキュメントを参照してください【5】。 - Azure AD アプリ登録と OAuth 2.0 認可コードフロー(スコープ指定・リフレッシュトークン取得含む)を正しく設定すれば、
Calendars.ReadWrite権限で安全にカレンダー操作が可能です。 - CRUD のサンプルは Node.js と Python で示しましたが、共通して タイムゾーン(IANA 名)と 必須フィールド に注意してください。
- Webhook(Graph Subscription)は最大 4230 分(≈3 日) の有効期限しか設定できないため、定期的な自動更新ロジックが必須です。また、
validationTokenと HMAC 署名の検証はセキュリティ上重要です。 - ビジネスシナリオとして 会議室予約同期、CRM 連携、Power Automate/RPA 自動生成 を紹介しました。数値的な効果は「参考情報」とし、実装時には自社データで検証してください。
以上の手順とベストプラクティスを踏まえて、まずは Azure ポータルでアプリ登録し、サンプルリポジトリ(GitHub 例: myorg/outlook-calendar-samples)をクローンしてローカル環境で動作確認することをおすすめします。
参考リンク
- Microsoft Graph – Recurrence オブジェクト https://learn.microsoft.com/graph/api/resources/recurrence
- Microsoft Graph – Subscription 有効期限 https://learn.microsoft.com/graph/api/subscription-post-subscriptions#request-body
- Microsoft Graph – Webhook の検証手順 https://learn.microsoft.com/graph/webhooks
- Microsoft Graph – サブスクリプション作成上限 https://learn.microsoft.com/graph/api/resources/subscription?view=graph-rest-1.0#limitations
- Microsoft Graph – Changelog(2024‑11) https://learn.microsoft.com/graph/changelog