Google Form Send Email to Owner after Response Submission - google-apps-script

I am just starting Google Forms. I need to email the form owner (myself and some others) a response as soon the the user submit the data. I need the data in the email which would include fields and their values that were submitted by the user as soon as they submit the form.
I am unable to use add-on as per my google account settings via my employer where add-on are blocked.
I am exploring app scripts but with little success as I am very new. As there some sample codes to help me get started with create a basic script to send email.
I have the following Code:
function sendFormByEmail(e)
{
var email = "ownersemail#host.ca";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
var subject = "New Hire: ";
for(var i in headers)
message += headers[i] + ': '+ e.namedValues[headers[i]].toString() + "\n\n";
subject += e.namedValues[headers[2]].toString() + " - starts " + e.namedValues[headers[15]].toString();
MailApp.sendEmail(email, subject, message);
}
Then I added this script in the form trigger like so:
I tried submitting the form but nothings heppens. How do I know that the script ran or there was a problem?
If I try to run this in the script editor :
It gives me an error :
TypeError: Cannot call method "getRange" of null. (line 7, file "Code")
Update
I tested the email functionality and it worked. So the problem has to be in Spread Sheet value retrieval.
function sendFormByEmail(e)
{
var email = "ownersemail#host.ca";
MailApp.sendEmail(email, "Test", "Test");
}
I also created a excel file on my google drive that holds these response from google form
Final Solution
function testExcel() {
var email = "ownersemail#host.ca";
var s = SpreadsheetApp.openById("GoogleDocsID");
var sheet = s.getSheets()[0];
var headers = sheet.getRange(1,1,1,sheet.getLastColumn()).getValues()[0];
var datarow = sheet.getRange(sheet.getLastRow(),1,1,sheet.getLastColumn()).getValues()[0];
var message = "";
for(var i in headers)
{
message += "" + headers[i] + " : " + datarow[i] + "\n\n";
//Logger.log(message);
}
MailApp.sendEmail(email, "Submitted Data Test", message);
}

Here is a shell for you to start with. I use this code for a very similar reason. This shell includes creating a Google Doc from template and adding data from the sheet into that Doc. You can use similar methods to set variables and add them into the email. I use an html template file(s) to manage exactly what is being sent each time.
The merge portion checks through the Doc (you can set it to look through html file) and finds my tags using RegEx; structed as so: <<columnHeader>>. In this way, You have a consistent template that replaces those tags with the data, in that column, for that row. Modify to your needs as you see fit.
This also displays the progress of the merge. That way, it won't repeat your emails/ merge.
NOTE: There are several data points missing as I removed the personal information; it won't run straight from this sample. You will have to add your document IDs, correct for variable placement, etc.
function mergeApplication() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("");
var formSheet = ss.getSheetByName("");
var lastRow = formSheet.getLastRow();
var lastColumn = sheet.getMaxColumns();
function checkAndComplete() {
var urlColumn = lastColumn;
var checkColumn = (urlColumn - 1);
var checkRange = sheet.getRange(2, checkColumn, (lastRow - 1), 1);
var check = checkRange.getBackgrounds();
var red = "#ff0404";
var yellow = "#ffec0a";
var green = "#3bec3b";
for (var i = 0; i < check.length; i++) {
if (check[i] == green) {
continue;
} else {
var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
var dataRow = sheet.getRange((i+2), 1, 1, (lastColumn - 2));
function mergeTasks() {
function docCreator() {
var docTemplate1 = DriveApp.getFileById("");
var docTemplate2 = DriveApp.getFileById("");
var folderDestination = DriveApp.getFolderById("");
var clientName = sheet.getRange((i+2), 2, 1, 1).getValue();
var rawSubmitDate = sheet.getRange((i+2), 1, 1, 1).getValue();
var submitDate = Utilities.formatDate(rawSubmitDate, "PST", "MM/dd/yy");
var typeCheck = sheet.getRange((i+2), (checkColumn - 1), 1, 1).getValue();
if (typeCheck == "Type 1") {
var docToUse = docTemplate1;
var emailBody = HtmlService.createHtmlOutputFromFile("").getContent();
} else {
var docToUse = docTemplate2;
var emailBody = HtmlService.createHtmlOutputFromFile("").getContent();
}
var docName = "" + clientName + " - " + submitDate;
var docCopy = docToUse.makeCopy(docName, folderDestination);
var docId = docCopy.getId();
var docURL = DriveApp.getFileById(docId).getUrl();
var docToSend = DriveApp.getFileById(docId);
var docInUse = DocumentApp.openById(docId);
var docBody = docInUse.getBody();
var docText = docBody.getText();
function tagReplace() {
var DOBCell = sheet.getRange((i+2), 3, 1, 1);
var rawDOB = DOBCell.getValue();
if (rawDOB !== "") {
var DOB = Utilities.formatDate(rawDOB, "PST", "MM/dd/yy");
} else {
var DOB = ""
}
var taggedArray = docText.match(/\<{2}[\w\d\S]+\>{2}/g);
var headerArray = sheet.getRange(1, 1, 1, (lastColumn - 2)).getValues();
var dataArray = dataRow.getValues();
dataArray[0][2] = DOB;
var strippedArray = [];
function tagStrip() {
for (var t = 0; t < taggedArray.length; t++) {
strippedArray.push(taggedArray[t].toString().slice(2, -2));
}
}
function dataMatch() {
for (var s = 0; s < strippedArray.length; s++) {
for (var h = 0; h < headerArray[0].length; h++) {
if (strippedArray[s] == headerArray[0][h]) {
docBody.replaceText(taggedArray[s], dataArray[0][h]);
}
}
}
docInUse.saveAndClose();
}
tagStrip();
dataMatch();
}
function emailCreator() {
var emailTag = sheet.getRange((i+2), (checkColumn - 9)).getValue();
var emailSubject = "" + clientName;
MailApp.sendEmail({
to: emailTag,
subject: emailSubject,
htmlBody: emailBody,
attachments: [docToSend.getAs(MimeType.PDF)],
replyTo: "",
});
}
tagReplace();
statusCell.setBackground(yellow);
emailCreator();
urlCell.setValue(docURL);
}
statusCell.setBackground(red);
docCreator();
statusCell.setBackground(green);
}
mergeTasks();
}
}
}
checkAndComplete();
}

Related

Sending an Email from google sheets only once

The code below works perfectly and sends the email I need it to send on an "OnChange" trigger. However, it sends an email for EVERY checked box in row 7 which is overload, it just needs to send an email for newly checked boxes.
Any advice on how to add a condition in the below code for this?
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Service');
var data = sheet.getDataRange().getValues();
for (var i = data.length - 1; i >= 1; i--) {
if (sheet.getRange(i,7).isChecked()){
var name = sheet.getRange(i,1).getValue();
var last = sheet.getRange(i,2).getValue();
var body = name + " " + last
var subject = 'New Service Item in Stock'
MailApp.sendEmail('me#mycompany.com', subject, body);
}
}
}
I haven't tried anything because there is nothing I could find online to get me in the right direction.
https://i.stack.imgur.com/cKfLv.png
Try unchecking them after you send them:
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Service');
var data = sheet.getDataRange().getValues();
for (var i = data.length - 1; i >= 1; i--) {
if (sheet.getRange(i, 7).isChecked() && sheet.getRange(i,8).getValue() != "Sent") {
var name = sheet.getRange(i, 1).getValue();
var last = sheet.getRange(i, 2).getValue();
var body = name + " " + last
var subject = 'New Service Item in Stock'
MailApp.sendEmail('me#mycompany.com', subject, body);
sheet.getRange(i, 8).setValue("Sent");
}
}
}
Performance improvement:
function sendEmails() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('Service');
var vs = sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getValues();
vs.forEach((r, i) => {
if (sh.getRange(i + 2, 7).isChecked() && r[7] == "Sent") {
let body = `${r[0]} ${r[1]}`;
let subject = "New Service Item in Stock";
MailApp.sendEmail('me#mycompany.com', subject, body);
sh.getRange(i, 8).setValue("Sent");
}
});
}

Email not sending or probably not being triggered on form submit Google Apps Scripts

Well we have this google form and the details are being added to google sheet with custom g apps scripts. When the details have been appended to the google sheet log, it should send email. If I run the sendmail() manually, it works but when I call it inside onFormSubmit(), it's not working. What could have gone wrong?
function onFormSubmit(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var templateLink = sheet.getSheetByName("Template Link").getRange(1, 1).getValue();
var logSheet = sheet.getSheetByName("Log");
var formResponsesSheet = sheet.getSheetByName("Form Responses 1");
var formResponsesHeader = formResponsesSheet.getRange(1, 2, 1, formResponsesSheet.getLastColumn() -1).getValues();
var newFileName = e.namedValues['Name'][0] + "-" + e.namedValues['Date'][0];
var populatedDocsFolder = DriveApp.getFolderById("1yTSd7W0U4Gcsm6CIw8NtD022F-MA7CPx");
var templateDocID = DocumentApp.openByUrl(templateLink).getId();
var newDocID = DriveApp.getFileById(templateDocID).makeCopy(newFileName, populatedDocsFolder).getId();
var newDocLink = DriveApp.getFileById(newDocID).getUrl();
var newDoc = DocumentApp.openById(newDocID);
var newDocBody = newDoc.getBody();
for (i = 0; i < formResponsesHeader[0].length; i++) {
var thisHeader = formResponsesHeader[0][i];
var thisValue = e.namedValues[thisHeader][0];
newDocBody.replaceText("<<" + thisHeader + ">>", thisValue);
}
//Log
var name = e.namedValues['Name'][0];
var email = e.namedValues['Email'][0];
var date = e.namedValues['Date'][0];
logSheet.appendRow([name,email,date,newDocID]);
//Trigger
ScriptApp.newTrigger("sendEmail").timeBased().after(15000).create();
//sendEmail();
}
function sendEmail() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = sheet.getSheetByName("Log");
var logSheetData = logSheet.getDataRange().getDisplayValues();
var templateName = sheet.getSheetByName("Template Name").getRange(1, 1).getValue();
for (i = 1; i < logSheetData.length; i++) {
if (logSheetData[i][4] == "") {
//SEND EMAIL
var name = logSheetData[i][0];
var email = logSheetData[i][1];
var date = logSheetData[i][2];
var id = logSheetData[i][3];
var pdfName = templateName + "-" + name + "-" + date;
//PDF EMAIL
try{
var doc = DriveApp.getFileById(id);
var blob = doc.getBlob().getAs('application/pdf').setName(pdfName + ".pdf");
var subject = 'Document Created';
//GmailApp.sendEmail(email, subject, "This is just a test", {attachments: [blob]});
MailApp.sendEmail(email, subject, "", {attachments: [blob], name: pdfName});
}catch(err){
continue;
}
//Log Sheet Update
logSheet.getRange(i + 1, 5).setValue("Sent");
}
}
}
function onOpen() {
SpreadsheetApp.getUi().createMenu("Custom Menu")
.addItem("Build Form Submit Trigger", "formSubmitTrigger")
.addSeparator()
.addItem("Send Email", "sendEmail")
.addSeparator()
.addItem("Mismatch Check", "mismatchCheck")
.addToUi();
}
function formSubmitTrigger() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
ScriptApp.newTrigger("onFormSubmit").forSpreadsheet(sheet).onFormSubmit().create();
}
function mismatchCheck() {
var result = "";
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var templateLink = sheet.getSheetByName("Template Link").getRange(1, 1).getValue();
var formResponsesSheet = sheet.getSheetByName("Form Responses 1");
var formResponsesHeader = formResponsesSheet.getRange(1, 2, 1, formResponsesSheet.getLastColumn() -1).getValues();
var docBody = DocumentApp.openByUrl(templateLink).getBody().getText();
var matches = docBody.match(/<</g); var noOfLessThanMatches = matches.length;
var matches = docBody.match(/>>/g); var noOfMoreThanMatches = matches.length;
var lessThan = docBody.search(/<</g);
var moreThan = docBody.search(/>>/g);
Logger.log([noOfLessThanMatches,noOfMoreThanMatches]);
result += "<b>Less Than Signs:</b> " + noOfLessThanMatches + "<br>";
result += "<b>More Than Signs:</b> " + noOfMoreThanMatches + "<br>";
result += "<br><b>Doc to Form Check</b><br>";
var newDocBody = docBody;
var reverseArray = [];
for (i = 0; i < noOfLessThanMatches; i++) {
var lessThan = newDocBody.search(/<</g);
var moreThan = newDocBody.search(/>>/g);
var subString = newDocBody.substring(lessThan + 2,moreThan);
Logger.log(subString);
var indexOf = formResponsesHeader[0].indexOf(subString);
if (indexOf > -1) {
result += subString + " - FOUND<br>";
} else {
result += subString + " - NOT FOUND<br>";
}
reverseArray.push(subString);
newDocBody = newDocBody.replace("<<" + subString + ">>","XX")
}
result += "<br><b>Form to Doc Check</b><br>";
for (z = 0; z < formResponsesHeader[0].length; z++) {
var thisString = formResponsesHeader[0][z];
var indexOf = reverseArray.indexOf(thisString);
if (indexOf > -1) {
result += thisString + " - FOUND<br>";
} else {
result += thisString + " - NOT FOUND<br>";
}
}
Logger.log(result);
var htmlOutput = HtmlService
.createHtmlOutput('<p>' + result + '</p>')
.setWidth(400)
.setHeight(500);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'RESULT');
}
UPDATE: I have pasted the whole code instead above so you guys can see
You have to register onFormSubmit as the function that handles the form submit trigger. Have you registered the function "onFormSubmit" like this:
ScriptApp.newTrigger('onFormSubmit').forForm(form).onFormSubmit().create();
You might also want to check the registered triggers by clicking on Edit > Current project's trigger from your Apps Script project.
[Edit] Since the trigger is created properly, change the first the line of the trigger code from:
function onFormSubmit(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
to this:
function onFormSubmit(e) {
var sheet = SpreadsheetApp.openById(e.source.getDestinationId());

Trying to 'install' a trigger from script editor returns 'You do not have permission to call newTrigger"

So, I've been trying to send an email through MailApp inside an onFormSubmit function. I recently learnt that simple triggers don't have extended access to services such as mail but installable's do.
So off I went to scour the internet for how to make an installable trigger, I don't understand the google documentation for them in the slightest, nor have I found a single helpful video/forum anywhere on them that makes them easy to understand,
therefore I turn to you, you bunch of geniuses.
Through the script editor, I'm calling this manually
function CreateFormSubmitTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('formDone')
.forSpreadsheet(ss)
.onFormSubmit()
.create()
}
every time I run it, it returns "You do not have permission to call newTrigger (line 7, file "Code")"
The function I'm trying to make a trigger for is below, When I had this on current project triggers > spreadsheet > onFormSubmit. It wasn't working either.
function formDone(e) {
Utilities.sleep(3000)
var range = e.range;
var ss = range.getSheet();
var row = range.getRowIndex();
var tactics =
Sheets.Spreadsheets.Values.get('id', "A:AQ"+row);
var headers =
Sheets.Spreadsheets.Values.get('id', 'A1:U1');
var templateID = "id"
var i = 0; i < tactics.values.length;
var Timestamp = tactics.values[i][0];
var IDCFREF = tactics.values[i][2];
var raisedby = tactics.values[i][4];
var AccMan = tactics.values[i][6];
var Contrib = tactics.values[i][7];
var Contract = tactics.values[i][8];
var CompName = tactics.values[i][9];
var ValidFrom = tactics.values[i][10];
var ValidTo = tactics.values[i][11];
var Freq = tactics.values[i][12];
var PDetailFreq = tactics.values[i][13];
var BillType = tactics.values[i][14];
var TypeOfRebate = tactics.values[i][15];
var RebateDetails = tactics.values[i][16];
var RTarget = tactics.values[i][17];
var GiveDeets = tactics.values[i][19];
var WhyGiveRebate = tactics.values[i][20];
var documentID = DriveApp.getFileById(templateID).makeCopy().getId();
console.log({message: IDCFREF})
if (DriveApp.getFilesByName("Rebate " + IDCFREF + " Request").hasNext()){
DriveApp.getFilesByName("Rebate " + IDCFREF + " Request").next().setTrashed(true)
} else {
}
DriveApp.getFileById(documentID).setName('Rebate ' + IDCFREF + ' Request');
var body1 = DocumentApp.openById(documentID).getBody();
var header = DocumentApp.openById(documentID).getHeader();
header.replaceText('##IDCF##', IDCFREF)
body1.replaceText('##REF##', IDCFREF)
body1.replaceText('##RAISED##', raisedby)
body1.replaceText('##ACCMAN##', AccMan)
body1.replaceText('##CONTRIB##', Contrib)
body1.replaceText('##SIGNED##', Contract)
body1.replaceText('##NAME##', CompName)
body1.replaceText('##FROM##', ValidFrom)
body1.replaceText('##TO##', ValidTo)
body1.replaceText('##FREQ##', Freq)
body1.replaceText('##BESPOKE##', PDetailFreq)
body1.replaceText('##BILL##', BillType)
body1.replaceText('##TYPE##', TypeOfRebate)
body1.replaceText('##DEETS##', RebateDetails)
body1.replaceText('##TARGET##', RTarget)
body1.replaceText('##FULL##', GiveDeets)
body1.replaceText('##ELAB##', WhyGiveRebate)
Utilities.sleep(5000)
var filemail = DriveApp.getFileById(documentID)
if(DocumentApp.openById(documentID).getBody().findText("#")) {
MailApp.sendEmail({
to: "email",
subject: "Rebate Request " + IDCFREF + " - Pending",
body: "",
attachments: [filemail]
})
} else {
MailApp.sendEmail({
to: "email",
subject: "Rebate Request " + IDCFREF + " - Complete",
body: "rebates",
attachments: [filemail]
});
}
}
Any light on the situation would be met by unparalleled appreciation.
Cheers

Need help iterating down a column in google sheets and sending out an email based on each individual value in the cells

I am guessing this is a simple thing to do but I am not sure how to do it. I have a google script that I want to run daily that checks the values of cells within one column in google sheets individually and sends an email if the value drops below a certain threshold.
What I have so far is
function sendEmail() {
var data = SpreadsheetApp.getActiveSheet().getRange('E2').getValue();
if (data < 300){
var emailAddress = "emailaddress#email.com";
var message = "test body";
var subject = "test subject";
MailApp.sendEmail(emailAddress, subject, message);
}
}
EDIT
Here is where I am now. It works except for pulling the emails from the cells.
function sendEmail() {
function letThemKnow(num) { //This creates a function named letThemKnow which is passed the variable num from the if/else statements
var emailAddress = email[i]; //Sets the variable to the email address of
var message = "Greetings! This is an automated message to let you know your license for " + software[i] + " expires in " + num + " days.";
var subject = "Impending expiration of " + software[i];
MailApp.sendEmail(emailAddress, subject, message);
}
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var lastRow = sh.getLastRow();
var data = sh.getRange(2, 5, lastRow, 1).getValues();
var software = sh.getRange(2, 1, lastRow, 1).getValues();
var email = sh.getRange(2, 7, lastRow, 1).getValues();
for (i = 0; i <= email.length; i++) {
for (i = 0; i <= software.length; i++) {
for (i = 0; i <= data.length; i++) {
var num = parseInt(data[i]);
if (num == 30) {
letThemKnow(num)
} else if (num == 14) {
letThemKnow(num)
} else if (num <= 7) {
letThemKnow(num)
}
}
} //
}
} //
Your for loop is starting at '0' and ending at '0'. Try this:
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var lastRow = sh.getLastRow();
var data = sh.getRange(2,5,lastRow,1).getValues();
for (i=0;i <= data.length;i++){
var num = parseInt(data[i]);
if (num < 300) {
var emailAddress = "email#email.com";
var message = "test body";
var subject = "test subject";
MailApp.sendEmail({
name: "Your Name",
to: emailAddress,
subject: subject,
htmlBody: message
});
}
}
}
If the email is the same every time, you should probably define those variables outside the loop.

Google Apps Script - Send Email with Edit Link

I am creating a script that sends a custom email right after you send the form. It works perfectly but I wanted it to work also when I edit the form it sends a automatic email with the changes made.
function Initialize() {
var triggers = ScriptApp.getProjectTriggers();
for (var i in triggers)
ScriptApp.deleteTrigger(triggers[i]);
ScriptApp.newTrigger("SendGoogleForm")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit().create();
}
function SendGoogleForm(e) {
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "Please paste this!\n\n";
var subject = "Email: ID: ";
var email = "";
//
var form = FormApp.openById('*******************'); //this is the ID in the url of your live form
var formResponses = form.getResponses();
//
for (var i = 0; i < formResponses.length; i++) {
var formResponse = formResponses[i];
}
for(var i in headers) {
if ( e.namedValues[headers[i]].toString() != "") {
message += headers[i] + ': '+ e.namedValues[headers[i]].toString() + "\n";
}
}
subject += e.namedValues[headers[2]].toString();
email += e.namedValues[headers[1]].toString();
message += "Edit Link: " + formResponse.getEditResponseUrl();
MailApp.sendEmail(email, subject, message);
}
I've found a script that may help to send a email when it is edited but I am not sure how I can implement it(found it in google docs forums https://productforums.google.com/forum/#!topic/docs/-guIl5QlvKk):
function checkResponse() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Form Responses 1');
var lastRow = s.getLastRow();
var range = s.getRange('A' + lastRow + ':C' + lastRow);
var notes = range.getNotes();
var values = range.getValues();
var changedFlag = null;
var body = '';
for (var i = 0; i < notes[0].length; i++ ) {
if ( notes[0][i] == 'Responder updated this value.' ) {
changedFlag = true;
// We know only to send the changed values
// Add changed value to email msg
body += values[0][i];
// May also want to clear the note as it remains after future edits of other values as well
s.getRange(lastRow, i).clearNote();
}
}
if ( !changedFlag ) {
// Email the whole row of values
for (var i = 0; i < values.length; i++) {
body += values[0][i];
}
}
GmailApp.sendEmail(recipient, subject, body)
}