The default notification setting in Google Forms tells you that someone submitted a response, but it forces you to open a spreadsheet to see what they actually said.

Writing a few lines of Google Apps Script changes that dynamic entirely by sending the exact answers directly to your inbox.

By connecting a custom script directly to your form, you can instantly route specific data to the right people, formatted exactly how you want to read it.

What are the prerequisites for automating Google Form emails?

Before writing any code, you need the right foundation in place.

  • A finalized Google Form - Your script will rely on the exact questions currently in your form. Changing a multiple-choice question to a checkbox later will change how the script reads the data array, which often breaks the email output.

  • Form-bound vs Sheet-bound architecture - This guide focuses on a container-bound script attached directly to the Google Form, rather than the destination spreadsheet. This method is faster, does not require a connected spreadsheet, and handles empty answers more gracefully.

  • Clear recipient logic - Decide whether you are sending emails to a fixed internal team, a dynamic list based on the form answers, or back to the submitter as a receipt.

  • A Google Workspace or standard Google account - Both account types can run Apps Script, but they carry different daily sending limits and security restrictions.

If you are migrating an older process and need to digitize your questions first, you can turn a PDF intake form into a Google Form before attaching any custom automation.

How to open and prepare the Apps Script editor

Google Apps Script lives directly inside your Google Form environment.

You do not need to install secondary software or configure a local development environment to write your automation.

  1. Open your Google Form in edit mode.

  2. Click the three vertical dots (More) in the top right corner of the screen, next to your profile picture and the Send button.

  3. Select Script editor from the dropdown menu.

  4. A new browser tab will open displaying the Apps Script interface.

  5. Click the default project title (Untitled project) in the top left and rename it to something recognizable, like Intake Form Email Routing.

If you are starting entirely from scratch and need a complex layout built quickly, you can generate a Google Form from a description to get your structure ready for the script editor.

When the editor opens, it will display a default, empty function named myFunction().

Delete this empty function entirely before proceeding to the next step so your workspace is clean.

Writing the script to extract form responses and send emails

The code needs to capture the incoming submission, unpack the specific answers, format them into a readable message, and pass that payload to Google's email service.

Because this script is bound directly to the form, we will use the e.response object to access the submitted data safely.

Copy and paste the following JavaScript into your empty editor:

function onFormSubmit(e) {
  // 1. Define the recipient and subject
  var emailRecipient = "[email protected]";
  var emailSubject = "New Form Submission Received";
  
  // 2. Get the specific response object from the event
  var formResponse = e.response;
  var itemResponses = formResponse.getItemResponses();
  
  // 3. Start building the plain text email body
  var emailBody = "A new submission has been received.\n\n";
  emailBody += "Here are the details:\n\n";
  
  // 4. Loop through every question in the form
  for (var i = 0; i < itemResponses.length; i++) {
    var itemResponse = itemResponses[i];
    var questionTitle = itemResponse.getItem().getTitle();
    var answer = itemResponse.getResponse();
    
    // Handle array outputs for checkbox questions
    if (Array.isArray(answer)) {
      answer = answer.join(", ");
    }
    
    // Add the question and answer to the email body
    emailBody += questionTitle + ": \n" + answer + "\n\n";
  }
  
  // 5. Append a timestamp
  var timeStamp = formResponse.getTimestamp();
  emailBody += "Submitted on: " + timeStamp + "\n";
  
  // 6. Send the email via MailApp
  MailApp.sendEmail({
    to: emailRecipient,
    subject: emailSubject,
    body: emailBody
  });
}

This script relies on the event object, represented by the letter e in the function parameters.

When the form is submitted, Google automatically passes this event object to your function in the background.

By relying on the event object rather than querying the form manually, your script processes the exact submission that triggered it, which eliminates race conditions if two people submit the form at the exact same second.

The getItemResponses() method is particularly useful because it completely ignores any blank answers.

If a user skips an optional question, that question simply will not appear in the final email, keeping your notifications clean.

For checkbox questions, the script receives an array of answers rather than a single text string.

The Array.isArray(answer) check ensures that multiple selections are joined together cleanly with commas, preventing the email output from looking like raw, unformatted code.

Google provides two different services for sending emails: MailApp and GmailApp.

For a form submission trigger, MailApp is almost always the better choice.

Using MailApp keeps the required authorization scopes strictly limited to sending messages on your behalf.

If you use GmailApp, the security warning will tell users that the script wants permission to "Read, compose, send, and permanently delete all your email from Gmail," which often causes internal IT departments to block the script entirely.

A static subject line makes it impossible to search for specific submissions in your inbox.

Instead of a generic title, append dynamic data to the subject variable to keep your inbox organized.

Subject line formatting

  • ❌ Weak: var emailSubject = "New Form Submission";

  • ✅ Strong: var emailSubject = "New Intake Form: " + clientName;

Why it works: Appending a unique identifier ensures that Gmail threads each submission separately rather than grouping them into one massive, unreadable conversation.

Handling file upload questions

If your form includes a file upload field, the standard script will output an unhelpful string of letters and numbers representing the Google Drive file ID.

You can intercept file upload questions during the loop and convert those IDs into clickable links.

Replace the loop in the basic script with this upgraded version to handle files automatically:

  for (var i = 0; i < itemResponses.length; i++) {
    var itemResponse = itemResponses[i];
    var questionTitle = itemResponse.getItem().getTitle();
    var answer = itemResponse.getResponse();
    
    // Handle array outputs for checkbox questions
    if (Array.isArray(answer) && itemResponse.getItem().getType() !== FormApp.ItemType.FILE_UPLOAD) {
      answer = answer.join(", ");
    }
    
    // Handle file upload questions by generating Drive links
    if (itemResponse.getItem().getType() === FormApp.ItemType.FILE_UPLOAD) {
      var fileIds = itemResponse.getResponse();
      var fileLinks = [];
      for (var f = 0; f < fileIds.length; f++) {
        fileLinks.push("https://drive.google.com/file/d/" + fileIds[f] + "/view");
      }
      answer = fileLinks.join("\n");
    }
    
    emailBody += questionTitle + ": \n" + answer + "\n\n";
  }

Upgrading to HTML emails

Plain text emails are functional, but they can be difficult to read when a form contains dozens of questions or long paragraph answers.

You can upgrade your script to send rich formatting by swapping body for htmlBody in the final MailApp.sendEmail payload.

Using HTML allows you to bold question titles, insert hard line breaks, and structure the data in clean tables.

  // Example: Building an HTML email payload
  var htmlContent = "<h2>New Submission Details</h2>";
  htmlContent += "<ul>";
  
  for (var i = 0; i < itemResponses.length; i++) {
    var title = itemResponses[i].getItem().getTitle();
    var ans = itemResponses[i].getResponse();
    
    htmlContent += "<li><strong>" + title + ":</strong> " + ans + "</li>";
  }
  
  htmlContent += "</ul>";
  
  MailApp.sendEmail({
    to: emailRecipient,
    subject: emailSubject,
    htmlBody: htmlContent
  });

Routing emails conditionally

If your form covers multiple departments or services, routing every submission to a single inbox creates an immediate bottleneck.

You can isolate the value of a specific question and use a simple if statement to change the destination address dynamically.

  // Example: Routing based on a dropdown question named "Department"
  var emailRecipient = "[email protected]";
  
  if (questionTitle === "Department") {
    if (answer === "Sales") {
      emailRecipient = "[email protected]";
    } else if (answer === "Support") {
      emailRecipient = "[email protected]";
    }
  }

How to configure the installable form submit trigger

Pasting the code into the editor does not make it run automatically.

You must explicitly tell Google to execute this specific function whenever a new submission occurs by creating an installable trigger.

  1. In the Apps Script editor, look at the left-hand sidebar and click the Triggers icon, which looks like a small alarm clock.

  2. Click the blue + Add Trigger button in the bottom right corner of the screen.

  3. In the "Choose which function to run" dropdown, select onFormSubmit.

  4. In the "Select event source" dropdown, ensure From form is selected.

  5. In the "Select event type" dropdown, choose On form submit.

  6. Under "Failure notification settings", change the dropdown from Notify me daily to Notify me immediately so you know exactly when a script fails.

  7. Click Save.

A Google security popup will immediately appear asking you to authorize the script.

Because you wrote this custom script yourself, Google flags it as an unverified application to ensure you know what code is running on your account.

Click your Google account email address in the popup window.

Click the small Advanced link at the bottom of the warning screen.

Click the link that says Go to Intake Form Email Routing (unsafe).

Click Allow to grant the script permission to read your form responses and send emails on your behalf.

Your trigger is now active and will run quietly in the background every time a user hits the submit button.

Expert tip: When testing your script, do not use your real email address for both the submission and the destination if you have Gmail's conversation grouping turned on. Gmail often hides automated messages sent to yourself in existing threads, making it look like the script failed when it actually succeeded.

Troubleshooting common Google Forms script execution errors

Even with clean code, automated emails can fail due to environmental issues, revoked permissions, or mismatched configurations.

When a script fails, Google sends an automated failure notification to your email address containing a specific error message.

Error Message Root Cause Resolution
TypeError: Cannot read property 'response' of undefined You clicked the Run button manually in the editor. The event object (e) only exists when triggered by an actual form submission. Submit a real test response through your live Google Form instead of running the script manually.
Exception: The parameters (String,String,String) don't match the method signature for MailApp.sendEmail. One of your email parameters (like the recipient address or the body text) is null, undefined, or formatted incorrectly. Verify that the emailRecipient variable contains a valid, quoted email address string and is not blank.
Authorization Required The script's permissions have been revoked, or you added new services to the code after the initial authorization. Open the script editor, run the function manually once to force the authorization popup to appear, and accept the new permissions.
Service invoked too many times for one day: email. You have exceeded your account's daily email sending limit for Apps Script. Wait 24 hours for the quota to reset, or upgrade to a Google Workspace account for higher limits.
Exception: Invalid email: null The script is trying to send an email to a blank address. This often happens if you pull the recipient address from a form field that the user skipped. Make the email field mandatory on your Google Form, or add a hardcoded fallback email address in your script.

Understanding Google execution limits and script security

Google does not offer unlimited processing power or email sending capabilities.

Apps Script operates within strict daily quotas designed to prevent spam and system abuse.

  • Consumer daily email limits - Free standard Google accounts (ending in @gmail.com) can send a maximum of 100 automated emails per 24-hour period.

  • Workspace daily email limits - Paid Google Workspace accounts have a significantly higher threshold, allowing up to 1,500 automated emails per day.

  • Trigger execution time - A single run of your script cannot exceed six minutes. Extracting text and sending an email usually takes less than two seconds, so this limit rarely impacts basic notifications.

  • Total trigger runtime - You are allotted a maximum of 90 minutes of total trigger execution time per day on a consumer account, and 6 hours on a Workspace account.

  • OAuth scopes and authority - Your script runs entirely under the authority of the account that created the trigger. If you share the form with a colleague or publish it publicly, the automated emails will still be sent from your email address, not the submitter's.

To track how close you are to your limits, you can view the execution logs directly in the Apps Script dashboard by clicking the Executions icon on the left sidebar.

FAQ

Can I send custom HTML-formatted emails instead of plain text?

Yes. You can pass an htmlBody parameter to the MailApp.sendEmail() method instead of the standard body parameter. This allows you to use standard HTML tags like <strong>, <br>, and <table> to structure the outgoing message. Just ensure your variables are concatenated correctly within the HTML strings before passing them to the mail service.

Why does my trigger fail with an 'Authorization Required' error?

This happens when the script attempts to use a Google service that you have not explicitly granted it permission to access. If you write the code to send an email, but then later add code to save a file to Google Drive, the script will halt. You must run the function manually from the editor one time to trigger the new consent screen and approve the added scopes.

What is the daily email quota for Google Apps Script?

Standard consumer accounts ending in @gmail.com are limited to sending 100 automated emails per 24-hour cycle. Paid Google Workspace accounts have a much larger allowance, permitting up to 1,500 emails per day. If you exceed this limit, the trigger will fail completely until the quota resets the following day.

Can I send different email notifications based on specific form answers?

Yes. You can intercept the answer to a specific question during the script's loop and use an if or switch statement to change the recipient variable dynamically. For example, if the user selects "Billing" from a dropdown, the script can reassign the target email address from a general inbox to your finance team's address before calling the send method.

Building the script to route your answers is usually the easy part; mapping out the logic for a massive, multi-page intake process is where teams actually get bogged down. If you have an existing document that needs to be digitized before you can even think about automation, a tool like Doc2Form can convert your layout directly into a Google Form. Once the structure is live, attach your new Apps Script trigger and let the data flow directly to your inbox.