2026.10.04
GASでMeetのURLを発行する方法|乱数で作った偽URLの失敗

「予定を
自社で
ところが、Math.random())で
私

この記事の目次(6項目)
何が起きていたか:形だけ正しいMeetのURL
Google Meetのmeet.google.com/ の
問題の
// ★やってはいけない例(再現イメージ)
const pick = n => Array.from({ length: n },
() => 'abcdefghijklmnopqrstuvwxyz'[Math.floor(Math.random() * 26)]).join('');
const meetUrl = `https://meet.google.com/${pick(3)}-${pick(4)}-${pick(3)}`;
これで
時系列を
- 2026年8月18日:アシスタントを
作り直した回で、 「予定と Meetを まとめて 登録する」 ボタンが 入る - 2026年8月21日:URLを
自前で 組み立てている ことに 気づき、 修正 - 2026年8月22日:テスト用の
予定を 実際に 作り、 発行された URLが カレンダー側の 会議URLと 一致する ことを 確認して、 予定を 削除
怖いのは、
1. 実在しない
2. それを
3.
エラーが
正直に
なぜ「それらしい値」が紛れ込むのか
これは
プログラムを
仮の
た
会議の

GASでMeetのURLを正しく発行する方法
ここからが
CalendarAppではMeetを作れない
GASでCalendarApp です。CalendarApp にはcreateEvent で
ここで
Advanced Calendar Serviceを有効にする
Meetをappsscript.json には、
"dependencies": {
"enabledAdvancedServices": [
{ "userSymbol": "Calendar", "serviceId": "calendar", "version": "v3" }
]
}
私の
conferenceData.createRequest と conferenceDataVersion:1
予定をconferenceData.createRequest)をconferenceDataVersion: 1 を
いま動いている
function createEventWithMeet(body) {
// 日時は必ず +09:00 を明示する(素の new Date('2026-10-04') はUTC扱いになる)
var time = String(body.time);
var hhmm = time.length === 4 ? '0' + time : time; // 9:00 を 09:00 にそろえる
var startIso = body.date + 'T' + hhmm + ':00+09:00';
var startMs = new Date(startIso).getTime();
var dur = Number(body.durationMinutes) || 60;
var endIso = Utilities.formatDate(
new Date(startMs + dur * 60 * 1000), 'Asia/Tokyo', "yyyy-MM-dd'T'HH:mm:ss") + '+09:00';
var resource = {
summary: body.title,
start: { dateTime: startIso, timeZone: 'Asia/Tokyo' },
end: { dateTime: endIso, timeZone: 'Asia/Tokyo' },
conferenceData: {
createRequest: {
requestId: Utilities.getUuid(), // 依頼ごとに一意の値
conferenceSolutionKey: { type: 'hangoutsMeet' }
}
}
};
var ev = Calendar.Events.insert(resource, 'primary', { conferenceDataVersion: 1 });
var meetUrl = ev.hangoutLink || meetUrlOf_(ev);
// 割り当てが登録直後に間に合わないことがあるので、一度だけ取り直す
if (!meetUrl) {
Utilities.sleep(1500);
var again = Calendar.Events.get('primary', ev.id);
meetUrl = again.hangoutLink || meetUrlOf_(again);
}
// 発行できなかったときは必ず空で返す
return { ok: true, eventId: ev.id, htmlLink: ev.htmlLink || '', meetUrl: meetUrl || '' };
}
function meetUrlOf_(ev) {
var eps = (ev && ev.conferenceData && ev.conferenceData.entryPoints) || [];
for (var i = 0; i < eps.length; i++) {
if (eps[i].entryPointType === 'video' && eps[i].uri) return eps[i].uri;
}
return '';
}
押さえる
requestIdは依頼ごとに ここで一意の 値に する。 使っている Utilities.getUuid()は乱数由来の 値ですが、 役割が 違います。 これは 「この 依頼を 区別する ための 番号」を こちらが 付けているだけで、 URL その ものを 作っているわけでは ありません。 URLを 決めるのは Googleです - URLは
hangoutLinkから受け取る。 入っていないときは conferenceData.entryPointsの中から、 種類が videoのものを 探します - 登録直後は
会議室の 空だったら割り 当てが間に 合わない ことがある。 1.5秒待って、 予定を 一度だけ取り直します - それでも
取れなければ、 ここで空のまま 返す。 「それらしい 値」を 埋めない ことが、 この 記事で いちばん 大事な 一行です

発行できなかったとき、どう振る舞わせるか
本物を
呼び出す側
① カレンダーへの
案内文を
② 予定は
案内文は
予定は
登録しましたが、 Meetリンクを 発行できませんでした。 案内文に URLは 入れていません (カレンダーから 発行してください)。
③ どちらも
ここで
案内文を
const meetUrl = (r && r.meetUrl) || '';
const inviteText =
`【件名】${title}\n` +
`【日時】${date} ${time}から(${dur}分間)\n` +
(meetUrl ? `【Google Meet参加URL】\n${meetUrl}\n` : '');
「取れなかったら
自分のコードに同じ穴がないか確かめる5つ
直した
- 外部の
サービスが コードの発行するはずの 値を、 自分の プログラムで 作っていないか。 中で Math.randomや、日付から 番号を 作っている 箇所を 検索し、 その 値が どこへ 出ていくかを 追います。 まばたきの 間隔のような 「見た 目の 演出」に 使う 乱数は 問題ありません。 相手に 渡る 値に 使っていないかを 見ます - 取引先に
出る URL、文面に 入る 値は、 すべて 出どころを 言えるか。 日時、 金額、 番号。 1つずつ 「これは どこから 来た 値か」を 答えられるようにします - 失敗した
ときに、 わざと成功と 同じ メッセージが 出ていないか。 通信を 切る、 権限を 外すなどして、 失敗させてみます - 「取れなかった
とき」の 仮の値が 空に なっているか。 値や 前回の 値が 残らないかを 確かめます - 出てきた値を、
発行元で 今回は、突き合わせたか。 テストの 予定を 作り、 返ってきた URLと Googleカレンダーに 表示される 会議URLが 一致する ことを 見てから、 予定を 消しました
最後の
なdoPost は

まとめ:「それらしい値」は、エラーより怖い
エラーは
- Meetの
URLは、 形を 知っていても 自分で 作らない。 発行できるのは Googleだけ - GASでは
CalendarAppではなく、Advanced Calendar Serviceの conferenceData.createRequestとconferenceDataVersion: 1で発行する - 取れなかったら
空で 返し、 案内文に 載せず、 載せなかった ことを 表示する - 直したら、
発行元の 画面と 突き合わせて 「本物だった」を 確かめる
事務の
UMEO CREATEでは、
▼ AIエージェント導入支援に
https://www.umeocreate.com/agent.html
【群馬・北関東の
UMEO CREATE
「自社の
「うちの
17問の
群馬県内での