Guides the user through building a Google Form in the Forms UI and connecting it to Google Apps Script triggers, without writing a custom integration or leaving the browser. Covers form design, the Apps Script editor, the onFormSubmit trigger, and small response-handling scripts that run automatically when a form is submitted.
Create the form in Google Forms with clear questions, answer types (short answer, multiple choice, checkbox), and required fields. Match question IDs to what the script will need later. Add a description to the form so respondents know what to expect.
In the form, go to Extensions > Apps Script. This opens a project bound to the form. The script can read each submission through the e.response event object.
Add a function that accepts the onFormSubmit event, reads e.response with getItemResponses(), and then performs the desired action: send an email, write to a spreadsheet, or branch on answers.
In Apps Script, go to the clock/triggers menu, select the onFormSubmit function, choose the event source From form and event type On form submit, then save and authorize. The function runs automatically on each new submission.
Submit a test response from a private/incognito window and verify the email, sheet row, or log arrives once. Check the Apps Script executions page (Executions in the editor) for errors and read the stack trace if something fails.
function onFormSubmit(e) {
const response = e.response;
const email = getEmail(response);
MailApp.sendEmail({
to: email,
subject: "Form submission received",
body: "Thank you. We have recorded your response."
});
}
function getEmail(response) {
// Requires Forms' VERIFIED email collection, not an email question or responder input.
const form = FormApp.getActiveForm();
if (!form.collectsEmail()) throw new Error("Verified email collection is required");
// Configure the form to Verified in the UI; Apps Script's boolean alone does not prove it.
if (PropertiesService.getScriptProperties().getProperty("VERIFIED_EMAIL_COLLECTION_APPROVED") !== "yes") {
throw new Error("Owner must verify and approve the form's email-collection mode");
}
const email = response.getRespondentEmail();
if (!email || !/^[^\s,@]+@[^\s,@]+\.[^\s,@]+$/.test(email)) throw new Error("Missing verified recipient");
// Limit one receipt per verified address per six hours under an atomic script lock.
const lock = LockService.getScriptLock();
lock.waitLock(5000);
try {
const cache = CacheService.getScriptCache();
if (cache.get(email)) throw new Error("Receipt already sent");
if (MailApp.getRemainingDailyQuota() < 20) throw new Error("Mail quota reserve reached");
cache.put(email, "sent", 21600);
} finally { lock.releaseLock(); }
return email;
}
function onFormSubmit(e) {
const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName("Responses");
const itemResponses = e.response.getItemResponses();
const asText = value => {
const text = Array.isArray(value) ? value.join(", ") : String(value ?? "");
return /^[\s\u0000-\u001f]*[=+@-]/.test(text) ? "'" + text : text;
};
const row = [new Date()].concat(itemResponses.map(r => asText(r.getResponse())));
sheet.appendRow(row);
}
This fragment requires an approved fixed MANAGER_EMAIL and an itemResponsesText helper that includes only permitted non-sensitive fields. Trigger installation authorizes recurring sends and needs that explicit scope; no helper is bundled.
function onFormSubmit(e) {
const items = e.response.getItemResponses();
for (const item of items) {
if (item.getItem().getTitle().toLowerCase() === "priority") {
const priority = item.getResponse();
const subject = priority === "High" ? "[URGENT] " : "";
MailApp.sendEmail({ to: MANAGER_EMAIL, subject: subject + "New submission", body: itemResponsesText(e) });
}
}
}
Logger.log so failures surface in the Executions page.onFormSubmit by default.Solution: Prefer the single event object e.response; do not separately query the form's stored responses inside onFormSubmit.
item.getResponse() returns undefined for optional questions.Solution: Guard with a check for a truthy response, or make the question required.
Solution: Use verified respondent-email collection and the approved recipient policy; do not send to arbitrary addresses entered in a question.
@google-sheets-automation - Use when the response logging target is a Sheet that needs its own automation.@google-docs-automation - Use when form output should create or update a Google Doc.