Google Form. Confirmation Email Script. With edit url - email

I have two working trigger functions in Google Script that fire when a form response spreadsheet gets a new submission. One inserts the "edit your submission" url into the spreadsheet. The other looks up the response's email and sends them a confirmation.
What I'm having a hard time understanding is how to populate the url first, and then send an email containing that url.
(Google Script is different to debug than js in the browser :\ )
Setup triggers
function Initialize() {
var triggers = ScriptApp.getScriptTriggers();
for (var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
ScriptApp.newTrigger("SendConfirmationMail")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit()
.create();
assignEditUrls();
}
On form submit, searches for column titled "Clients Email", and sends a formatted email to them.
function SendConfirmationMail(e) {
try {
var ss, cc, sendername, subject, columns;
var message, value, textbody, sender;
var url;
// This is your email address and you will be in the CC
cc = Session.getActiveUser().getEmail();
// This will show up as the sender's name
sendername = "XXXX";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
subject = "Form Complete: Mobile App - Client Questionnaire";
// This is the body of the auto-reply
message = "Confirmation text here.<br><br>Thanks!<br><br>";
ss = SpreadsheetApp.getActiveSheet();
columns = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
// This is the submitter's email address
sender = e.namedValues["Clients Email"].toString();
// Only include form values that are not blank
for ( var keys in columns ) {
var key = columns[keys];
if ( e.namedValues[key] ) {
message += key + ' :: '+ e.namedValues[key] + "<br />";
}
}
textbody = message.replace("<br>", "\n\n");
GmailApp.sendEmail(sender, subject, textbody,
{cc: cc, name: sendername, htmlBody: message});
} catch (e) {
Logger.log(e.toString());
}
}
Separate function. Looks up form and applies the edit URL to the 26th column.
function assignEditUrls() {
var form = FormApp.openById('10BVYipGhDa_AthabHE-xxxxxx-hg');
//enter form ID here
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses');
//Change the sheet name as appropriate
var data = sheet.getDataRange().getValues();
var urlCol = 26; // column number where URL's should be populated; A = 1, B = 2 etc
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j][0].setMilliseconds(0))]:'']);
}
sheet.getRange(2, urlCol, resultUrls.length).setValues(resultUrls);
}

Programmers are provided no direct control over the order that trigger functions will be invoked, when they are dependent on the same event.
In your situation though, there are a couple of options available.
Use only one trigger function for the event, and have it invoke the current functions in the order you require. (Alternatively, set assignEditUrls() up as the only trigger function, and have it call SendConfirmationMail() after completing its task.
Have SendConfirmationMail() check for the availability of the Edit URL, and call Utilities.sleep() if the URL isn't ready yet. (In a loop, until ready.)

Related

MailApp.sendEmail function runs without errors but no emails are sent

The below script runs without any visible error, but no emails are sent. Any ideas as to why?
function sendEmailLoop() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
sheets.forEach(function(sheet) {
var range = sheet.getDataRange();
if (sheet.getName() == "Summary") //Disregard tab named 'Summary'
{
}
else {
var range = sheet.getDataRange(); //to set the range as array
var values = range.getDisplayValues(); //to get the value in the array
var lastRow = range.getLastRow();
var ss = SpreadsheetApp.getActiveSpreadsheet(); //declare the spreadsheet
var sheet = ss.getSheetByName("Sheet1");
var Title = values[0][0]; //[Title] cell A1
var URL = values[0][1]; //[URL] cell B1
var i;
var logContent = '';
for (i = 3; i < lastRow; i++) {
var Name = values[i][0]; //[Name] cell A++
var Email = values[i][1]; // [Email] cell B++
Logger.log('to: ' + Email);
Logger.log('subject: ' + Name + Title + 'Test');
Logger.log('message: ' + 'This is a test message for the training that can be found at ' + URL);
/*
MailApp.sendEmail({
to: Email,
subject: Name + Title + 'Test',
message: 'This is a test message for the training that can be found at ' + URL});
*/
}; //end for loop - email tab data
}; // end 'else'
}); // end function(sheet)
} // end SendEmailLoop()
Here is the Stackdriver log of a successful execution (success meaning no errors, but still no emails are sent):
The structure of the spreadsheet associated with the script:
Note - an earlier version of this script didn't include the sheets.forEach() method call (ie, to loop through each tab of the spreadsheet) and the emails were sent fine.
Could the lack of emails being sent or received be related to the fact that I have many sheets and this function is looping through them?
function sendEmailLoop() {
var exclA=['Summary'];
var ss=SpreadsheetApp.getActive();
var sheets=ss.getSheets();
sheets.forEach(function(sheet) {
if (exclA.indexOf(sheet.getName())==-1) {
var range=sheet.getDataRange();
var values=range.getDisplayValues();
var lastRow=range.getLastRow();
var Title=values[0][0];
var URL=values[0][1];
var logContent='';
for (var i=3; i <values.length; i++) {
var Name=values[i][0];
var Email=values[i][1];
Logger.log('to: %s\nsubject: %s %s Test\nmessage: %s This is a test message for the training that can be found at %s',Email,Name,Title,URL);
/*
MailApp.sendEmail({
to: Email,
subject: Name + Title + 'Test',
message: 'This is a test message for the training that can be found at ' + URL});
*/
}
}
});
}
Answer:
You need to uncomment your MailApp code.
Code changes:
I tested your code and it seems to run without issue for me, including the receipt of the emails, only that the code comments around your MailApp call need to be removed (the /* and the */).
I would also suggest adding a conditional line before you send the email in the event .getDataRange() obtains seemingly empty rows:
if (Email == "") {
continue;
};
MailApp.sendEmail({
to: Email,
subject: Name + Title + 'Test',
message: 'This is a test message for the training that can be found at ' + URL});
References:
JavaScript Comments

How to run script if a google sheets cell contains email?

I'm looking for help to send an email whenever a new row is added by a google form entry if said entry contains an email in the Email column. I'm new to Javascript, but I've pieced together some code which I plan to run off an onEdit trigger in GSheets.
My problem is that if there is no email address, the code will fail. I need to know how to wrap this in an "if/else" or maybe just a simple error handling bit would be fine, not sure.
If I go with an "if/else", I'll need to check if the email column contains a value. I don't need to check if it is a valid email; the google form already does this on submission.
Here is the code I have right now:
function MessageNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("Message Board"));
//
//extracts the values in last row and stores them into a two-dimensional
array called data
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var dataRange = sheet.getRange(lastRow,3,1,8);
var data = dataRange.getValues();
//
//pull column elements into a one-dimensional array called rowData
for (i in data) {
var rowData = data[i];
var emailAddress = rowData[2];
var poster = rowData[7];
var subject = rowData[3];
var recipName = rowData[6];
var comment = rowData[4];
var replyLink = rowData[5];
//
//
var message = 'Dear ' + recipName + ',\n\n'+poster+' has posted the
following comment directed to you: '+'\n'+comment+'\n\n'+'To reply to this
comment click: '+replyLink;
var subject = subject;
MailApp.sendEmail(emailAddress, subject, message);
}
}
thanks in advance for any help you can give me.
Thank you tehhowch for the help. I'm new at this so I'll have to continue researching the link you referred to regarding iteration best practice. However I was able to get this working with a simple 'if' wrapper, which turned out to be simpler than I thought.
I did find out that form submission does not recognize an active sheet, so manually testing my code worked, while form submission did not trigger it.
After some looking, I replaced:
var ss = SpreadsheetApp.getActiveSpreadsheet();
with this:
var ssID = '//insert spreadsheet id here';
var ss = SpreadsheetApp.openById(ssID);
This still did not work, so I had to kickstart it by deleting the trigger and putting it back in (found this info: On form submit trigger not working)
This may not be the most efficient code, but here is what I have now, and it does work:
function MessageNotification() {
var ssID = '//insert spreadsheet id here';
var ss = SpreadsheetApp.openById(ssID);
ss.setActiveSheet(ss.getSheetByName("Message Board"));
//extracts the values in last row and stores them into a two-dimensional
array called data
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var dataRange = sheet.getRange(lastRow,3,1,8);
var data = dataRange.getValues();
//
//pull column elements into a one-dimensional array called rowData
for (i in data) {
var rowData = data[i];
var emailAddress = rowData[2];
var poster = rowData[7];
var subject = rowData[3];
var recipName = rowData[6];
var comment = rowData[4];
var replyLink = rowData[5];
//
//
var message = 'Dear ' + recipName + ',\n\n'+poster+' has posted the
following comment directed to you: '+'\n'+comment+'\n\n'+'To reply to this
comment click: '+replyLink;
var subject = subject;
if(emailAddress)
{
MailApp.sendEmail(emailAddress, subject, message);}
}
}
As mentioned in the question comments, you want to use the event object available to the on form submit trigger. This can be accessed from a container-bound script on either the form or its responses spreadsheet, simply by adding a parameter to the function that receives the trigger.
This object is of the form:
e: {
authMode: <enum>,
namedValues: {
'q1title': [ <q1string> ],
'q2title': [ <q2string> ],
...
},
range: <Range>,
triggerUid: <string>,
values: [<q1string>, <q2string>, ...]
}
Using this object means that accessing of the Spreadsheet, for the purposes of emailing someone based on contents of the form, is unnecessary.
function MessageNotification(e) {
if(!e) return; // No form event object was provided.
var responses = e.namedValues;
var emailQTitle = /* the title of the question that asks for the email */;
// Check that 1) this question exists in the response object, and also
// 2) it has an answer with a value that 3) is "truthy".
// https://developer.mozilla.org/en-US/docs/Glossary/Truthy
if(responses[emailQTitle] // 1
&& responses[emailQTitle].length // 2
&& responses[emailQTitle][0]) // 3
{
var emailAddress = responses[emailQTitle][0];
/* access the responses variable in a similar manner
for the other variables needed to construct the email */
MailApp.sendEmail(emailAddress, ... );
} else {
/* There was no response to the email question. */
// You can use View->Stackdriver Logging to inspect the form response, for
// example, to make sure that it had the format or values you expected.
console.log({form_object: e, responses: responses, emailTitle: emailQTitle});
}
}

I am working on this code to update google contacts with google forms and spreadsheet linked to it

I want this code to auto add contacts using trigger when form is submit but i get errors.
The code works properly with spreadsheet but I am not able get it work with forms.
I am kind of noob with coding.
So simple explanation would be helpful
Also contacts get add to "other" group in google contacts,is there any way to add them directly to "my contacts"?
function createHeaders() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// Freezes the first row
sheet.setFrozenRows(1);
// Set the values we want for headers
var values = [
["First Name", "Last Name", "Email", "Phone Number", "Company", "Notes"]
];
// Set the range of cells
var range = sheet.getRange("A1:F1");
// Call the setValues method on range and pass in our values
range.setValues(values);
}
function createContact() {
var alreadyAdded = "Already added";
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:G3
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var firstName = row[0]
var lastName = row[1]
var emailAddress = row[2]
var phone = row[3]
var company = row[4]
var notes = row[5]
var addedAlready = row[6];
if (addedAlready != alreadyAdded) {
// Create contact in Google Contacts
var contact = ContactsApp.createContact(firstName, lastName, emailAddress);
// Add values to new contact
contact.addCompany(company, "");
contact.addPhone(ContactsApp.Field.WORK_PHONE, phone);
contact.setNotes(notes);
sheet.getRange(startRow + i, 7).setValue(alreadyAdded);
};
};
};
I was able to reproduce the error by passing one or more empty strings as arguments to the createContact() method:
var contact = ContactsApp.createContact("", "", "");
Check the values in your data array by logging them to see if you've got any empty strings there. You can wrap the code in a try block the prevent errors from stopping program execution. Any errors will be logged in a catch block
try {
var contact = ContactsApp.createContact(a, b, c);
}
catch(error) {
Logger.log(error);
}
I see you're trying to connect your Spreadsheet to Google Form. Check the Connecting to Google Forms
Apps Script allows you to connect Google Forms with Google Sheets
through Forms and Spreadsheet services. This feature can automatically
create a Google Form based on data in a spreadsheet. Apps Script also
enables you to use triggers, such as onFormSubmit to perform a
specific action after a user responds to the form.
you might be referring to onFormSubmit.
Here's the code demo for your reference.

Getting a script to trigger when only a specific form is submitted - Google Script / Sheets / Forms

I feel like this should be so easy and obvious, but I cannot figure it out...
I am working with 2 forms and 2 spreadsheets. Form 1 submits to Sheet 1. On Sheet 1, for each record, there is a link that takes the user to Form 2, which is half pre-populated with data from Sheet 1. When the user submits Form 2, it populates Sheet 2.
I have a couple of scripts that are supposed to be triggered when Form 1 is submitted. I am using the "From Spreadsheet" "OnFormSubmit" trigger. The scripts, however, are also triggering when Form 2 is submitted.
How can I make it so the scripts only execute when Form 1 is submitted? Also, is there a way to ensure that scripts trigger in a specific order?
If it helps, the scripts are below. They all work properly as is, except for the triggering issue. I know that I can merge the 2nd and 3rd script, and I will, but I'd like to fix this triggering issue first, as I'm getting double the emails every time I test.
1st script:
function onFormSubmit(e) {
//Uses time in milleseconds to create unique ID #
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("ComplaintLog");
var d = new Date();
var n = d.getTime();
var lastRow = sheet.getLastRow();
var cell = sheet.getRange("BA" + lastRow);
cell.setValue(n);
var cell = sheet.getRange("BB" + lastRow);
cell.setFormula("=right(BA"+lastRow+",6)");
sheet.getRange("BB"+lastRow).copyTo(sheet.getRange("BC"+lastRow), +
{contentsOnly:true});
}
2nd script:
function formSubmitReply(e) {
//Sends email to certain users when a new complaint has been entered
var emailAddresses = 'person#organzation.com';
MailApp.sendEmail(emailAddresses,
"person#organzation.com",
"New Guest Complaint",
"A new guest complaint has been entered into the database."
+ "\n\n To vew the database, click here: http://goo.gl/DI33EC");
}
3rd script:
function createResolutionForm() {
var ss = SpreadsheetApp.getActive()
var sheet = ss.getSheetByName("ComplaintLog")
var lastRow = sheet.getLastRow();
var data = ss.getSheetByName("ComplaintLog") +
.getRange("A"+lastRow+":Z"+lastRow).getValues();
var form = FormApp.openById('The form's ID goes here. that part works.');
var items = form.getItems();
for (var i = 0; i < data.length; i++) {
var formResponse = form.createResponse();
//ID
var formItem = items[1].asTextItem();
var response = formItem.createResponse(data[i][0]);
formResponse.withItemResponse(response);
//Guest Name
var formItem = items[2].asTextItem();
var response = formItem.createResponse(data[i][3]);
formResponse.withItemResponse(response);
//email
var formItem = items[3].asTextItem();
var response = formItem.createResponse(data[i][4]);
formResponse.withItemResponse(response);
// The pre-populated form is being created here. I didn't include every
// form item for brevity's sake.
}
//Create Link
var formUrl = formResponse.toPrefilledUrl();
//Enable Clickable ID
var idNum = sheet.getRange("BC"+lastRow).getValues();
sheet.getRange("A"+lastRow).setFormula +
('=HYPERLINK("' + formUrl + '","' + idNum + '")');
var sheetUrl = "The URL to the spreadsheet goes here - that part works.";
//Send Email to assigned managers
var j,tempname=[],name, subject, managername, message;
managername = sheet.getRange("P"+lastRow).getValue();
tempname=managername.split(" ");
Logger.log(managername)
if (tempname.length==2) {
name=tempname[0].slice(0,1) + tempname[1] + '#organization.com';
subject = 'Action Required';
var message = "<html><body>"
+ "<p> You have been assigned to follow-up on a complaint,"
+ "or your contact information has been given to a customer in"
+ "regards to a complaint."
+ "<p><p>The complaint ID number is " + idNum +"."
+ "<p>To go directly to this complaint,"
+ "<b>click here</b>."
+ "<p>To vew the database so that you can take action,"
+click here."
+ "</body></html>";
MailApp.sendEmail(name, subject,"",{htmlBody : message});
}
}
Setting up the triggers from within the script might be what you're looking for. You can create triggers that respond to form submission events on a per-form basis like so:
function setup () {
ScriptApp.newTrigger('onForm1ResponseHandler').forForm(form1).onFormSubmit().create();
ScriptApp.newTrigger('onForm2ResponseHandler').forForm(form2).onFormSubmit().create();
}
where form1 and form2 are Form objects and 'onForm1ResponseHandler' is the name of the handler function.
With a handler function set up like this:
function onForm1ResponseHandler (e) {
...
}
e will be an object with properties documented here (for the Form Submit event).

Send email from google spreadsheet

I found the following script to insert form submission values into a google spreadsheet.
function doPost(e) { // change to doPost(e) if you are recieving POST data
var ss = SpreadsheetApp.openById(ScriptProperties.getProperty('active'));
var sheet = ss.getSheetByName("DATA");
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]; //read headers
var headers2 = sheet.getRange(2, 1, 1, sheet.getLastColumn()).getValues()[0]; //read headers
var nextRow = sheet.getLastRow(); // get next row
var cell = sheet.getRange('a1');
var col = 0;
for (i in headers2){ // loop through the headers and if a parameter name matches the header name insert the value
if (headers2[i] == "Timestamp"){
val = new Date();
} else {
val = e.parameter[headers2[i]];
}
cell.offset(nextRow, col).setValue(val);
col++;
}
//http://www.google.com/support/forum/p/apps-script/thread?tid=04d9d3d4922b8bfb&hl=en
var app = UiApp.createApplication(); // included this part for debugging so you can see what data is coming in
var panel = app.createVerticalPanel();
for( p in e.parameters){
panel.add(app.createLabel(p +" "+e.parameters[p]));
}
app.add(panel);
return app;
}
//http://www.google.sc/support/forum/p/apps-script/thread?tid=345591f349a25cb4&hl=en
function setUp() {
ScriptProperties.setProperty('active', SpreadsheetApp.getActiveSpreadsheet().getId());
}
Now I want to send a formatted email to two of my coworkers every time a row gets inserted. I tried to use:
var emailAddress = "email#gmail.com"; // First column
var message = "message"; // Second column
var subject = "Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
but it's not sending anything.. can anyone advise please?
I had the same trouble.
With the most recent version of Google Apps I had to save the script, create a new revision, and re-publish the script making sure to select the new revision. After this the new code was in effect. I wasted several hours in the belief that the script would be updated if I just saved it.
Somehow the new method saves the script elsewhere. It's almost impossible to tell what code is actually running unless you go through the process of saving a revision, and re-publishing.