【1】はじめに

仕事ではWindows版のOutlookを使い、プライベートや移動中にはスマホからGoogleカレンダーを確認するという使い分けをしている方は多いと思います。しかし、手動で両方の予定を更新するのは非常に手間がかかります。
今回はPythonを使って、Windows版Outlookの予定をGoogleカレンダーへ自動的に同期するツール(sync_calendar.py)を作成しましたので紹介します。 なお、世の中には、OGCS/OneCal/Zapier /Makeなど種々の優れたツールがありますが、逆に機能が多すぎて使いにくい側面もあります。 本ツールは、シンプルで軽いプログラムなので、用途に応じてカスタムして使う分には結構便利だと思います。

【2】動作環境

本ツールは、以下の環境で動作を確認しています。

【3】準備(ライブラリのインストール)

Outlookとの通信およびGoogle APIの使用のために、以下のライブラリが必要です。コマンドプロンプトからインストールしてください。

pip install pywin32 google-api-python-client google-auth-httplib2 google-auth-oauthlib

【4】ソースコード

以下が同期ツールのメインコードです。Google Cloudで取得する「credentials.json」と同じフォルダにファイル名「sync_calendar.py」で保存してください。

import win32com.client from datetime import datetime, timedelta import json import os from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from google.oauth2.credentials import Credentials from google.auth.transport.requests import Request # ====================== # 設定 # ====================== SCOPES = ['https://www.googleapis.com/auth/calendar'] STATE_FILE = "synced_events.json" # ====================== # Outlook予定取得 # ====================== def get_outlook_events(): outlook = win32com.client.Dispatch("Outlook.Application") namespace = outlook.GetNamespace("MAPI") calendar = namespace.GetDefaultFolder(9) items = calendar.Items items.IncludeRecurrences = True items.Sort("[Start]") # V1.1 old:start = datetime_now() start = datetime.now() - timedelta(days=2) end = start + timedelta(days=30) # V1.2 start_str = start.strftime("%m/%d/%Y") end_str = end.strftime("%m/%d/%Y") restriction = f"[Start] >= '{start_str}' AND [Start] <= '{end_str}'" restricted_items = items.Restrict(restriction) events = {} for item in restricted_items: try: # v1.2 start_val = item.Start end_val = item.End if not start_val or not end_val: continue key = item.EntryID + start_val.strftime("%Y-%m-%dT%H:%M:%S") events[key] = { "title": item.Subject or "", "start": start_val.strftime("%Y-%m-%dT%H:%M:%S"), "end": end_val.strftime("%Y-%m-%dT%H:%M:%S"), "location": item.Location or "", "updated": str(item.LastModificationTime) } except Exception as e: # v1.2 print("エラー:", e) continue return events # ====================== # Google認証 # ====================== def get_google_service(): creds = None if os.path.exists("token.json"): creds = Credentials.from_authorized_user_file("token.json", SCOPES) # v1.1 if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) # V1.1(自動更新) elif not creds or not creds.valid: flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES) creds = flow.run_local_server(port=0) with open("token.json", "w") as f: f.write(creds.to_json()) return build("calendar", "v3", credentials=creds) # ====================== # Google操作 # ====================== def add_event(service, oid, e): body = { "summary": e["title"], "location": e["location"], "start": { "dateTime": e["start"], "timeZone": "Asia/Tokyo" }, "end": { "dateTime": e["end"], "timeZone": "Asia/Tokyo" }, "description": f"Outlook連携\nOID:{oid}", # "通知"を無しに設定 "reminders": { "useDefault": False } } created = service.events().insert(calendarId='primary', body=body).execute() return created["id"] def update_event(service, gid, oid, e): body = { "summary": e["title"], "location": e["location"], "start": { "dateTime": e["start"], "timeZone": "Asia/Tokyo" }, "end": { "dateTime": e["end"], "timeZone": "Asia/Tokyo" }, "description": f"Outlook連携\nOID:{oid}", # v1.2 "reminders": { "useDefault": False } } service.events().update(calendarId='primary', eventId=gid, body=body).execute() def delete_event(service, gid): service.events().delete(calendarId='primary', eventId=gid).execute() # ====================== # 状態管理 # ====================== def load_state(): if os.path.exists(STATE_FILE): with open(STATE_FILE, "r") as f: return json.load(f) return {} def save_state(state): with open(STATE_FILE, "w") as f: json.dump(state, f, indent=2) # ====================== # メイン # ====================== def main(): print("==== 同期開始 ====") prev_state = load_state() outlook_events = get_outlook_events() service = get_google_service() new_state = {} add_count = 0 update_count = 0 delete_count = 0 # ===== ① 追加・更新 ===== for oid, e in outlook_events.items(): if oid not in prev_state: gid = add_event(service, oid, e) add_count += 1 else: gid = prev_state[oid]["google_id"] if prev_state[oid]["updated"] != e["updated"]: update_event(service, gid, oid, e) update_count += 1 new_state[oid] = { "google_id": gid, "updated": e["updated"] } # ===== ② 削除検知 ===== for oid in prev_state: if oid not in outlook_events: gid = prev_state[oid]["google_id"] try: delete_event(service, gid) delete_count += 1 except: pass save_state(new_state) print(f"追加: {add_count}件") print(f"更新: {update_count}件") print(f"削除: {delete_count}件") print("==== 完了 ====") if __name__ == "__main__": main()

【5】制限事項

本コードはシンプルな同期を実現するためのサンプルです。実運用にあたっては、以下の点にご注意ください。

【6】Google Cloudでの準備

Google Calendar APIを使用するには、Google Cloud Consoleでの設定が必要です。

1. プロジェクトの作成とAPIの有効化

  1. Google Cloud Consoleにアクセスし、新しいプロジェクトを作成します。
  2. 「APIとサービス」>「ライブラリ」から「Google Calendar API」を検索し、「有効にする」をクリックします。

2. OAuth 同意画面の設定

  1. 「APIとサービス」>「OAuth 同意画面」を選択します。
  2. 「User Type」で「外部」を選択し、「作成」をクリックします。
  3. アプリ名(例:sync_calendar)とサポートメール、デベロッパーの連絡先を入力し、「保存して次へ」をクリックします。
  4. 「スコープを追加または削除」をクリックし、`.../auth/calendar` を選択して追加します。

3. テストユーザーの追加

  1. 「テストユーザー」の項目で「+ ADD USERS」をクリックします。
  2. 自分のGoogleメールアドレスを入力し、「追加」をクリックします。
  3. 概要画面が表示されるので、一番下の「ダッシュボードに戻る」をクリックします。

4. 認証情報の作成とJSONファイルのダウンロード

  1. 左側のメニューから「APIとサービス」>「認証情報」を選択します。
  2. 画面上部の「+ 認証情報を作成」をクリックし、「OAuth クライアント ID」を選択します。
  3. 「アプリケーションの種類」から「デスクトップ アプリ」を選択し、任意の名前を入力して「作成」をクリックします。
  4. ポップアップ画面にある「JSON をダウンロード」をクリックして、ファイルを保存します。
  5. ダウンロードしたファイルを「credentials.json」にリネームして、スクリプトと同じフォルダに保存します。

【7】実行

予めOutlookを起動したあと、コンソールから以下のように入力して下さい。

python sync_calendar.py

初回実行時はブラウザが開き、Googleアカウントへのログインと権限の許可が求められます。許可すると `token.json` が生成され、次回からは自動で実行されます。

【8】技術的解説

本ツールの機能を以下に列挙します。

本ツールは、Outlook および Google Calendar の操作を行います。Outlookの操作はwin32com Libraryを使用します。
win32comは、Pythonを使用してWindowsアプリケーション(特にMicrosoft Officeアプリケーション)を操作するためのライブラリです。 Excelの操作はCOM(Component Object Model)というWindowsの仕組みを使用しますが、Pythonプログラムからこれを行うライブラリがwin32comになります。

本ツール ➔ win32com ➔ COM ➔ Outlookアプリ
具体的には以下の処理がoutlookのAPIになります。

import win32com.client … outlook = win32com.client.Dispatch("Outlook.Application") …

一方、Google Calendarの方は、Google API Client Libraryを使用しています。Google Calendarは、REST API経由でアクセスしますがGoogle API Client Libraryがこの間を取り持ちます。

本ツール ➔ Google API Client Library ➔ Google Calendar REST API
本ツールからカレンダーを操作するにはGoogle API Client Libraryの以下のAPIを使用します。

操作 API
予定追加 events.insert
予定更新 events.update
予定削除 events.delete
認証 OAuth 2.0

プログラムとデータを配置するフォルダ構成は以下のようになります。「c:\sync」は、別のディレクトリでもかまいません。

C:\sync\ ├ sync_calendar.py ├ credentials.json ← Google Calendarから取得 ├ token.json ← 自動生成 └ synced_events.json ← 自動生成
credentials.jsonは、本ツールがGoogleにアクセスするためのアプリを証明するファイルです。 事前に、Google Cloud Consoleへアクセスして取得します(手順は【6】参照)。
ファイルには以下の項目が含まれています。
項目 説明
client_id アプリのID
client_secret アプリのパスワード
project_id Google Cloudのプロジェクト
auth_uri ログイン先
token_uri トークン取得先

初回実行時に以下のコードで、 (1)Googleに接続、(2)ログイン画面を出す、(3)権限を要求する が行われます。
flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES)
token.jsonは、Googleにログインした状態を保存するファイルであり、Google Calendar REST APIを使えるようにする認証情報です。 初回実行時にブラウザが起動して認証、ログイン作業を行いますが、このタイミングでtoken.jsonが作成され、2回目以降の起動では認証、ログインが不要になります。
<注意事項> ファイルには以下の項目が含まれています。
項目 意味
access_token APIを実行するための鍵
refresh_token 自動で再ログインするための鍵
expiry 有効期限
synced_events.jsonは、OutlookとGoogleの対応関係を覚えておくファイルです。以下がファイルの中身(例)です。 予定の数だけエントリが作成されます。
{ "00000000C1A8C1…504F0000": { "google_id": "92dutlq9ot91jodtccackikvbs", "updated": "2026-05-11 13:29:34.788000+00:00" }, "00000000C1A8C1…EB290000": { "google_id": "9fsh2s0op9rfrjltj12tp7dqic", "updated": "2026-05-12 07:52:22.467000+00:00" }, … }
各エントリは以下の項目で構成されています。
項目 意味
Outlook ID Outlookの予定の識別子
google_id Googleカレンダー上のID
updated 最終更新日時
synced_events.jsonの上記エントリ情報により以下を実現しています。


【改訂記録】
2026/05/16版:公開
2026/05/18版:

2026/05/22版:

[ホームへ戻る]