無料業務自動化

Googleカレンダー+n8nで会議直前アラートを完全自動化

·13 min read·Nexeed Lab
n8n業務自動化

n8nとGoogleカレンダーAPIを連携し、会議30分前にSlack通知・議事録テンプレート自動生成を実現するワークフロー構築手順を解説します。

「あ、今日の会議忘れてた」という経験は誰にでもあるはずです。 カレンダーは開いているのに、作業に集中していると通知を見逃してしまいがちです。 n8nとGoogleカレンダーを連携させれば、会議の30分前にSlackへ自動でアラートを送り、議事録テンプレートのリンクまで同時に通知できます。 外部サービスの追加契約なしで、Dockerとブラウザだけで完結する構成を解説します。

このワークフローで実現できること

  • 会議の30分前にSlackへ自動通知(タイトル・開始時刻・場所・参加者を含む)
  • 議事録テンプレート(Google Docs)のコピーリンクを通知に自動添付
  • 毎朝9時にその日の全会議スケジュールをSlackへ一覧投稿

通知メッセージはFunction Nodeで自由に整形できるため、チームの運用に合わせた拡張も容易です。 既存のGoogleカレンダーをそのまま使えるので、チームのカレンダー運用を変える必要はありません。

システム構成

このシステムは用途の異なる2つのワークフローで構成されています。

ワークフロー① 「30分前アラート」 Schedule Trigger(5分ごと)→ Google Calendar Node(今後35分以内の予定を取得)→ IF Node(0件ならスキップ)→ Function Node(通知メッセージを整形)→ Slack Node(チャンネルへ投稿)

ワークフロー② 「朝の会議一覧」 Schedule Trigger(毎朝9時)→ Google Calendar Node(当日の全予定を取得)→ Function Node(一覧メッセージを整形)→ Slack Node(チャンネルへ投稿)

2つを別々のワークフローとして管理することで、片方だけを一時停止したり設定変更したりしやすくなります。 通知チャンネルを変えたい場合も、対象のワークフローだけを編集すれば済みます。

事前準備

n8nのインストール

Dockerでn8nをローカルに起動します。 GENERIC_TIMEZONE=Asia/Tokyo を必ず指定してください。 この環境変数を省略すると、Schedule TriggerがUTC基準で動き、日本時間と9時間ずれた時刻に起動します。

docker run -it --rm \
  --name n8n \
  -p 5678:5678 \
  -v ~/.n8n:/home/node/.n8n \
  -e GENERIC_TIMEZONE=Asia/Tokyo \
  -e TZ=Asia/Tokyo \
  docker.n8n.io/n8nio/n8n

ブラウザで http://localhost:5678 を開き、初回のアカウントセットアップを完了させてください。 永続化したい場合は -v ~/.n8n:/home/node/.n8n のボリュームマウントが重要です。 これを省略すると、コンテナを停止するたびに設定やワークフローが消えてしまいます。

Google Calendar APIの認証設定

n8nからGoogleカレンダーを操作するにはOAuth2認証の設定が必要です。 手順はやや多いですが、一度設定すれば以後はトークンが自動更新されます。

まずGoogle Cloud Console(console.cloud.google.com)で新規プロジェクトを作成します。 「APIとサービス」→「ライブラリ」で Google Calendar API を検索して有効化します。 次に「認証情報」→「OAuth 2.0 クライアント IDの作成」を開き、種類に「ウェブアプリケーション」を選択します。 「承認済みのリダイレクト URI」に http://localhost:5678/rest/oauth2-credential/callback を追加します。 作成後に表示されるクライアントIDとクライアントシークレットをコピーしておきます。

n8n側では「Credentials」→「New Credential」→「Google Calendar OAuth2 API」を選択します。 コピーしたクライアントIDとシークレットを入力し、「Connect my account」ボタンを押します。 Googleアカウントでの認証が完了すれば、カレンダーデータへのアクセス許可が付与されます。

Slack Botの準備

api.slack.com/apps でSlack Appを新規作成します。 左メニューの「OAuth & Permissions」を開き、Bot Token Scopesに chat:write を追加します。 「Install to Workspace」でワークスペースにインストールし、表示される Bot User OAuth Token をコピーします。 n8nの「Credentials」→「Slack API」にこのトークンを登録しておきます。 最後に、通知を送りたいSlackチャンネルで /invite @ボット名 を実行してBotを参加させてください。

ワークフロー①:会議30分前アラート

Schedule Triggerの設定

「Every X Minutes」モードを選び、Intervalを 5 に設定します。 このノードが5分おきに起動し、次の会議まで30〜35分かどうかをチェックします。

Google Calendar Nodeの設定

  • Resource: Event
  • Operation: Get All
  • Calendar ID: 対象カレンダーのID(通常はGmailアドレスと同じ文字列)
  • Time Min: ={{$now.toISO()}}
  • Time Max: ={{$now.plus({minutes: 35}).toISO()}}

Time Maxを30分ぴったりでなく35分に設定する理由は、取得漏れを防ぐバッファを持たせるためです。 5分おきの起動タイミングによっては、ちょうど30分前を通り過ぎてしまうことがあるためです。

Function Nodeでメッセージを整形する

取得したイベントデータを、Slackへ投稿しやすいJSONに整形します。 conferenceData.entryPoints にはGoogle Meetの参加リンクが入っています。 event.location が設定されている場合はそちらを優先し、ない場合はMeetリンクにフォールバックします。 参加者リストは attendees 配列から自分(self: true)を除いて生成します。

const event = $input.item.json;
const startTime = new Date(event.start.dateTime || event.start.date);
const endTime = new Date(event.end.dateTime || event.end.date);

const formatTime = (date) => date.toLocaleString('ja-JP', {
  timeZone: 'Asia/Tokyo',
  month: 'numeric',
  day: 'numeric',
  hour: '2-digit',
  minute: '2-digit'
});

const attendees = (event.attendees || [])
  .filter(a => !a.self)
  .map(a => a.displayName || a.email)
  .join('、');

const location =
  event.location ||
  (event.conferenceData?.entryPoints?.[0]?.uri) ||
  '場所未設定';

const templateUrl =
  'https://docs.google.com/document/d/YOUR_TEMPLATE_ID/copy';

return [{
  json: {
    title: event.summary || '(タイトル未設定)',
    startTime: formatTime(startTime),
    endTime: formatTime(endTime),
    location,
    attendees: attendees || 'なし',
    templateUrl,
    eventLink: event.htmlLink
  }
}];

YOUR_TEMPLATE_ID は自分のGoogle DocsテンプレートのドキュメントIDに書き換えてください。 ドキュメントIDはGoogle DocsのURL中の /d//edit の間に含まれる文字列です。

Slack Nodeの設定

  • Resource: Message
  • Operation: Post
  • Channel: 通知先チャンネル名(例: #meeting-alerts

Messageフィールドには以下のテキストを入力します。

🔔 *30分後に会議があります*

*{{$json.title}}*
🕐 {{$json.startTime}} 〜 {{$json.endTime}}
📍 場所: {{$json.location}}
👥 参加者: {{$json.attendees}}

📝 <{{$json.templateUrl}}|議事録テンプレートを開く>
🔗 <{{$json.eventLink}}|カレンダーで確認>

ワークフロー②:朝の会議スケジュール一覧

Schedule Triggerの設定

CronモードでCron Expressionに 0 9 * * 1-5 を入力します。 この設定で平日(月〜金)の朝9時ちょうどに1回だけ起動します。 土日は動かないため、不要な通知が発生しません。

Google Calendar Nodeの設定

  • Time Min: ={{$now.startOf('day').toISO()}}
  • Time Max: ={{$now.endOf('day').toISO()}}

当日の0時から23時59分59秒までの全イベントを取得します。 前日や翌日の予定が混入しないため、スケジュール一覧が明確になります。

Function Nodeでスケジュール一覧を整形する

取得したイベントを開始時刻順に並び替え、Slackへ投稿するメッセージを生成します。 終日イベントは start.dateTime が存在しないためフィルターで除外しています。 会議が0件の場合も「会議なし」のメッセージを返すことで、Slack Nodeのエラーを防ぎます。

const events = $input.all();

const today = new Date().toLocaleDateString('ja-JP', {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  weekday: 'long',
  timeZone: 'Asia/Tokyo'
});

if (events.length === 0) {
  return [{ json: { message: `📅 *${today}* の会議はありません。` } }];
}

const sorted = events
  .map(e => e.json)
  .filter(e => e.start?.dateTime)
  .sort((a, b) =>
    new Date(a.start.dateTime) - new Date(b.start.dateTime)
  );

const eventList = sorted.map(event => {
  const start = new Date(event.start.dateTime);
  const end = new Date(event.end.dateTime);
  const timeStr =
    start.toLocaleTimeString('ja-JP', {
      hour: '2-digit', minute: '2-digit', timeZone: 'Asia/Tokyo'
    }) +
    '〜' +
    end.toLocaleTimeString('ja-JP', {
      hour: '2-digit', minute: '2-digit', timeZone: 'Asia/Tokyo'
    });
  return `• *${timeStr}* ${event.summary || '(タイトル未設定)'}`;
}).join('\n');

return [{
  json: {
    message: `📅 *${today} の会議スケジュール*\n\n${eventList}\n\n準備を忘れずに!`
  }
}];

Slack NodeのTextフィールドには ={{$json.message}} を設定します。

運用上の注意点

重複通知の防止 Schedule Triggerが5分ごとに起動するため、同じ会議を複数回検出する可能性があります。 完全に防ぐには、n8nのStatic Dataに通知済みイベントIDを保存し、IF Nodeで重複チェックを追加します。 まず基本構成で試してみて、重複が気になるようになったタイミングで対策を加えると良いでしょう。

終日イベントの扱い 終日イベントは start.dateTime ではなく start.date フィールドに日付文字列が入ります。 Google Calendar Nodeはデフォルトで終日イベントも取得します。 Function Node内の .filter(e => e.start?.dateTime) でこれを除外しているので、終日イベントへの誤通知は発生しません。

複数カレンダーへの対応 部署共有カレンダーなど複数のカレンダーを同時に監視したい場合は、Google Calendar Nodeを複数並べてMerge Nodeで結合します。 その後のIF NodeやFunction Nodeはそのまま再利用できます。

Googleトークンの有効期限 OAuthのリフレッシュトークンは長期未使用やGoogleのポリシー変更時に失効することがあります。 ワークフローが突然エラーになった場合は、n8nの「Credentials」から対象クレデンシャルを開き「Reconnect」で再認証してください。

トラブルシューティング

「Google Calendar API has not been used」エラーが出る Google Cloud ConsoleでCalendar APIが有効化されていないときに発生します。 「APIとサービス」→「ライブラリ」で「Google Calendar API」を検索し、有効化してください。

通知が9時間ずれて届く DockerコンテナのGENERIC_TIMEZONEが未設定のためUTCで動作しています。 コンテナ起動コマンドに -e GENERIC_TIMEZONE=Asia/Tokyo -e TZ=Asia/Tokyo を追加して再起動してください。

Slackに投稿されない BotがチャンネルにInviteされていない場合に発生します。 通知先チャンネルで /invite @ボット名 を実行してから、n8nのワークフローを手動でテストしてください。

まとめ

n8nとGoogleカレンダーを組み合わせることで、会議の見逃しと準備不足を同時に防げます。 コードはFunction Node内に収まっており、外部サーバーや追加のAPIキー管理なしにDocker一台で運用できます。 議事録テンプレートリンクの自動添付を加えることで、会議直前のバタバタした準備をなくせるのも大きなメリットです。 まずワークフロー①だけ試してみて、動作を確認できたらワークフロー②の朝の一覧通知へと拡張してみてください。

参考資料

この記事をシェア

XFacebookはてブ
Googleカレンダー+n8nで会議直前アラートを完全自動化 | AI活用ラボ