経費申請や休暇申請をGoogleフォームで受け付けているものの、承認は上長への口頭確認やチャットの「OK」だけで済ませている場合、いつ誰が承認したのかが後から追えなくなります。
この記事では、Google Apps Scriptでフォーム申請に承認フローを付け、承認依頼メールの送信から承認記録の保存まで自動化する仕組みをまとめました。
完成イメージと仕組み
完成すると、フォームが送信された瞬間に申請内容がスプレッドシートへ記録され、同時に承認者へ承認依頼メールが届きます。
承認者がすることは、メールに並ぶ承認と却下のリンクのどちらかをクリックするだけです。
クリックされた瞬間に、リンク先のWebアプリが対象の申請行へ承認状況と日時を書き込むため、誰がいつ承認したかがスプレッドシート上に残ります。
似たような形で申請から通知までをまとめて設計したい場合は、モデルケースも参考になります。
この仕組みが向いているのは、承認の分岐が「通す」か「差し戻す」かの1段階だけで済む申請です。
金額に応じて承認者を変えたい、複数人の承認を順番に通したいといった多段階のフローになると、条件分岐の実装量が一気に増えます。
| 申請フローの複雑さ | 向いている作り方 |
|---|---|
| 承認者1人・承認か却下かの1段階 | この記事のGoogle Apps Script構成 |
| 金額に応じて承認者が異なる、複数人が順番に承認する | Power Automateの承認機能(後述) |
手順
フォームの準備からトリガー設定までは、大きく4つのステップです。
Step1. フォームとスプレッドシートを用意する
Googleフォームで申請フォームを作り、質問に氏名と申請内容の項目を入れます。
回答をスプレッドシートに送るよう設定すると、A列に送信日時、B列に氏名、C列に申請内容が自動で並ぶシートができます。
続けて、このシートのD列を「申請ID」、E列を「承認状況」、F列を「承認日時」の見出しにしておきましょう。
Step2. コードを貼り付ける(コード全文)
スプレッドシートのメニューから拡張機能を開き、Apps Scriptを選んでスクリプトエディタを開きます。
表示されているコードを全て消し、次のコードをまるごと貼り付けてください。
function onFormSubmitSendApprovalRequest(e) {
const sheetName = '申請一覧'; // ★ここを変える: フォーム回答先シート名
const managerEmail = 'manager@example.com'; // ★ここを変える: 承認者のメールアドレス
const webAppUrl = 'https://script.google.com/macros/s/xxxxx/exec'; // ★ここを変える: Step4でデプロイしたWebアプリのURL
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const lastRow = sheet.getLastRow();
const applicantName = sheet.getRange(lastRow, 2).getValue();
const requestContent = sheet.getRange(lastRow, 3).getValue();
const applicationId = lastRow;
sheet.getRange(lastRow, 4).setValue(applicationId);
sheet.getRange(lastRow, 5).setValue('未承認');
const approveUrl = `${webAppUrl}?id=${applicationId}&action=approve`;
const rejectUrl = `${webAppUrl}?id=${applicationId}&action=reject`;
const body = [
`${applicantName}さんから申請が届きました。`,
'',
`内容: ${requestContent}`,
'',
`承認する場合はこちら: ${approveUrl}`,
`却下する場合はこちら: ${rejectUrl}`,
].join('\n');
MailApp.sendEmail(managerEmail, '【承認依頼】新しい申請が届きました', body);
}
function doGet(e) {
const sheetName = '申請一覧';
const targetRow = Number(e.parameter.id);
const action = e.parameter.action;
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const statusLabel = action === 'approve' ? '承認済み' : '却下';
sheet.getRange(targetRow, 5).setValue(statusLabel);
sheet.getRange(targetRow, 6).setValue(new Date());
return ContentService.createTextOutput(`申請ID ${targetRow} を${statusLabel}にしました。`);
} onFormSubmitSendApprovalRequest が送信直後の行から氏名と申請内容を読み取り、行番号をそのまま申請IDとして使って承認依頼メールを送ります。
doGet はWebアプリとして公開したときに、リンクがクリックされるたびに呼ばれる関数です。
URLに含まれる id と action を受け取り、該当する行の承認状況と承認日時を書き込みます。
Step3. onFormSubmitトリガーを設定する
スクリプトエディタ左側の時計マーク「トリガー」を開き、右下の「トリガーを追加」を押します。
実行する関数にonFormSubmitSendApprovalRequest、イベントのソースにスプレッドシート、イベントの種類にフォーム送信時を選んで保存すれば設定は完了です。
以降はフォームが送信されるたびに、この関数が自動で実行されます。
Step4. Webアプリとして公開する
スクリプトエディタ右上の「デプロイ」から「新しいデプロイ」を選び、種類でWebアプリを選択します。
このとき「次のユーザーとして実行」は「自分」のままで問題ありません。
承認リンクをクリックした承認者ではなくアカウント所有者の権限でスクリプトが動くため、承認者にシートの編集権限がなくても承認状況を書き込めるからです。
「アクセスできるユーザー」を「全員」にしないと承認者がリンクを開けないので、社内の運用ポリシーに沿った公開範囲かどうかを確認してから選んでください。
なお、この承認リンクには認証の仕組みがなく、URLの id の数字を書き換えれば別の申請行も承認・却下できてしまいます。
公開範囲を「全員」にするとURLを知っている人なら社外からでも操作できるため、承認者が同じ組織のGoogleアカウントを持っているなら公開範囲を組織内に絞り、承認依頼メールの転送範囲にも気をつけてください。
デプロイが完了するとWebアプリのURLが発行されるので、そのURLをStep2のコード内 webAppUrl に貼り付けて再度保存すれば、承認リンクが正しく動きます。
Googleフォームでどんな申請から自動化を始めるべきか迷う場合は、着手順の考え方を別記事で整理しています。

Power Automateとの使い分け
ここまでの仕組みはGoogle Workspace環境が前提です。
Microsoft 365環境なら、同じ承認の記録をPower Automateの承認機能で標準的に実現できます。
Power Automateには「承認」というアクションが用意されていて、承認依頼の通知から承認者の操作画面、承認履歴の保存までがノーコードで完結します。
そのため、Microsoft 365を使っている会社がこの記事のようなコードを書く必要は基本的にありません。
逆にGoogle Workspace環境では、フォームの承認を標準機能だけで完結させる手段がなく、この記事のようなGoogle Apps Scriptによる組み立てが現実的な選択肢になります。
承認フローを検討するときは、まず自社がどちらの環境かを確認してください。
Power Automateでの具体的な作り方は、多段階承認まで含めて別記事にまとめています。

Google Apps Scriptでの承認フロー構築について相談してみませんか?
「承認の分岐が複雑で今回の構成では対応できない」「承認履歴をもっと見やすく整理したい」「社内にGoogle Apps Scriptを設計できる人材がいない」
少しでもお心当たりがあれば、お気軽にご相談ください。
現在、Google Apps Scriptを使った業務自動化のお悩みをお伺いする 無料の個別相談 を実施しています。
よくある質問
Q. 承認者が複数人いる場合はどうすればいいですか?
このコードは承認者1人を前提にした最小構成です。
複数人の承認を順番に通したい場合は、承認状況の列を承認者ごとに分けて持ち、全員分が「承認済み」になったタイミングで次の処理に進む条件を追加する必要があります。
Q. 承認リンクを誤って2回クリックしてしまったらどうなりますか?
現在のコードは対象行の承認状況を上書きするだけなので、2回クリックしても承認日時が最後にクリックした時刻に更新されるだけで、記録が壊れることはありません。
ただし却下の後に承認を上書きできてしまう点が気になる場合は、doGet の冒頭でE列が既に「未承認」以外なら処理を打ち切るガード条件を追加してください。
Q. 申請者にも承認結果を通知したいです。
doGet の中で承認状況を書き込んだ直後に、その行の申請者のメールアドレスを取得して MailApp.sendEmail() を呼び出せば通知できます。
申請フォームにメールアドレスの質問項目を追加し、B列やC列と同じように取得する処理を足す形になります。
Q. WebアプリのURLは一度発行したら変わりませんか?
同じデプロイを「デプロイを管理」から編集して再公開する場合はURLが変わりません。
一方で「新しいデプロイ」として新規に作り直すと別のURLが発行されるため、コード修正のたびに新規デプロイを選ばないよう注意してください。