★ 【Python】OutlookスケジュールをGoogleカレンダーに自動同期 ★
【1】はじめに
仕事ではWindows版のOutlookを使い、プライベートや移動中にはスマホからGoogleカレンダーを確認するという使い分けをしている方は多いと思います。しかし、手動で両方の予定を更新するのは非常に手間がかかります。
今回はPythonを使って、Windows版Outlookの予定をGoogleカレンダーへ自動的に同期するツール(sync_calendar.py)を作成しましたので紹介します。
なお、世の中には、OGCS/OneCal/Zapier /Makeなど種々の優れたツールがありますが、逆に機能が多すぎて使いにくい側面もあります。
本ツールは、シンプルで軽いプログラムなので、用途に応じてカスタムして使う分には結構便利だと思います。
【2】動作環境
本ツールは、以下の環境で動作を確認しています。
- OS: Windows 10 / 11
- Outlook: Windows版(デスクトップアプリ)
- Python 3.x
【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】制限事項
本コードはシンプルな同期を実現するためのサンプルです。実運用にあたっては、以下の点にご注意ください。
- 単一PC専用 同じOutlookやGoogle Calendarに対して複数のPCから本ツールを実行すると矛盾が発生します。
【6】Google Cloudでの準備
Google Calendar APIを使用するには、Google Cloud Consoleでの設定が必要です。
1. プロジェクトの作成とAPIの有効化
- Google Cloud Consoleにアクセスし、新しいプロジェクトを作成します。
- 「APIとサービス」>「ライブラリ」から「Google Calendar API」を検索し、「有効にする」をクリックします。
2. OAuth 同意画面の設定
- 「APIとサービス」>「OAuth 同意画面」を選択します。
- 「User Type」で「外部」を選択し、「作成」をクリックします。
- アプリ名(例:sync_calendar)とサポートメール、デベロッパーの連絡先を入力し、「保存して次へ」をクリックします。
- 「スコープを追加または削除」をクリックし、`.../auth/calendar` を選択して追加します。
3. テストユーザーの追加
- 「テストユーザー」の項目で「+ ADD USERS」をクリックします。
- 自分のGoogleメールアドレスを入力し、「追加」をクリックします。
- 概要画面が表示されるので、一番下の「ダッシュボードに戻る」をクリックします。
4. 認証情報の作成とJSONファイルのダウンロード
- 左側のメニューから「APIとサービス」>「認証情報」を選択します。
- 画面上部の「+ 認証情報を作成」をクリックし、「OAuth クライアント ID」を選択します。
- 「アプリケーションの種類」から「デスクトップ アプリ」を選択し、任意の名前を入力して「作成」をクリックします。
- ポップアップ画面にある「JSON をダウンロード」をクリックして、ファイルを保存します。
- ダウンロードしたファイルを「credentials.json」にリネームして、スクリプトと同じフォルダに保存します。
【7】実行
予めOutlookを起動したあと、コンソールから以下のように入力して下さい。
python sync_calendar.py
初回実行時はブラウザが開き、Googleアカウントへのログインと権限の許可が求められます。許可すると `token.json` が生成され、次回からは自動で実行されます。
【8】技術的解説
本ツールの機能を以下に列挙します。
- ローカルPCで動作するOutlookのカレンダーから予定を取得しGoogle Calendarに保存する
- 同期する期間は実行日~1か月
- 複数回実行しても重複した項目のコピーを防止する(重複防止)
- 更新日時で差分更新する(Outlookで削除したものはGoogle Calendar側も同期して削除する)
- Google Calendar側で追加した予定には影響なし(削除しない、Outlook側にコピーしない)
- Google Calendar側の通知(reminder)は「なし」に設定
本ツールは、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回目以降の起動では認証、ログインが不要になります。
<注意事項>
- 削除したら、次回起動時に、ブラウザが開かれ再ログインになります
- 他PCにコピーした場合はそのまま使用可能(同じGoogleアカウントならOK)
このため他人に渡すと危険
ファイルには以下の項目が含まれています。
| 項目 | 意味 |
| 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の上記エントリ情報により以下を実現しています。
- 重複防止 (同じOutlook予定を何度も作らない)
- 更新検知 (Outlookの予定が変更されたか?)
- 削除検知 (Outlookから消えたか?)
【改訂記録】
2026/05/16版:公開
2026/05/18版:
- 誤記修正及び、下記のバグ修正
- 過去予定がGoogleカレンダーから消える
- 時間を開けるとGoogleログイン画面が出る
※修正箇所は"# v1.1"とコメントされている箇所
2026/05/22版:
- 以下のバグの修正
Outlookで「繰り返し」で設定されている予定のうちの1つの予定だけ、
日時を変更した場合、Googleカレンダー側に反映できない事象の対応
※修正箇所は"# v1.2"とコメントされている箇所
- 注意事項
変更後のsync_calendar.pyを実行前に以下を実施して下さい。
- Googleカレンダー側で、descriptionに「Outlook連携」と書かれている予定を全部削除
- synced_events.json を削除
[ホームへ戻る]