最近、会食が多く、初めましての方と話すことが多くありました。折角、話が弾んでも情報を覚え続けられないことが多く、この間も同じような話しましたよね?的な雰囲気になってしまったことが多々ありました。
そこで、簡単に何か便利なものができないか?と思い立ち、作ってみたのが、この通知システムです。
「会食メモ」という考え方
会食メモとは、会食や打ち合わせの内容を最低限記録し、次回に活かすためのメモです。
難しいことは不要です。


会食メモに書くべき最低限の項目
- 相手の名前・会社
- 会った日付
- 場所(店名など)
- 話した話題
- 次につながる一言
- 好み・NG話題(あれば)
これだけで十分です。
「会食メモ × リマインド」という仕組み
そこで私が作ったのが、
会食メモ × リマインドの仕組みです。
何ができるのか?
- 会食後、スマホで3分入力
- 会食メモを一元管理
- 次回の会食予定が近づくと前回の要点が自動で届く
「思い出す努力」を一切しなくて済みます。
仕組みは驚くほどシンプル
使っているのは、すべて無料のツールです。
- Googleフォーム(会食後の入力)
- Googleスプレッドシート(データ管理)
- Googleカレンダー(予定管理)
- Google Apps Script(自動処理)
流れはこうです。
会食後
↓
Googleフォームで会食メモ入力(3分)
↓
スプレッドシートに自動保存
↓
次回の会食予定が近づく
↓
前回の会食メモがメールで届く
実際に使って感じた変化
この仕組みを使い始めてから、明確に変わりました。
- 会食前の不安がなくなった
- 会話が自然につながる
- 「覚えてくれているんですね」と言われる
- 地雷を踏まなくなった
結果として、
人間関係に使うエネルギーが激減しました。何よりもその人のことを知りたいと前向きになりました。
会食メモは営業ツールではない
誤解されがちですが、
会食メモは営業職専用のものではありません。
- 社内の打ち合わせ
- 上司・部下との面談
- 取引先との会食
- 外部パートナーとのミーティング
人と継続的に関わるすべてのビジネスパーソンにおすすめです。
初心者でも続けられる理由
この仕組みが続く理由はシンプルです。
- 入力は「会食後に3分」
- 思い出す作業は「自動」
- 脳の負担がほぼゼロ
「頑張らなくても回る」ことが、最大の価値です。
完全版について
上記では考え方と全体像を解説しました。
実際に使っている完全版では、
- 会食メモ用Googleフォーム
- 人物一覧から自動で候補が更新される仕組み
- 自動リマインドスクリプト
- 初心者向けの設定手順
まで含めています。
そのまま使える形でまとめていきます。
会食メモ~リマインド作成
それでは早速、作成していきましょう。
0) 使い方(概要)
- Googleスプレッドシートを作成
People/Meetingsの2シートを作り、ヘッダー行を入れる
- Apps Scriptを開いて下記コード貼り付け
SPREADSHEET_IDを設定(シートURLの/d/と/editの間)setupTrigger()を1回実行(権限許可)- カレンダーにイベントを入れる
接待:山田 太郎(○○商事)形式
- 毎朝9時に自動でブリーフメールが届く
1) MVPのゴール(最初に作るもの)
できること
- 接待相手(人物)を登録・更新
- 接待(会食)予定を登録(Googleカレンダーに入れる)
- 予定日の前日(または当日朝)に、相手の要点をメールで自動通知
- 前回話した内容
- NG話題
- 好み(酒・食・話題)
- 次回のおすすめ話題(任意)
2) データベース設計(スプレッドシート)
スプレッドシートに以下の2シートを作ります。
シート① People シート 1行目(A1〜)
以下を 1行目にそのまま貼り付け(タブ区切り):
person_id name name_kana company title relationship_level likes_food likes_drink likes_topics ng_topics notes updated_at

シート② Meetings シート 1行目(A1〜)
meeting_id date person_id place attendees topics takeaway mood next_action created_at
Peopleにまず1人だけ登録(動作確認用)
Peopleの2行目に例として入力(タブ区切りコピペOK):
P0001 山田 太郎 やまだ たろう ○○商事 部長 A 鮨・和食 ハイボール ゴルフ・投資 政治・家庭 前回は新規案件の相談。次回は見積の方向性確認。
※ updated_at は空でOK(後で自動更新に拡張可能)
3) 予定(カレンダー)側の運用ルール

Googleカレンダーのイベントタイトルを以下の形式にします。
例:接待:山田 太郎(○○商事)
または会食:山田 太郎
GAS側はタイトルから 氏名を抽出し、Peopleに一致させます。
(氏名一致の精度を上げるため、Peopleのnameは「カレンダー表記と同じ」にするのがコツ)
デフォルトでのタイトルの先頭キーワードの許容例は「接待」「会食」「面談」「打合せ」「商談」
になります。
4) GAS構成(ファイルとトリガー)
実行タイミング
- 毎日 09:00 に定期実行
→ 24時間以内の接待イベントを探して通知
通知時間は変更可能です。後述を参照下さい。
GASの主な処理
- 今日〜24時間のカレンダーイベントを取得
- イベントタイトルから相手名を抽出
- Peopleから該当人物を検索
- 最新のMeetingsログを1件引く
- まとめてメール送信(自分宛)
5) Apps Scriptを作成してコード貼り付け
- スプレッドシート上部:拡張機能 → Apps Script

- 新規プロジェクトに、GASコードを貼り付け
- コード内の以下を設定:
SPREADSHEET_ID = "ここにスプレッドシートID";
SPREADSHEET_IDの取得方法は以下になります。
スプレッドシートURLの/d/ と /edit の間の文字列がIDです。
GAS実装コード
以下を Apps Script に貼り付けて使えます。
(※ SPREADSHEET_ID と CALENDAR_ID はあなたの環境に合わせて設定)
/**
* 接待メモ × リマインド(個人版A)
* - Google Calendarの予定(接待/会食)から相手を抽出
* - People / Meetingsから情報を引く
* - 自分宛に事前ブリーフィングをメール送付
* - 二重通知防止(同一イベントを一度だけ通知)
*/
/** ===== 設定 ===== */
const SPREADSHEET_ID = "ここにスプレッドシートID";
const CALENDAR_ID = "primary";
const NOTIFY_TO = Session.getActiveUser().getEmail();
const LOOKAHEAD_HOURS = 30; // 前日夜〜当日も拾えるよう少し長め
const SUBJECT_PREFIX = "【接待ブリーフ】";
/** ===== シート名 ===== */
const SHEET_PEOPLE = "People";
const SHEET_MEETINGS = "Meetings";
/**
* 毎日実行(推奨:09:00)
*/
function dailyBriefing() {
const now = new Date();
const end = new Date(now.getTime() + LOOKAHEAD_HOURS * 60 * 60 * 1000);
const cal = CalendarApp.getCalendarById(CALENDAR_ID);
const events = cal.getEvents(now, end);
if (!events || events.length === 0) return;
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const people = loadPeople_(ss);
const meetings = loadMeetings_(ss);
events.forEach(ev => {
const title = ev.getTitle();
const start = ev.getStartTime();
// 「接待:氏名(会社)」などから氏名を抽出
const personName = extractPersonName_(title);
if (!personName) return;
const person = findPersonByName_(people, personName);
if (!person) return;
// 二重通知防止キー
const notifyKey = buildNotifyKey_(person.person_id, start);
if (wasNotified_(notifyKey)) return;
const lastMeeting = findLastMeeting_(meetings, person.person_id);
const subject = `${SUBJECT_PREFIX}${person.name} / ${formatDateTime_(start)}`;
const body = buildBriefBody_(person, lastMeeting, title, start);
GmailApp.sendEmail(NOTIFY_TO, subject, body);
markNotified_(notifyKey);
});
}
/** ====== データ読込 ====== */
function loadPeople_(ss) {
const sh = ss.getSheetByName(SHEET_PEOPLE);
const values = sh.getDataRange().getValues();
values.shift(); // header
return values
.filter(r => r[0] && r[1])
.map(r => ({
person_id: r[0],
name: r[1],
name_kana: r[2],
company: r[3],
title: r[4],
relationship_level: r[5],
likes_food: r[6],
likes_drink: r[7],
likes_topics: r[8],
ng_topics: r[9],
notes: r[10],
updated_at: r[11],
}));
}
function loadMeetings_(ss) {
const sh = ss.getSheetByName(SHEET_MEETINGS);
const values = sh.getDataRange().getValues();
values.shift(); // header
return values
.filter(r => r[0] && r[2])
.map(r => ({
meeting_id: r[0],
date: r[1],
person_id: r[2],
place: r[3],
attendees: r[4],
topics: r[5],
takeaway: r[6],
mood: r[7],
next_action: r[8],
created_at: r[9],
}));
}
/** ====== タイトル解析 ====== */
function extractPersonName_(title) {
// 許容例:
// "接待:山田 太郎(○○商事)"
// "会食: 山田太郎"
// "面談:山田 太郎"
// → 先頭キーワード + ":" or ":" を見て抽出
const m = title.match(/^(接待|会食|面談|打合せ|商談)\s*[::]\s*([^\((]+)(?:[\((].*[\))])?$/);
if (!m) return null;
return m[2].trim();
}
function findPersonByName_(people, name) {
const norm = normalize_(name);
return people.find(p => normalize_(p.name) === norm) || null;
}
function findLastMeeting_(meetings, personId) {
const list = meetings
.filter(m => m.person_id === personId)
.sort((a, b) => new Date(b.date) - new Date(a.date));
return list[0] || null;
}
/** ====== メール本文 ====== */
function buildBriefBody_(person, lastMeeting, eventTitle, eventStart) {
const L = [];
L.push(`予定:${eventTitle}`);
L.push(`日時:${formatDateTime_(eventStart)}`);
L.push("");
L.push("■ 相手(要点)");
L.push(`- 氏名:${person.name}${person.name_kana ? `(${person.name_kana})` : ""}`);
L.push(`- 所属:${joinNonEmpty_([person.company, person.title], " / ") || "—"}`);
L.push(`- 重要度:${person.relationship_level || "—"}`);
L.push("");
L.push("■ 好み・地雷");
L.push(`- 食:${person.likes_food || "—"}`);
L.push(`- 酒:${person.likes_drink || "—"}`);
L.push(`- 話題:${person.likes_topics || "—"}`);
L.push(`- NG:${person.ng_topics || "—"}`);
L.push("");
L.push("■ 前回(直近ログ)");
if (lastMeeting) {
L.push(`- 日付:${formatDate_(lastMeeting.date)}`);
L.push(`- 場所:${lastMeeting.place || "—"}`);
L.push(`- 話題:${lastMeeting.topics || "—"}`);
L.push(`- 要点:${lastMeeting.takeaway || "—"}`);
L.push(`- 次アクション:${lastMeeting.next_action || "—"}`);
} else {
L.push("- 記録なし(初回 or 未入力)");
}
L.push("");
L.push("■ メモ");
L.push(person.notes || "—");
return L.join("\n");
}
/** ====== 二重通知防止 ====== */
function buildNotifyKey_(personId, startDate) {
const day = Utilities.formatDate(startDate, Session.getScriptTimeZone(), "yyyyMMdd");
const time = Utilities.formatDate(startDate, Session.getScriptTimeZone(), "HHmm");
return `brief_${personId}_${day}_${time}`;
}
function wasNotified_(key) {
const props = PropertiesService.getScriptProperties();
return props.getProperty(key) === "1";
}
function markNotified_(key) {
const props = PropertiesService.getScriptProperties();
props.setProperty(key, "1");
}
/**
* 1回だけ実行:毎日09:00のトリガー作成
*/
function setupTrigger() {
ScriptApp.newTrigger("dailyBriefing")
.timeBased()
.everyDays(1)
.atHour(9)
.create();
}
/**
* デバッグ用:通知履歴を全削除(必要なときだけ)
*/
function resetNotifiedFlags() {
const props = PropertiesService.getScriptProperties();
const all = props.getProperties();
Object.keys(all)
.filter(k => k.startsWith("brief_"))
.forEach(k => props.deleteProperty(k));
}
/** ====== util ====== */
function normalize_(s) {
return (s || "").replace(/\s+/g, "").trim();
}
function joinNonEmpty_(arr, sep) {
return arr.filter(v => v && String(v).trim()).join(sep);
}
function formatDateTime_(d) {
return Utilities.formatDate(d, Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm");
}
function formatDate_(d) {
if (!d) return "—";
const dd = (d instanceof Date) ? d : new Date(d);
return Utilities.formatDate(dd, Session.getScriptTimeZone(), "yyyy-MM-dd");
}

6) トリガーを1回だけ設定
Apps Scriptの関数一覧から setupTrigger() を実行

権限許可(Gmail/Calendar/Sheets)を進める
7) Googleカレンダーに予定を入れる(重要:タイトル形式)
タイトルは必ずこの形式にします:
接待:山田 太郎(○○商事)会食:山田 太郎
開始日時は、明日以降でも当日でもOKです。
(スクリプトは「今から30時間以内」を見て通知します)
8) 動作確認(すぐ試す)
Apps Scriptで dailyBriefing() を選択→「▷実行」をクリック。

自分宛に **【接待ブリーフ】**メールが届けば成功です。
運用ルール(最短で回る)
- 会食後にMeetingsへ1行だけ入れる(3分)
- date / person_id / place / topics / takeaway / next_action だけ埋めれば十分
- 次回の予定が入ると、前日(または当日)にメールで要点が届く
まとめ
ここでは、最小版の仕組みを紹介しました。次回は、Googleフォームからメモ内容をスプレッドシートに転記する機能を紹介します。
