Google Apps Script(GAS)は、Googleスプレッドシート・Gmail・カレンダー・ドライブ・フォームを、JavaScriptで書いた短いプログラムで動かす仕組みです。Google Workspaceにも無料のGoogleアカウントにも最初から入っていて、追加の契約もサーバーも要りません。フォームの回答が来たら確認メールを返す、毎朝その日の予約をChatに送る、月末に請求書のPDFを作る、といった「毎回だれかが手でやっている作業」を置き換えるのが主な使いみちです。この記事では、GASで何ができて何ができないか、どこにスクリプトを作るか、最初の1本を動かすまでの手順と、そのときに出る承認の画面の意味を順に書きます。例は全記事で共通の、スタッフ6名ほどの予約制の小さな料理教室「サンプル料理教室」です。プログラミングの経験は無くても読めるように書いていますが、コードをコピーして貼り、少し書き換えるところまでは手を動かします。
この記事の内容
先に決めること
GASは書きはじめるのが簡単なぶん、次の3つを決めずに作ると、半年後に「誰が作ったか分からないスクリプトが動いていて、止め方も分からない」状態になります。
1つ目は、誰のアカウントで作るかです。GASのスクリプトやトリガーは、作った人のアカウントで動きます。担当者の個人のアカウントで作ると、その人が辞めてアカウントを消したときに止まります。サンプル料理教室では、会社のアカウントのうち、代表のアカウントか、仕組み用に1つ用意した管理用のアカウントで作ると決めています。作ったスクリプトの一覧は、どのファイルに何があって何をするかを1枚のシートに書いておきます。
2つ目は、GASでやるか、標準機能でやるか、別の道具でやるかです。フォームの回答のコピーを回答者に送るだけならフォームの標準の設定でできますし、表の集計なら関数で足ります。GASは「標準機能では届かないところ」だけに使います。Googleの外のサービス(LINE・kintone・会計ソフトなど)と何本もつなぐなら、最初からn8nに任せたほうが後が楽です。目安は後の章で書きます。
3つ目は、管理コンソールでGASを使える人を絞るかどうかです。既定では、Apps Scriptは組織内のすべてのユーザーとゲストに対してオンになっています。スタッフが6名ほどならそのままで困ることは少ないですが、誰でも作れる状態にしておくと、知らないところでメールを自動送信するスクリプトが動いていることがあります。絞るなら、管理コンソールの「メニュー」→「アプリ」→「Google Workspace」→「ドライブとドキュメント」→「Google Apps Script」で、組織部門ごとにオンとオフを切り替えます。オフにした人は、スクリプトの作成・編集・実行ができなくなり、トリガーも動かなくなります。その人が持ち主のスクリプトでも、オンのままのほかの人は引き続き開いて実行できます。オフにする前に、その人のトリガーで動いているものがないか先に確かめます。反映には最長で24時間ほどかかることがあります。
GASでできること
GASは、Googleの各アプリを操作するための「サービス」を呼び出して動きます。業務でよく使うのは次のとおりです。
| 対象 | 使うサービス | できることの例 | サンプル料理教室での使いみち |
|---|---|---|---|
| スプレッドシート | SpreadsheetApp | 行を読む・書く・並べ替える・シートを作る | 予約一覧の対応状況を読む、台帳へ転記する |
| Gmail | GmailApp・MailApp | メールを送る、下書きを作る、受信を検索する | 体験申込の確認メール、月謝の請求書の送付 |
| カレンダー | CalendarApp | 予定を作る・読む・変える | 体験の予約をレッスンのカレンダーに入れる |
| ドライブ | DriveApp | ファイルやフォルダを作る・コピーする・移動する | 請求書のPDFを経理フォルダに保存する |
| フォーム | FormApp | 質問を作る、回答を読む、選択肢を書き換える | 体験の日程の選択肢を毎週入れ替える |
| ドキュメント・スライド | DocumentApp・SlidesApp | ひな形をコピーして文字を差し込む | 修了証や案内文を会員ごとに作る |
| 外部のAPI | UrlFetchApp | 外のサービスにHTTPで送る・受け取る | Chatのスペースや姉妹サイトのLINEに通知を送る |
| Webアプリ | HtmlService・ContentService | URLを開くと動くページや受け口を作る | 講師用の簡単な入力ページ |
| 画面の追加 | SpreadsheetApp.getUi など | メニュー・ダイアログ・サイドバー | スプレッドシートに「教室メニュー」を足す |
| 自分で作る関数 | カスタム関数 | セルで =関数名() として使う | 税込の金額を計算する関数 |
これらを「いつ動かすか」を決めるのがトリガーです。毎朝8時に動かす、フォームが送信されたら動かす、スプレッドシートが編集されたら動かす、といった指定ができます。トリガーは次の記事で詳しく書きます。
コードは今のJavaScriptで書きます。JavaScriptを書いたことがなくても、この記事のコードをそのまま貼れば動きます。少しずつ書き換えて覚える形で十分です。
スタンドアロンとコンテナバインド
GASのスクリプトには、置き場所が2種類あります。最初にどちらで作るかを決めます。
| コンテナバインド | スタンドアロン | |
|---|---|---|
| どこにあるか | スプレッドシート・ドキュメント・スライド・フォームの中 | ドライブに単独のファイルとして置かれる |
| 作り方 | ファイルを開いて「拡張機能」→「Apps Script」(フォームは「その他」メニューから「スクリプト エディタ」) | script.google.com で「新しいプロジェクト」、またはドライブで「新規」→「その他」→「Google Apps Script」 |
| ドライブに表示されるか | されない | される |
| 親のファイルの扱い | getActiveSpreadsheet() などで、IDを書かずに親のファイルを参照できる | ファイルIDを指定して開く |
| メニューやダイアログ | 親のファイルに足せる | 足せない |
| 切り離し | 親のファイルから切り離せない | もともと単独 |
| ファイルをコピーしたとき | スクリプトもコピーされ、コピーした人がコピーの持ち主になる | 影響なし |
| 向く使いみち | 1つの台帳の中で完結する処理 | 複数のファイルをまたぐ処理、Webアプリ |
サンプル料理教室で作るものは、ほとんどがコンテナバインドです。予約一覧のスプレッドシートの確認メール、会員台帳のスプレッドシートの請求書、というように、処理が1つの台帳に結びついているからです。台帳を開けばそこにスクリプトがあるので、あとから「どこにあるのか」で迷いません。
スタンドアロンにするのは、複数の台帳をまたいで動く処理です。たとえば、予約一覧と会員台帳と出席表の3つを毎晩読んで、Chatに1日のまとめを送る処理は、どれか1つのファイルに入れると、そのファイルを誰かがコピーしたり消したりしたときに巻き込まれます。
コンテナバインドの注意は、ファイルをコピーするとスクリプトもコピーされることです。月ごとに台帳をコピーして新しい月のファイルを作る運用をしていると、トリガーの無いスクリプトのコピーが毎月増えていきます。実際に運用していると、インストール型のトリガーはコピーしたファイルには付いてこず、新しいファイルでは作り直すまで自動では動きません。台帳を月ごとにコピーする運用はやめて、1つの台帳に月の列を持たせるほうがGASとは相性がよいです。
手順:最初のスクリプトを作って動かす
予約一覧のスプレッドシートで、対応状況が「未対応」の申込の件数と名前を、自分あてにメールで送るスクリプトを作ります。予約一覧のシートは、1行目が見出しで、A列から順に「タイムスタンプ」「氏名」「メール」「希望日」「コース」「経路」「対応状況」と並んでいるとします。
エディタを開く(パソコン)
- 予約一覧のスプレッドシートを開きます。
- メニューの「拡張機能」→「Apps Script」をクリックします。
- 新しいタブでApps Scriptのエディタが開きます。左上の「無題のプロジェクト」をクリックし、「予約一覧の通知」と名前を付けて「名前を変更」をクリックします。
- 中央のコードの欄に最初から入っている
function myFunction() {}を全部消します。

スマホのスプレッドシートのアプリでは作業しません。作るのも直すのもパソコンのブラウザで行います。
コードを貼る
- 次のコードを貼ります。
function countRows() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('予約一覧');
const lastRow = sheet.getLastRow();
Logger.log('予約一覧のデータは ' + (lastRow - 1) + ' 件です');
}
function notifyPending() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('予約一覧');
const values = sheet.getDataRange().getValues();
const header = values.shift();
const nameCol = header.indexOf('氏名');
const dateCol = header.indexOf('希望日');
const statusCol = header.indexOf('対応状況');
const pending = values.filter(function (row) {
return row[statusCol] === '未対応';
});
const lines = pending.map(function (row) {
const d = row[dateCol];
const dateText = d instanceof Date
? Utilities.formatDate(d, 'Asia/Tokyo', 'M/d HH:mm')
: String(d);
return '・' + row[nameCol] + ' 様(希望日 ' + dateText + ')';
});
const to = Session.getActiveUser().getEmail();
const subject = '未対応の体験申込 ' + pending.length + '件';
const body = pending.length > 0 ? lines.join('\n') : '未対応の申込はありません。';
MailApp.sendEmail(to, subject, body);
Logger.log(subject);
}
- キーボードで
Ctrl+S(Macは⌘+S)を押すか、保存のアイコンをクリックして保存します。
1つ目の countRows は、シートを読んでログに件数を出すだけの関数です。2つ目の notifyPending が本番の処理で、見出しの名前から列の位置を探しているので、列の並びが変わっても動きます。'予約一覧' はシートのタブの名前と1文字でも違うと動かないので、自分のシート名に合わせて書き換えます。
実行して承認する
- エディタの上にある関数の選択欄で
countRowsを選びます。 - 「実行」をクリックします。
- はじめて実行すると、権限の確認が出ます。「権限を確認」をクリックします。
- 会社のアカウントを選びます。
- スクリプトが求める権限の一覧が出るので、内容を読んで「許可」をクリックします。
- 画面の下に「実行ログ」が開き、
予約一覧のデータは 12 件ですのような行が出れば成功です。


- 関数の選択欄で
notifyPendingを選び、「実行」をクリックします。 - メールを送る権限が新しく要るので、もう一度権限の確認が出ます。手順9から11と同じように許可します。
- 自分のGmailに「未対応の体験申込 3件」のようなメールが届けば完成です。
コードに新しいサービス(今回はメールの送信)を足すと、前に承認したスクリプトでも、追加の承認が求められます。コメントにしただけのコードでも、そのサービスの承認を求められることがあります。
スプレッドシートにメニューを足す
毎回エディタを開いて実行するのは手間なので、スプレッドシートのメニューから動かせるようにします。同じエディタの末尾に次のコードを足して保存します。
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('教室メニュー')
.addItem('未対応の申込をメールで送る', 'notifyPending')
.addToUi();
}
予約一覧のスプレッドシートを再読み込みすると、メニューの右端に「教室メニュー」が出ます。受付はここをクリックするだけで、未対応の一覧を自分あてに送れます。受付が初めて使うときは、受付のアカウントで承認の画面が出ます。

承認の画面と警告の意味
GASは、実行の前にコードを読んで、どのサービス(スプレッドシート、Gmailなど)を使うかを調べ、それに必要な権限(スコープ)を自動で決めます。実行する人がまだ承認していなければ、承認の画面が出ます。承認すると、スクリプトはその人のデータにその人の権限でアクセスできます。
ここで「このアプリは Google で確認されていません」という警告の画面が出ることがあります。これは、スクリプトがGmailやドライブのような機密性の高い権限を使っているのに、Googleの審査を受けていないときに出るものです。同じ組織の中だけで使う内部向けのアプリは審査が要らないとされていますが、社内で作ったスクリプトでも、使う権限や実行する人のアカウントによってはこの警告が出ることがあります。「ウイルスがある」という意味ではありません。
ただし、警告を進めてよいのは、自分か社内の担当者が書いたコードで、中身を読んで何をするか分かっている場合だけです。他人から送られてきたスプレッドシートを開いて、知らないスクリプトの承認を求められたら、進めずに閉じます。承認すると、そのスクリプトは自分のGmailやドライブに自分の権限でアクセスできるからです。
承認の取り消しは、Googleアカウントの「セキュリティ」→「サードパーティ製のアプリとサービスへの接続」→「すべての接続を表示」から、そのスクリプトを選んで削除します。スクリプトを使わなくなったら、ここから外しておきます。
| 画面 | 意味 | 進めてよいか |
|---|---|---|
| 権限の確認(「権限を確認」) | このスクリプトが使う権限の承認を求めている | 自分で書いた、または社内で確認済みのスクリプトなら進める |
| 「このアプリは Google で確認されていません」 | 機密性の高い権限を使うが、Googleの審査を受けていない | 中身が分かっている社内のスクリプトなら進める。知らないものは閉じる |
| 権限の一覧 | メールの送信、スプレッドシートの読み書きなど、何を許すか | 内容がコードの目的と合っているか読む |
| 「その操作を実行するには承認が必要です。」(エラー) | 承認していない状態でトリガーなどから動いた | エディタで関数を1回手で実行して承認する |

実行時間と割り当て(2026年10月時点)
GASは無料で使えるかわりに、1回の実行時間と、1日に使える量に上限があります。Google Workspaceのアカウントと無料のGoogleアカウント(gmail.com など)で、1日あたりの量が違います。
| 項目 | 無料のGoogleアカウント | Google Workspaceのアカウント |
|---|---|---|
| 1回の実行時間 | 6分 | 6分 |
| カスタム関数の実行時間 | 30秒 | 30秒 |
| トリガーの合計実行時間 | 90分/日 | 6時間/日 |
| メールの宛先の数 | 100/日 | 1,500/日 |
| ドメイン内へのメールの宛先 | 100/日 | 2,000/日 |
| カレンダーの予定の作成 | 5,000/日 | 10,000/日 |
| ドキュメントの作成 | 250/日 | 1,500/日 |
| UrlFetchの呼び出し | 20,000/日 | 100,000/日 |
| 1人・1スクリプトあたりのトリガーの数 | 20 | 20 |
| 1人あたりの同時実行 | 30 | 30 |
1日の割り当ては人ごとにかかり、最初のリクエストから24時間でリセットされます。試用期間中のアカウントには、さらに別の制限がかかります。この表の数字は予告なく変わることがあるとGoogleが書いているので、本番の設計をするときは、割り当てのページを開いて今の数字を確かめます。
サンプル料理教室の規模なら、まず上限に当たることはありません。体験の申込が1日10件、確認メールを10通送っても、1,500通の上限には遠く届きません。上限に当たりやすいのは次の2つです。
1つ目は、1回の実行時間の6分です。会員100人分の請求書のPDFを1つのスクリプトで作って送ると、1人あたり数秒かかるだけで6分を超えます。超えると途中で止まり、何人目まで送ったか分からなくなります。10人ずつに分けて時間主導型のトリガーで続きから動かすか、送ったかどうかの列を台帳に持たせて、止まっても続きから再開できる形にします。
2つ目は、トリガーの合計実行時間です。1分おきに動くトリガーを何本も置くと、1日の合計に届くことがあります。1分おきに見張る必要がある処理はまれなので、5分や1時間の間隔で足りないか先に考えます。
上限に当たったときのエラーには、「サービスが呼び出された回数が多すぎます」(1日の割り当てを超えた)や「Service using too much computer time for one day.」(1日の実行時間を超えた)があります。止まったときの見方は「GASが止まったとき:エラー・実行時間・上限の見方」の記事にまとめています。
実行の記録を見る
エディタで手で実行したときは、画面の下の「実行ログ」に Logger.log や console.log で書いた内容が出ます。ただし、ここに出たログは長くは残りません。
トリガーで動いた分も含めた記録は、エディタの左側の「実行数」で見ます。いつ・どの関数が・どのトリガーで動き・成功したか失敗したかが並びます。失敗だけを見たいときは「フィルタを追加」→「ステータス」で「失敗」と「タイムアウト」にチェックを入れます。

本番で動かすスクリプトには、どこまで進んだかを console.log で書いておきます。止まったときに、何件目で止まったかが実行数の記録から追えます。
サンプル料理教室で、この先作るもの
このあとの記事では、サンプル料理教室の業務を1つずつGASに置き換えていきます。全体像は次のとおりです。
| 記事 | 作るもの | 置き場所 | 動かすきっかけ |
|---|---|---|---|
| GASのトリガー:定期実行・フォーム送信時・編集時 | 毎朝8時に今日の体験予約をChatに送る。フォームの回答を台帳に転記する | 予約一覧(コンテナバインド) | 時間主導型、フォーム送信時 |
| GASでメールを自動送信する:スプレッドシートの宛先に1通ずつ差し込む | 体験申込の確認メールと、会員へのお知らせの差し込みメール | 予約一覧・会員台帳 | フォーム送信時、メニューから手動 |
| GASでカレンダーに予定を自動登録する:予約の一覧からカレンダーへ | 確定した体験の予約をレッスンのカレンダーに入れる | 予約一覧 | 編集時(対応状況が「確定」になったら) |
| スプレッドシートで請求書を作り、PDFで送る:GASで月末をまとめる | 会員ごとの月謝の請求書PDFを作り、確認してから送る | 会員台帳 | メニューから手動、月末の時間主導型 |
| GASが止まったとき:エラー・実行時間・上限の見方 | 止まったときの見方と、分けて動かす作り方 | 全部 | — |
どれも、今回作った「シートを読んで、条件に合う行で何かする」の形の応用です。
応用:カスタム関数とWebアプリ
セルの中で使う自分の関数も作れます。月謝の税込の金額を出す関数なら、次のように書きます。
// 税込の金額を返す(セルで =TAX_INCLUDED(F2) のように使う)
function TAX_INCLUDED(price) {
return Math.round(price * 1.1);
}
保存すると、スプレッドシートのセルで =TAX_INCLUDED(F2) と書けます。カスタム関数の実行時間は30秒までで、メールを送ったり他のファイルを書き換えたりする処理には使えません。計算だけに使います。計算で済むことはふつうの関数で書けることが多いので、カスタム関数は「関数で書くと式が長くなりすぎるとき」に絞ります。
URLを開くと動くWebアプリも作れます。doGet か doPost という名前の関数を書き、エディタ右上の「デプロイ」→「新しいデプロイ」で種類に「ウェブアプリ」を選んで公開します。実行するユーザーを「自分」にすると、誰が開いてもスクリプトの持ち主の権限で動きます。外から開ける入り口になるので、会員の個人情報を返すようなWebアプリは作らないでおきます。講師の入力画面が欲しいなら、AppSheetのほうが早く、安全に作れます。
できないことと、その代わり
| やりたいこと | GASでは | 代わりの手 |
|---|---|---|
| 6分を超える処理を1回で動かす | 6分で止まる | 分けて動かす。量が多いならn8nやデータベースへ |
| 1分より細かい間隔で見張る | 時間主導型は最短でも分単位 | 外のサービスから呼ぶ。Webhookで受ける |
| LINE・kintone・会計ソフトなど外のサービスと何本もつなぐ | UrlFetchAppで書けるが、APIごとに認証とエラー処理を書くことになる | n8nに任せる |
| 止まったときに自動でやり直す | 自分で書かないと無い | 処理済みの印を台帳に持たせて、次の回に続きから動かす |
| スマホでコードを直す | エディタはパソコンのブラウザ向けで、スマホでは実用にならない | パソコンで直す |
| 誰が作ったか分からなくなるのを防ぐ | 管理の仕組みは無い | 作ったスクリプトの一覧を台帳にする。作るアカウントを決める |
n8nに任せる目安は、次のどれかに当てはまるときです。Googleの外のサービスと3つ以上つなぐ。止まったら自動でやり直してほしい。処理の流れを画面で見て、プログラムを書かない人にも直してほしい。1日に何千件も処理する。逆に、スプレッドシートの中で完結する処理や、Gmailで数十通を送るくらいの処理は、GASのほうが手軽で、別のサーバーも要りません。サンプル料理教室では、Googleの中の処理はGAS、問い合わせをLINEとChatに流すような外とつなぐ処理はn8n、と分けています。
よく詰まるところ
| 症状 | 原因 | 直し方 |
|---|---|---|
| 「拡張機能」に「Apps Script」が無い | 管理コンソールでGASがオフになっている。または個人のアカウントで開いている | 管理者に「Google Apps Script」の設定を確認してもらう。会社のアカウントに切り替える |
実行すると TypeError: Cannot read properties of null が出る | getSheetByName のシート名がタブの名前と違い、シートが見つからない | シート名を1文字ずつ見比べる。前後の空白も確かめる |
| 実行ボタンを押しても何も起きない | 関数の選択欄で別の関数(onOpen など)が選ばれている | 選択欄で目的の関数を選び直す |
| 「このアプリは Google で確認されていません」で止まる | 機密性の高い権限を使う、審査を受けていないスクリプト | 社内で書いたものなら進める。知らないものは進めない |
| トリガーで動かすと「その操作を実行するには承認が必要です。」 | 新しいサービスを足したあと、承認をやり直していない | エディタで関数を1回手で実行し、承認する |
| 「アクセスが拒否されました: DriveApp」 | 管理者がドライブのAPIを止めている | 管理者に確認する |
| 外のURLを呼ぶと「管理者により許可されていません」 | 管理コンソールで外部へのアクセスが許可リストで絞られている | 管理者に、呼ぶURLを許可リストに足してもらう |
| 日付が英語の長い文字や、9時間ずれた時刻でメールに出る | 日付をそのまま文字にしている。タイムゾーンが合っていない | Utilities.formatDate(d, 'Asia/Tokyo', 'M/d HH:mm') で文字にする。プロジェクトの設定のタイムゾーンを東京にする |
| 途中で止まり「実行時間の上限」に関するエラーが出る | 1回の実行が6分を超えた | 処理を分け、処理済みの印を台帳に付けて続きから動かす |
| 台帳をコピーしたら同じスクリプトが2つになった | コンテナバインドのスクリプトはファイルと一緒にコピーされる | 古いほうのファイルのスクリプトを使わない。コピーで月を分ける運用をやめる |
| メニューの「教室メニュー」が出ない | onOpen を保存していない、またはファイルを開き直していない | 保存してからスプレッドシートを再読み込みする |
| 実行ログが前の分しか残っていない | エディタの実行ログは長く保持されない | 「実行数」で過去の実行を見る |
TypeError の行の「null」は、本番の環境でいちばん多いエラーです。受付がシートのタブ名を「予約一覧(新)」に変えた日から、確認メールが全部止まっていた、ということが実際に起きます。シート名を変えるとスクリプトが止まることを、台帳を触る人全員に伝えておくか、シート名ではなくシートのIDで開く書き方にしておきます。
次にやること
- GASのトリガー:定期実行・フォーム送信時・編集時
- GASでメールを自動送信する:スプレッドシートの宛先に1通ずつ差し込む
- GASが止まったとき:エラー・実行時間・上限の見方
- Google Workspaceとn8nをつなぐ:フォーム・Gmail・スプレッドシートを外へ流す