アフィリエイト広告を利用しています

Claude CodeでZoom一括予約ツール【実践レポート】CSVから一括登録・招待者管理・Googleカレンダー連携まで

Zoomのミーティング、1件ずつポチポチ登録していること、ありませんか?

3件くらいなら「まぁ、いいか」ってなるんですけど、講座の予約を7件とか8件とか入れないといけないとき、しかも全部に招待者を追加しないといけないとき……もう、心が折れそうになりますよね。

Claude Codeとの対話だけで、CSVからZoomミーティングを一括登録して、Googleカレンダー経由で招待メールまで送れるローカルアプリを作りました。

開発にかかった時間は、およそ3時間。

コードは1行も自分で書いていません。Claude Codeに「こうしたい」「ああしたい」と伝えていっただけ。そのやり取りの過程を記録しておきます。

きっかけは「7件のZoomミーティングに招待者を追加する作業」

講座用のZoomミーティングが7件ありまして。

第1講〜第7講まで、それぞれに受講者のメールアドレスを招待者として登録する必要がありました。

1件ずつZoomの管理画面を開いて、メールアドレスをコピペして、保存して、次のミーティングを開いて……。

「これ、面倒だなぁ」

面倒と感じたら、自動化したくなるのがエンジニア。

というわけで、Claude Codeに相談してみたんです。

まずはCSVから一括登録するUIを作った

最初は「CSVを読み込んで、Zoomミーティングを一括登録するWebアプリがほしい」という、ざっくりしたリクエストから始めました。

Claude Codeが最初に作ってくれたのは、和風デザインのHTML。判子アイコンに明朝体フォント。

「いや、実用的なデザインにして。和の要素は不要」

と伝えたら、すぐにInter + JetBrains MonoのモダンなUIに変わりました。ブルー基調の落ち着いた業務ツールっぽいデザイン。いい感じ。

3ステップのウィザード形式

できあがったUIは、3ステップ構成です。

  1. CSV読み込み — ファイルドロップまたはテキスト直接入力
  2. 内容確認 — パース結果をテーブル表示、チェックボックスで選択
  3. 登録完了 — 結果一覧とJoin URLの表示

日付形式は 2026-04-17 だけじゃなく 2026/04/17 にも対応してもらいました。スラッシュ区切りもよく使いますから。

ローカルアプリでいいやん

最初はCloudflare Workerとしてデプロイする前提で進んでいたんですが、途中で気づきました。

「あっ、Webアプリじゃなくていいの。ローカルで動けば十分。」

ということで、シンプルなNode.jsのローカルサーバーに方針転換。node server.js で起動して、http://localhostにアクセスするだけ。

1Passwordから認証情報を自動取得

ここがちょっとこだわったポイント。Zoom APIのClient IDやSecretを .env ファイルに書くのではなく、1Password CLI(opコマンド)から起動時に自動取得する仕組みにしました。

function getSecret(item, field) {
  return execSync(`op read "op://Development/${item}/${field}"`, { encoding: 'utf-8' }).trim();
}

サーバー起動時にこんな感じで認証情報を読み込みます。

1Password から認証情報を取得中...
  Zoom: OK
  Google Calendar: OK (OAuth2)
Zoom 一括予約サーバー起動中: http://localhost:xxxx

安心感がありますよね。秘密情報をファイルに残こさずに処理できます。

Zoom APIとの格闘

スコープが足りない問題

Zoom S2S(Server-to-Server)OAuthアプリを作って、1Passwordに認証情報を保存。ここまでは順調。

で、いざミーティング一覧を取得しようとしたら……

Invalid access token, does not contain scopes:[meeting:read:list_meetings]

ここでハマりました。

Zoom Marketplaceでアプリのスコープを追加する必要があったんです。しかも一覧取得と個別取得で別のスコープが必要という。

最終的に必要だったスコープはこちら:

  • meeting:read:list_meetings — 一覧取得
  • meeting:read:meeting — 個別詳細取得
  • meeting:write:meeting — 作成
  • meeting:update:meeting — 更新
  • meeting:delete:meeting — 削除

1つずつエラーを見ながら追加していった感じです。

定期ミーティングの罠

招待者を取得しようとしたら、start_timeundefined になる問題が発生。

調べてみると、定期ミーティング(recurring meeting)の場合、start_time ではなく occurrences という配列に各回のスケジュールが入っているんですね。

if (detail.occurrences && detail.occurrences.length > 0) {
  const futureOccurrences = detail.occurrences
    .filter(o => o.start_time >= now && o.status === 'available');
  // 各回分を処理
} else if (detail.start_time) {
  // 通常のミーティング
}

Claude Codeがこの分岐をサッと書いてくれて、「なるほど、そういう構造なのか」と勉強になりました。

Google Calendar連携で招待メールを送る

Zoomの meeting_invitees にメールアドレスを追加しても、招待メールは自動送信されないということが判明。

じゃ、どうすれば、いいのか?

Google Calendarにイベントを作って、sendUpdates: 'all' を指定すれば、Googleカレンダー経由で招待メールが送られる。Zoom Join URLを本文に含めておけば、受け取った人はそこからミーティングに参加できるという流れを。

サービスアカウントではダメだった

最初はGoogleのサービスアカウントで認証しようとしました。

unauthorized_client: Client is unauthorized to retrieve access tokens using this method

個人のGmailアカウント(Google Workspace以外)では、サービスアカウントの「ドメイン全体の委任」が使えないんですね。OAuth2クライアント認証に切り替える必要がありました。

OAuth2の初回認証スクリプト

OAuth2認証の場合、初回だけブラウザでログインしてリフレッシュトークンを取得する必要があります。これ用の専用スクリプト auth-google.js を作りました。

node auth-google.js

実行するとURLが表示されて、ブラウザで認証すると、リフレッシュトークンが自動的に1Passwordに保存される仕組み。

ふぅ。これでようやくGoogle Calendar連携が動くようになりました。

タイムゾーンの二重変換問題

「13時開始のミーティングが、Googleカレンダーで早朝4時になっている!」

9時間ずれ。UTC→JSTの二重変換が原因でした。

toISOString() がUTC文字列(Z付き)を返すのに、Google Calendar APIに timeZone: 'Asia/Tokyo' を指定していたので、UTC時刻をJSTとして解釈してしまっていたんです。

修正後は、+09:00 付きのJST文字列を直接生成するようにしました。

function toJSTString(date) {
  const jst = new Date(date.getTime() + 9 * 60 * 60 * 1000);
  // ...
  return `${y}-${mo}-${d}T${h}:${mi}:${s}+09:00`;
}

タイムゾーン、難しい、、です。

完成したツールの機能まとめ

最終的に、こんな機能を持つツールが完成しました。

新規登録タブ

  • CSVファイルのドロップまたはテキスト入力
  • バリデーション(日付・時間・会議名のチェック)
  • チェックボックスで登録対象を選択
  • Zoomミーティング一括作成
  • Google Calendar経由で招待メール自動送信

招待者追加タブ

  • Zoomから予定済みミーティング一覧を取得
  • キーワード絞り込み(会議名・日時・IDで検索)
  • 表示中のミーティングの招待者を一括取得
  • 招待者一括追加(Zoom + Googleカレンダー招待メール)
  • 招待メールのみ送信モード(Zoom側は変更しない)
  • ミーティング一括削除(確認ダイアログ付き)

ファイル構成

zoom-scheduler/
├── server.js          # Node.js サーバー(Zoom API + Google Calendar API)
├── auth-google.js     # Google OAuth2 初回認証スクリプト
├── package.json
├── run.sh             # メニュー式起動スクリプト
└── public/
    └── index.html     # フロントエンド UI

たった5ファイル。シンプルな構成です。

Claude Codeとの開発で感じたこと

「対話で開発」のリアル

今回のやり取りで印象的だったのは、エラーを貼るだけで解決策が返ってくること。

Zoom APIのスコープエラー、Google認証のエラー、タイムゾーンのずれ……。ターミナルのエラーメッセージをそのまま貼ると、「あ、これはスコープが足りないですね」「OAuth2に切り替えましょう」と返ってくる。

自分で調べる時間がほぼゼロ。

ドキドキするくらいスムーズでした。

方針転換も柔軟

「Cloudflare Workerで」→「やっぱりローカルアプリで」→「サービスアカウントで」→「OAuth2に切り替えて」

こういう方針転換を何度もしましたが、Claude Codeは嫌な顔ひとつせず(顔ないけど)、すぐに対応してくれました。

ハマりポイントは人間側の知識不足

技術的なハマりポイントのほとんどは、ZoomやGoogleの管理画面での設定漏れでした。スコープの追加、OAuth同意画面の設定、テストユーザーの追加……。

コード側の問題はClaude Codeがすぐ解決してくれるけど、外部サービスの設定画面は自分で操作する必要があり、このあたりの理解不足からのトライエラーでした。

起動方法

cd ~/zoom-scheduler
node server.js

ブラウザで http://localhost:xxxx を開くだけ。

1Passwordにサインインしていれば、認証情報は自動で読み込まれます。

まとめ

  • CSVからZoomミーティングを一括登録できる
  • 既存ミーティングに招待者を一括追加できる
  • Google Calendar経由で招待メールを自動送信できる
  • ミーティングの一括削除もできる
  • 認証情報は1Passwordで安全に管理
  • 開発はClaude Codeとの対話だけ、コード手書きゼロ

Zoomのミーティング管理で「もうちょっと楽にならんかな」と思っている方、Claude Codeとの対話で自分専用のツールを作ってみる、という選択肢もありますよーという実例でした。

この記事を書いた人

大東 信仁

カンパチが好きです。

プロフィールはこちら

10月14日開催 参加者募集中
(画像をタップ→詳細へ)

ミッションナビゲート モニター
(画像をタップ→詳細へ)

広告