Google Forms Automated Emails - google-apps-script

I am using a Google Form and collecting the responses on a Sheet. I require notification emails be sent out to different teams depending on one of the responses on the Form. For example the form has the question, which Province are you in, if its AB then I need the AB team to get an email notification, if its the BC team I need only that team to be notified.
I have tried to use the Sheet (Responses) and build scripts off there by using Importrange function to create seperate sheets for each Province but that has not worked out so far. I am currently trying to see if I can just create the scripts in the Form itself and not have to worry about the sheets and just use one sheet.
var form = FormApp.getActiveForm();
var formResponses = form.getResponses();
for (var i = 0; i < formResponses.length; i++) {
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
for (var j = 0; j < itemResponses.length; j++) {
var itemResponse = itemResponses[j];
Logger.log('Response #%s to the question "%s" was "%s"',
(i + 1).toString(),
itemResponse.getItem().getTitle(),
itemResponse.getResponse());
}
}
/**
* Sends emails when form updated by end user, split responses by Province, send emails to team specified for each Province only.
*/
function sendEmails() {
var emailAddress = "example#example.com"; // First column
var message = itemResponse; // Response
var subject = 'Survey Updated';
MailApp.sendEmail(emailAddress, subject, message);
}
Currently the code above will send me an email once the form is submitted, I cannot figure out how to filter by Province or email a specific team based on the Province response. I also would like the details from each response to be in the body of the email so the teams do not have to open the spreadsheet.

Edit your sendEmails() function to grab the latest form response and search the item responses for the province:
function onSubmit(e) {
var responses = FormApp.getActiveForm().getResponses();
var response = responses[responses.length - 1].getItemResponses();
var provinceQuestionNumber = 4 // which question is the province question?
var province = response[provinceQuestionNumber - 1].getResponse()
if (province == "Province1"){
MailApp.sendEmail('province1Team#domain.com', 'New form response!', "The form has a new response for someone in province " + province + ".");
}
else if (province == "Province2"){
MailApp.sendEmail('province2Team#domain.com', 'New form response!', "The form has a new response for someone in province " + province + ".");
}
else if (province == "Province3"){
MailApp.sendEmail('province3Team#domain.com', 'New form response!', "The form has a new response for someone in province " + province + ".");
}
else if (province == "Province4"){
MailApp.sendEmail('province4Team#domain.com', 'New form response!', "The form has a new response for someone in province " + province + ".");
}
/*
...
*/
}
Then go to Edit -> Current Project's Triggers and set up a new installable trigger with the following settings:
Choose which function to run: sendEmails
Choose which deployment should run: Head
Select event source: From form
Select event type On form submit
Also don't forget to change the names of the provinces and extend the conditional statement if you need, and set which question number the province question is by changing the value of provinceQuestionNumber.

Try using the onFormSubmit trigger and write your script in the Spreadsheet with the Linked Sheet. You will be able to get the information you need from the event object on every onFormSubmit() and you should be able to direct your emails as needed with that information.
If you have any problems please return with additional questions.

The information you need (the response's province name) should be available in a field of the itemResponse object. So, what you nerd to do is access that information and make a switch case with it's value.
There is a link for the documentation of the itemResponse.getResponse() method:
https://developers.google.com/apps-script/reference/forms/item-response#getResponse()

Related

How to send a conditional email depending on a google form answer on google sheets?

I have just set up a google form that automatically populates a Google Sheet. I'm trying to set up an automatic email to notify a specific contact everytime someone submits a form and marks their test as positive. If they submit a negative test, I don't want it to send anything.
I've written the following with the following trigger:
Select event source - From Spreadsheet
Select event type - On from Submission
I've linked the formula to another Sheet for the script contacts. I managed to get it to send an email, however, it was previously sending an email even if a negative test was submitted. Because of this, I added another 'If' for a negative display but now it wont send anything at all.
Can anyone help? This is my first time coding any feel like I have hit a roadblock.
Formula:
function positiveemailsubmission()
{
var positiverange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("LFT Submissions").getRange("G2:G50000")
var positivevalue = positiverange.getDisplayValue("Positive");
{
if (positivevalue.getDisplayValue() === "Positive")
{
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Script info").getRange("B2");
var emailAddress = emailRange.getDisplayValue();
var message = 'A positive LFT test has been submitted. Please see the form for more information (WWW.DOCUMENTLINK.CO.UK)';
var subject = 'Positive LFT Submission ';
GmailApp.sendEmail(emailAddress, subject, message);
}
if (positivevalue.getDisplayValue() === "Negative")
{
}
}
}
In order to provide a proper response to the question, I'm writing this answer as a community wiki, since the solution is in the comments section.
Like #Yuri Khristich said, positiverange was a range of a lot of rows "G2:G50000", in this case what you need is the value of the last row (last submit from Form) to determine if that specific answer was "Positive" or "Negative".
I tested your script with the changes mentioned in the comments and it worked.
function positiveemailsubmission()
{
var positiverange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("LFT Submissions");
var positivevalue = positiverange.getRange("G" + positiverange.getLastRow());
{
if (positivevalue.getDisplayValue() === "Positive")
{
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Script info").getRange("B2");
var emailAddress = emailRange.getDisplayValue();
var message = 'A positive LFT test has been submitted. Please see the form for more information (WWW.DOCUMENTLINK.CO.UK)';
var subject = 'Positive LFT Submission ';
GmailApp.sendEmail(emailAddress, subject, message);
}
if (positivevalue.getDisplayValue() === "Negative")
{
}
}
}

Problems generating PDFs from Google Forms after it is submitted

I am creating a Google Script that fills a Google Doc template based on the fields of a Google Forms and sends the generated PDF via email to the user.
All of the steps that I followed are explained in detail here: Hacking it: Generate PDFs from Google Forms
The script (obtained from the article) is:
function onSubmit(e) {
const rg = e.range;
const sh = rg.getSheet();
//Get all the form submitted data
//Note: This data is dependent on the headers. If headers, are changed update these as well.
const cName = e.namedValues['Client Name'][0];
const cEmail = e.namedValues['Client Email'][0];
const cAddress = e.namedValues['Client Address'][0];
const cMobile = e.namedValues['Client Mobile'][0];
const sendCopy = e.namedValues['Send client a copy?'][0];
const paymentType = e.namedValues['What is your agreed upon payment schedule?'][0];
const fixedCost = e.namedValues['What was your agreed upon cost for the project?'][0];
const hourlyRate = e.namedValues['Hourly Rate'][0];
const manHours = e.namedValues['Total man hours'][0];
const services = e.namedValues['Select the services'][0];
//Consequential Data
const tax = 18.5
var subtotal = 0;
var taxAmt = 0;
var payableAmt = 0;
//if the user has selected hourly payment model
//Note: Be careful that the responses match the elements on the actual form
switch (paymentType ){
case 'Hourly Rate':
subtotal = hourlyRate*manHours;
taxAmt = subtotal * (tax/100);
payableAmt = +subtotal + +taxAmt;
break;
case 'Fixed Cost':
subtotal = fixedCost;
taxAmt = fixedCost * (tax/100)
payableAmt = +fixedCost + +taxAmt;
break;
}
const invoiceID = 'IN' + Math.random().toString().substr(2, 9);
var formattedDate = Utilities.formatDate(new Date(), "IST", "dd-MMM-yyyy");
//Set the consequential data in the columns of the spreadsheet for record keeping
//Note: These variable are dependent on the sheet's columns so if that changes, please update.
const row = rg.getRow();
const payableAmtCol = 2; //B
const invoiceIDCol = 3; //C
sh.getRange(row,payableAmtCol).setValue(payableAmt);
sh.getRange(row,invoiceIDCol).setValue(invoiceID);
//Build a new invoice from the file
//Folder and file IDs
const invoiceFolderID = '<invoice-folder-id>';
const invoiceFolder = DriveApp.getFolderById(invoiceFolderID);
const templateFileID = '<template-id>';
const newFilename = 'Invoice_' + invoiceID;
//Make a copy of the template file
const newInvoiceFileID = DriveApp.getFileById(templateFileID).makeCopy(newFilename, invoiceFolder).getId();;
//Get the invoice body into a variable
var document = DocumentApp.openById(newInvoiceFileID);
var body = document.getBody();
//Replace all the {{ }} text in the invoice body
body.replaceText('{{Invoice num}}', invoiceID);
body.replaceText('{{Date}}', formattedDate);
body.replaceText('{{Client Name}}', cName);
body.replaceText('{{Client Address}}', cAddress);
body.replaceText('{{Client Mobile}}', cMobile);
body.replaceText('{{Client Email}}', cEmail);
body.replaceText('{{Services}}', services.split(', ').join('\n'));
body.replaceText('{{Subtotal}}', subtotal);
body.replaceText('{{Tax Value}}', taxAmt);
body.replaceText('{{Total}}', payableAmt);
//In the case of hourly rate payment type, let's add an additional message giving the rate and the man hours.
if(paymentType.includes('Hourly Rate')){
//It should look something like this on the invoice
//Hourly Rate
//Rate of Rs.1200/hour
//Completed 50 man hours
const message = paymentType + '\nRate of Rs.' + hourlyRate + '/hour\nCompleted ' + manHours + ' man hours';
body.replaceText('{{Payment Type}}', message);
} else {
body.replaceText('{{Payment Type}}', paymentType);
}
document.saveAndClose();
//send email with the file
var attachment = DriveApp.getFileById(newInvoiceFileID);
GmailApp.sendEmail(cEmail, '<subject>,
'<body>',
{attachments: [attachment.getAs(MimeType.PDF)]});
}
The code works fine. Now I need that the user can edit its response after he press "Send Form" on Google Forms. So I decided to check "Respondents can edit after submit". Then I need to send the document again via GmailApp with the edited fields. So I created a new trigger: Edit (from a Spreadsheet). The other trigger is Form submit.
However I have a problem. When the user edits a field and press, again, "Send Form", the trigger "Edit" is activated with the following error: Failed to send email: no recipient.
If I go to the Spreadsheet responses I can see the edited row (because the cell has a comment "The person who responded has updated this value"), and the column mail is not edited but it stills throwing the exception.
How can we solve this problem if cEmail was never edited?
Searchs
I could find some interesting answers:
Failed to send email: no recipient
Google scripts “Failed to send email: no recipient” but email arrives
Failed to send email: no recipient, what is wrong with my code?
They seem to describe that a blank row can be generated when the trigger "Edit" is activated. However I don't see why this could happen, and how I can solve it since the Spreadsheet Responses is automatically edited after a new user submit an answer.
When a form response is edited the on form submit event object properties values and namedValues only include values for those questions that were edited.
To fix the error Failed to send email: no recipient, replace
GmailApp.sendEmail(cEmail, '<subject>,
'<body>',
{attachments: [attachment.getAs(MimeType.PDF)]});
by
const recipientIdx = 1; // This is the 0 based index of the column having the recipient email address
const recipient = cEmail ? cEmail : e.range.getValues().flat()[recipientIdx]
GmailApp.sendEmail(recipient , '<subject>',
'<body>',
{attachments: [attachment.getAs(MimeType.PDF)]});
P.S. Instead of hardcoding the value assigned to recipientIdx you might use some code to get it based on the column headers.
NOTE: The above only will prevent the error mentioned in the question. In order to make the script work you will have to apply the same idea for all the fields: Read the missing values from the spreadsheet by using the e.range.getValues().flat().
Related
How to check if current submission is editing response or a new response
How to check if current form submission is editing response

How can I send a completed Google Form to a user when I submit the form?

I have created a Google Form for my Elem. School Principal for Teacher Observations. She would like to be able to send the completed form to the teacher when she submits the form.
my idea is to somehow add a textbox for the Email address at the end of the form, and when email address is filled, click Submit which will process the form, and send a copy to the recipient email address. I am tryingo to do this via Google's Script editor, but I am not versed in JavaScript. Any help would be appreciated.
If you want to send the filled form to the address of whoever filled it, you can use the "Collect email addresses" and "response receipts" functions.
However, if you want to send the email to other users based on a form input field you can use something like this:
function onFormSubmit(e) {
var form = e.source;
var response = e.response.getItemResponses();
var targetEmail = response[response.length].getResponse(); //Gets response for last question
var htmlResponse = HtmlOutput.createHtmlOutput("<h1>Form Submission:</h1>");
var questions = form.getItems();
for (var i=0; i<questions.length; i++) {
var answerOfQuestion = response[i].getResponse();
if (typeof(answerOfQuestion)=="object") {
var tempAnswer = "<ul>";
for (var j = 0; j<answerOfQuestion.length; j++) {
tempAnswer += "<li>"+answerOfQuestion[j].toString()+"</li>";
}
tempAnswer += "</ul>";
answerOfQuestion = tempAnswer;
}
htmlResponse.append("<p><b>"+questions[i].getTitle()+":</b> "+answerOfQuestion+"</p>");
}
GmailApp.createDraft(targetEmail, 'Form Submission', 'Here is the form results:' + htmlResponse.getContent() , {
htmlBody: htmlResponse.getContent(),
}).send();
}
Go to Settings (the gear icon) > General Tab
Select both "collect email addresses" and "response receipts"
No additional coding necessary.

Auto-direct emails to specific addresses on Google Form submit

This is my first post so apologies in advance if I am posting to the wrong place or asking a question that has been answered elsewhere - go easy on me!
In a nutshell, I have a Google Form and a connected Google Sheet. I need to automate it so that, when a new form is submitted, an email is sent to a specific colleague (the student's supervisor). I have had a good go myself but am now totally stuck!
I have created the form, linked it to a sheet, written the code, added the trigger and tested by submitting a form. Nothing happened! No error messages, just... nothing!
Any advice hugely appreciated. I am very new to this and still taking baby steps.
The code I have cobbled together (which is probably full of errors!) is as follows:
function wa132657(e) {
//setup the spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
//get the range from OnFormSubmit
var range = e.range;
Logger.log("DEBUG: the range is "+range.getA1Notation());//DEBUG
// get the data for the range
var response = row.getValues();
// get the supervisor name from the form submission
var supervisor = response[0][1];
Logger.log("DEBUG: Supervisor = "+supervisor);// DEBUG
// get the emails list
var emailSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SupEmails");
// get ALL the data from this sheet
var emaildata = emailSheet.getDataRange().getValues();
// check how many rows of data
var emailLastRow = emailSheet.getLastRow();
// start the loop through the emails data
for (var i=1; i<emailLastRow; i++){
// if the supervisor is equal to SupervisorEmail
if (supervisor == emaildata[i][0]){
// there is a match
//Next, get the email address
var emailSupervisor = emaildata[i][1];
Logger.log("DEBUG: supervisor = "+emaildata[i][0]+", email address: "+emailSupervisor);// DEBUG
// Finally, send the Email.
var theirName = e.values[2];
var theirProgramme = e.values[3];
var theAbsenceReason = e.values[8];
var theAbsenceStart = e.values[5];
var theAbsenceEnd = e.values[6];
var subject = "Student Absence Report";
var message = "New Absence Report: " + theirName + " \n Programme: " + theirProgramme; + " \n\n
Reason for Absence: \n" + theAbsenceReason + " \n Start of Absence" + theAbsenceStart + "\n End of Absence:" + theAbsenceEnd;
MailApp.sendEmail(emailSupervisor, subject, message);
}
}
}

Using data from var in subjectLine

I'm modifying Amit's code ( found here: http://labnol.org/?p=20884)
to try to send email with the data from a Google Form.
But what I'm trying to grab is from his keys and columns.
I want to specifically take the first 1 and 2 column's data from the row in question and use it as a var in the subject field.
But the output (in email and when sent to asana) is listed as undefined. Where did I go wrong?
/*
Send Google Form Data by Email v4.2
Written by Amit Agarwal amit#labnol.org
Source: http://labnol.org/?p=20884
*/
/**
* #OnlyCurrentDoc
*/
function Initialize() {
try {
var triggers = ScriptApp.getProjectTriggers();
for (var i in triggers)
ScriptApp.deleteTrigger(triggers[i]);
ScriptApp.newTrigger("EmailGoogleFormData")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit().create();
} catch (error) {
throw new Error("Please add this code in the Google Spreadsheet");
}
}
function EmailGoogleFormData(e) {
if (!e) {
throw new Error("Please go the Run menu and choose Initialize");
}
try {
if (MailApp.getRemainingDailyQuota() > 0) {
// You may replace this with another email address
var email = "x+00000000#mail.asana.com";
// Enter your subject for Google Form email notifications
var key, entry,
message = "",
ss = SpreadsheetApp.getActiveSheet(),
cols = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
// Iterate through the Form Fields
for (var keys in cols) {
key = cols[keys];
entry = e.namedValues[key] ? e.namedValues[key].toString() : "";
// Only include form fields that are not blank
if ((entry !== "") && (entry.replace(/,/g, "") !== ""))
message += key + ' :: ' + entry + "\n\n";
var first = entry[1];
var last = entry[2];
var subject = first+" "+last+": Interested Candidate";
}
MailApp.sendEmail(email, subject, message);
}
} catch (error) {
Logger.log(error.toString());
}
}
/* For support, contact developer at www.ctrlq.org */
entry is a string, defined here:
entry = e.namedValues[key] ? e.namedValues[key].toString() : "";
...which you later treat as an array:
var first = entry[1];
var last = entry[2];
At this point, first and last will both be undefined, because entry isn't an array. Further, this is inside a for loop that's traversing all the columns in the row - you can't see any bad side-effect from that, but these assignments and generation of a subject are happening multiple times.
That last clue suggests a better way to achieve your goal. Define the first and last variables before the loop, with default values. Then when looping over columns, watch for the columns containing the candidates' name, and update the default contents. Finally, after the loop, generate the subject line.
function EmailGoogleFormData(e) {
if (!e) {
throw new Error("Please go the Run menu and choose Initialize");
}
try {
if (MailApp.getRemainingDailyQuota() > 0) {
// You may replace this with another email address
var email = "x+00000000#mail.asana.com";
// Enter your subject for Google Form email notifications
var key, entry,
first = "unknown", last = "unknown",
message = "",
ss = SpreadsheetApp.getActiveSheet(),
cols = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
// Iterate through the Form Fields
for (var keys in cols) {
key = cols[keys];
entry = e.namedValues[key] ? e.namedValues[key].toString() : "";
// Only include form fields that are not blank
if ((entry !== "") && (entry.replace(/,/g, "") !== ""))
message += key + ' :: ' + entry + "\n\n";
if (key == "first") { // Assumes "first" is column header
first = entry;
}
if (key == "last") { // Assumes "last" is column header
last= entry;
}
}
var subject = first+" "+last+": Interested Candidate";
MailApp.sendEmail(email, subject, message);
}
} catch (error) {
Logger.log(error.toString());
}
}
Sandy Good has created a similar app Data Director. I don't know why he did not mention it here? May be it's not what you're looking for.
I haven't used it yet, but thought his works might help someone who needs it.
----------------------------------------
OVERVIEW:
Send form data to different sheet. Integrate with Calendar. Sends emails. Makes an Edit URL and/or a PreFilled URL.
The Data Director for Forms Add-on has multiple features. It can send the form response to an alternate spreadsheet. It can send an email or multiple emails when the Form is submitted. It can add a guest to your calendar event.
When your Google Form is submitted, the Data Director for Forms Add-on can get the last form submission, and save it to a second spreadsheet destination of your choice. The destination spreadsheet can be any Google spreadsheet that your Google account has permission to write to. For example: Your Google Form currently writes data to a spreadsheet, but you want the form response to also go into a second sheet in the same spreadsheet. This Add-on can do that. Or the Add-on can write a copy of the form response to a completely different spreadsheet.
You should install this add-on if you want to save a copy the form response to to a destination other than what is set in the Form's design.
But that's not all Data Director can do! Data Director will also create an Edit URL and/or a PreFilled URL, and save those links to the spreadsheet.
There's even more! It will also send an email to the email address of your choice with a custom message. This is an extra option that you may want or need to use.
Here's a list of What Data Director can do!
Send a copy of the form response to a Google spreadsheet.
The same Google spreadsheet that is already receiving the Form response, or
A different spreadsheet than is currently receiving the Form response.
Exclude the timestamp from the copied response if you choose. The default is to include the timestamp.
Create an Edit URL and save a link to the destination spreadsheet.
Create a PreFilled URL and save the link to the destination spreadsheet.
Send multiple emails to the email addresses of your choice.
Send an email to the email address collected from a Form field.
Include the Edit Url and/or the PreFilled Url in the email.
CC the email to the address of your choice, or not.
Includes the option to specify the subject line.
The Body of the email can be written in the settings for the email. No need to create a template email.