今までの記事一覧
- GASでGoogleForm回答を取得するなら lastRow?(e)?試してみた
- onFormSubmit(e)を手動実行でデバッグする方法
- どっちを使う?onFormSubmit(e)の values と namedValues の違いと使い分け
- onFormSubmit(e) の e.values 配列順のしくみ
- Googleフォームで質問を変えても壊れない!cleanFormData(e)でnamedValues防御力をアップ
- Googleフォームの質問変更に負けない!「部分一致」と「秘密の暗号」でcleanFormData(e)の防御力を鉄壁に
- 手動コピペはもう卒業!Googleフォームの回答別に処理を自動仕分け <この記事
- Googleフォームで同時に大量送信されても踏ん張る!LockServiceで順番制御!try - catch - finally でバトンを繋げ!
- LockServiceでは順番は守れない?受付番号で順序を保証する方法
前提
この記事は、フォーム回答を保存している スプレッドシート側のGAS を前提にしています。
トリガーは以下を設定しています。
- スプレッドシートから
- フォーム送信時
おさらい
前回はフォームの質問文に暗号を仕込むことで、質問文を変更してもGASコードを変えることなく回答を取得できるようにしました。
でも、実際の仕事、ログを取っておしまい…ではないですよね?
実際は回答内容によっていろいろな処理をしなきゃいけないはず。
今回は、前回手に入れた「最強のデータ取得法」を使って、届いた瞬間に適切な部署のシートへ自動で放り込む 「自動仕分け機」 を作りましょう。
手動でコピペはもう卒業です!
今回のタスク
- 「問い合わせ先」に応じて、対応するシートへ転記する
スプレッドシートには、フォーム内容が自動で入る「フォームの回答」シートのほかに
「総務部シート」「経理部シート」「営業部シート」「製造部シート」「その他のシート」があります。

ユーティリティ関数 cleanFormData(e)
では前回同様、ユーティリティ関数を作ります。
質問文の暗号は|name|等を使いましょう。
function cleanFormData(e) {
const namedValues = e.namedValues;
const data = {};
// 全ての質問項目をループ
for (let key in namedValues) {
const value = namedValues[key][0];
// もし質問の中に|mail|が入ってたら、一律で mail に入れる
if (key.includes("|mail|")) {
data.mail = value;
// もし|name|が入ってたら name に入れる
} else if (key.includes("|name|")) {
data.name = value;
// もし|dept|が入ってたら dept に入れる
} else if (key.includes("|dept|")) {
data.dept = value;
// もし|inq|が入ってたら inq に入れる
} else if (key.includes("|inq|")) {
data.inq = value;
}
// 質問文そのままでも呼び出せるように保存
data[key] = value;
}
return data;
}
これで「メールアドレス」「お名前」「問い合わせ先」「問い合わせ内容」に
それぞれ「mail」「name」「dept」「inq」というニックネームが付きました。
ニックネームが付いていないものは質問文そのもので呼び出せます。
メイン関数 onFormSubmit(e)
ここからはメイン関数です。
function onFormSubmit(e) {
// ユーティリティ関数 cleanFormData でフォームからのデータを整形
const formData = cleanFormData(e);
// 日付データ(スプレッドシート書き込み用)
const timestamp = new Date(formData["タイムスタンプ"]);
// 振り分け先のシートを決める
let targetSheetName = "その他のシート"; // デフォルト(見つからない時用)
// 問い合わせ先部署によってシートをかえる分岐処理
if (formData.dept == "総務部"){
targetSheetName = "総務部シート";
} else if (formData.dept == "経理部"){
targetSheetName = "経理部シート";
} else if (formData.dept == "営業部"){
targetSheetName = "営業部シート";
} else if (formData.dept == "製造部"){
targetSheetName = "製造部シート";
}
// スプレッドシートへの書き込み
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(targetSheetName);
if (sheet){
sheet.appendRow([timestamp,formData.mail,formData.name,formData.inq]);
// シート名が見つからなかったらログを出す
} else {
Logger.log("エラー:シート「" + targetSheetName + "」が見つかりませんでした。");
}
}
ユーティリティ関数で整形されたデータが変数formDataに入ります。
formData.deptに問い合わせ先が入っているので、その内容によってif文を使って条件分岐し
書き込み先のシート名を決めていきます。
万が一、フォーム作成担当者が勝手に「社長室」なんてのを追加した場合に備えて、
「総務部」「経理部」「営業部」「製造部」以外の回答がきたら「その他のシート」に行くように
let targetSheetName = "その他のシート"; これを入れておきましょう。
あとはスプレッドシートに書き込むだけ。
sheet.appendRow は、指定したシートの最終行に1行追加するメソッドです。
timestamp フォームのタイムスタンプ ※注
formData.mail フォームの「メールアドレス」
formData.name フォームの「お名前」
formData.inq フォームの「問い合わせ内容」
これらを[ ]の中に入れてappendRowに渡します。
ここでも万が一、誰かがシート名を変えてしまったときにエラーで止まらないように、
} else {
Logger.log("エラー:シート「" + targetSheetName + "」が見つかりませんでした。");
}
でログを残しておくと安心です。
※注 "タイムスタンプ"は環境によって"Timestamp"になっていることがあります。
もし実行してみて日付がうまく取得できない場合は、スプレッドシートの「フォームの回答」シートの1行目を確認してください。
では、実験してみましょう。
一瞬で転記されました!
これで手動コピペから卒業です。
おまけ1:手動デバッグ方法
全パターンの振り分けをテストするために、何度もフォーム画面から送信するのは面倒なので、以下のダミーデータを使ったテスト用関数を使うのもアリです。
エディタでtest_onFormSubmitを選択して実行すると、このnamedValuesの内容でonFormSubmit(e)が走ります。
function test_onFormSubmit() {
const dummyEvent = {
namedValues: {
"メールアドレス|mail|": ["abc@mail.com"],
"お名前|name|": ["ほげ山 ほげ太郎"],
"問い合わせ先|dept|": ["総務部"], // ここを書き換えて各シートへ飛ぶかテスト!
"問い合わせ内容|inq|": ["テスト問い合わせ"],
"タイムスタンプ": ["2026/03/01 12:00:00"]
}
};
onFormSubmit(dummyEvent);
}
おまけ2:if文をスッキリ書く方法(上級編)
if文が増えてくるとコードが長くなるため、実務ではこんなふうに対応表(オブジェクト)で書く方法もあります。
- 元のコード
let targetSheetName = "その他のシート"; // デフォルト(見つからない時用)
if (formData.dept == "総務部"){
targetSheetName = "総務部シート";
} else if (formData.dept == "経理部"){
targetSheetName = "経理部シート";
} else if (formData.dept == "営業部"){
targetSheetName = "営業部シート";
} else if (formData.dept == "製造部"){
targetSheetName = "製造部シート";
}
- オブジェクト化したコード
const sheetMap = {
"総務部": "総務部シート",
"経理部": "経理部シート",
"営業部": "営業部シート",
"製造部": "製造部シート"
};
const targetSheetName = sheetMap[formData.dept] || "その他のシート";
慣れてきたら、こちらの書き方もぜひ試してみてください。
応用:担当ごとにメールする
今回はシートに記入するだけでしたが、例えばこんなふうにメールアドレスを入れると
function onFormSubmit(e) {
// ユーティリティ関数 cleanFormData でフォームからのデータを整形
const formData = cleanFormData(e);
// 日付データ(スプレッドシート書き込み用)
const timestamp = new Date(formData["タイムスタンプ"]);
// 振り分け先のシートを決める
let targetSheetName = "その他のシート"; // デフォルト(見つからない時用)
// メールアドレス
let mailAddress = "my_mail@mail.com";// ★ここを追加
// 問い合わせ先部署によってシートを換える分岐処理
if (formData.dept == "総務部"){
targetSheetName = "総務部シート";
mailAddress = "soumu@mail.com";// ★ここを追加
} else if (formData.dept == "経理部"){
targetSheetName = "経理部シート";
mailAddress = "keiri@mail.com";// ★ここを追加
} else if (formData.dept == "営業部"){
targetSheetName = "営業部シート";
mailAddress = "eigyo@mail.com";// ★ここを追加
} else if (formData.dept == "製造部"){
targetSheetName = "製造部シート";
mailAddress = "seizo@mail.com";// ★ここを追加
}
// 日付データを 2026/04/01 12:25:36 等の形式にする
const formattedDate = Utilities.formatDate(timestamp, "JST", "yyyy/MM/dd HH:mm:ss");
// メール本文
const mailbody = `
ご担当者様
以下のとおりフォームで問い合わせがありました。
日時:${formattedDate}
氏名:${formData.name}
メール:${formData.mail}
担当部署:${formData.dept}
質問内容:${formData.inq}
`
GmailApp.sendEmail(mailAddress,"問い合わせ内容",mailbody);
//以下略
それぞれの部署あてにメールを送信することもできます。
まとめ
今回はフォームで届いた回答を、内容に応じて処理分岐し、スプレッドシートへの転記や担当者へメールする 「自動仕分け機」 を作りました。
ところが、この便利な仕分け機にも一つだけ弱点が。
もし、イベントの申し込みなどで 「全く同じ瞬間に2人が送信ボタンを押したら」 どうなるでしょう?
そんなわけで、次回はLockServiceを使って同時実行対策をしましょう。


