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});
}
}
Related
This is the extended version of my previous question.
I want to send email once in a week to the recipients based on the status column.
Sheet Link: https://docs.google.com/spreadsheets/d/1GC59976VwB2qC-LEO2sH3o2xJaMeXfXLKdfOjRAQoiI/edit#gid=1546237372
The previous code is attached in the sheet.
From the sheet, When the Status column will be new and ongoing, a table will be generated with column Title, Link and due date and send a single email to the recipients even they are repeated.
In the sheet, For resource Anushka, Status New appeared twice and Ongoing once. The table will be like-
Anushka || New || 10/25/2022
Anushka || New || 10/25/2022
Anushka || Ongoing || 10/25/2022
And after creating it, it will send single email to each recipients though they have appeared several times.
I have done it for getting multiple emails whatever the status is with the help of another commenter from stackflow but I want to modify it and change it. The code for this one is a bit longer as I have two helper gs file, html table code and the main one. That's why I am not writing all the codes here. But in the sheet from the extension, one can see my code.
If anyone give me suggestions how to change or modify the logic, it will be appreciated.
Code
function macro(){
// get range of cell with data from A1 to any cell near having value (call data region)
var table = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3").getRange("A1").getDataRegion();
var header=table.getValues()
var resource=header[0][1]
var status_r=header[0][3]
var due_date_r=header[0][5]
var link_r=header[0][10]
// create custom table filtered by the column having header "State" where the value match "New"
var filterTable = new TableWithHeaderHelper(table)
.getTableWhereColumn("Status").matchValueRegex(/(New)/);
// for each row matching the criteria
for(var i=0; i< filterTable.length() ; i++){
// Get cell range value at column Mail
var mail = filterTable.getWithinColumn("Email").cellAtRow(i).getValue();
// Any other value of column Target Value
var resource_col = filterTable.getWithinColumn("Resource").cellAtRow(i).getValue();
var status_col = filterTable.getWithinColumn("Status").cellAtRow(i).getValue();
var due_date_col = filterTable.getWithinColumn("Due Date").cellAtRow(i).getValue();
var link_col = filterTable.getWithinColumn("Link").cellAtRow(i).getValue();
var new_data=[[resource_col,status_col,due_date_col,link_col]]
var htmltemplate=HtmlService.createTemplateFromFile("email")
htmltemplate.resource=resource
htmltemplate.status_r=status_r
htmltemplate.due_date_r=due_date_r
htmltemplate.link_r=link_r
htmltemplate.new_data=new_data
var htmlformail=htmltemplate.evaluate().getContent()
var subjectMail = "Automation Support Services Actions Items";
var dt1 = new Date()
var dt2 = due_date_col
// get milliseconds
var t1 = dt1.getTime()
var t2 = dt2.getTime()
var diffInDays = Math.floor((t1-t2)/(24*3600*1000));
// 24*3600*1000 is milliseconds in a day
console.log(diffInDays);
// Send email
MailApp.sendEmail({
to:mail ,
subject: subjectMail,
htmlBody:htmlformail,
});
}
}```
2 loops can make the job.
// get range of cell with data from A1 to any cell near having value (call data region)
var table = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3").getRange("A1").getDataRegion();
// init html header data
var header=table.getValues()
var resource=header[0][1]
var status_r=header[0][3]
var due_date_r=header[0][5]
var link_r=header[0][10]
var listOfEmails = [];
var tableWithHeader = new TableWithHeaderHelper(table)
// get all email
for(var i=0; i< tableWithHeader.length() ; i++){
var mail = tableWithHeader.getWithinColumn("Email").cellAtRow(i).getValue();
listOfEmails.push(mail)
}
// filter all email to get unique liste of email
var uniqueMailList = listOfEmails.filter((c, index) => {
return listOfEmails.indexOf(c) === index;
});
for(var i=0; i< uniqueMailList.length; i++){
// get mail of target i
var mail = uniqueMailList[i]
// filter table using mail of target i and status
var mailTable = new TableWithHeaderHelper(table)
.getTableWhereColumn("Status").matchValueRegex(/(New)/)
.getTableWhereColumn("Email").matchValue(mail);
// initialise html template
var htmltemplate=HtmlService.createTemplateFromFile("email")
htmltemplate.resource=resource
htmltemplate.status_r=status_r
htmltemplate.due_date_r=due_date_r
htmltemplate.link_r=link_r
var new_data = []
var htmlformail
// loop into the filtered table of target i only
for(var j=0; j< mailTable.length() ; j++){
// Any other value of column Target Value
var resource_col = mailTable.getWithinColumn("Resource").cellAtRow(j).getValue();
var status_col = mailTable.getWithinColumn("Status").cellAtRow(j).getValue();
var due_date_col = mailTable.getWithinColumn("Due Date").cellAtRow(j).getValue();
var link_col = mailTable.getWithinColumn("Link").cellAtRow(j).getValue();
new_data.push([resource_col,status_col,due_date_col,link_col])
}
htmltemplate.new_data=new_data
htmlformail=htmltemplate.evaluate().getContent()
var subjectMail = "Automation Support Services Actions Items";
var dt1 = new Date()
var dt2 = due_date_col
// get milliseconds
var t1 = dt1.getTime()
var t2 = dt2.getTime()
var diffInDays = Math.floor((t1-t2)/(24*3600*1000));
// 24*3600*1000 is milliseconds in a day
console.log(diffInDays);
// Send email
MailApp.sendEmail({
to:mail ,
subject: subjectMail,
htmlBody:htmlformail,
});
}
I'm not confident on the new_data.push([resource_col,status_col,due_date_col,link_col]), it's seems to be corect but I have no no way to verify that
Anyway thanks for using the utils script at https://github.com/SolannP/UtilsAppSsript, glad to see it help 👍
I'm new to Google Apps script and am trying to add an image inline to an automated response email.
The auto reply works perfectly, the main text of the email formats well in plain text and html.
the problem i'm facing is that the image does not appear.
my code:
// This constant is written in column Y for rows for which an email
// has been sent successfully.
var EMAIL_SENT = 'EMAIL_SENT';
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(sheet.getSheetByName('Data'))
var startRow = 2; // First row of data to process
// Fetch the range
var dataRange = sheet.getRange("L2:L1000")
var dataRange2 = sheet.getRange("K2:K1000")
var dataRange3 = sheet.getRange("O2:O1000")
var dataRange4 = sheet.getRange("Y2:Y1000")
var dataRange5 = sheet.getRange("B2:B1000")
// Fetch values for each row in the Range.
var data = dataRange.getValues();
var data2 = dataRange2.getValues();
var data3 = dataRange3.getValues();
var data4 = dataRange4.getValues();
var data5 = dataRange5.getValues();
for (var i = 0; i < data.length; ++i) {
var yesno = data2[i]
if(yesno == "Yes"){
var TFlogoUrl = "https://drive.google.com/openid=1nzmvP_zzOms1HiBoFCsVLFjDM6ZzM287";
var TFlogoBlob = UrlFetchApp
.fetch(TFlogoUrl)
.getBlob()
.setName("TFlogoBlob");
var emailAddress = data[i];
var ShipID = data3[i];
var cmdrID = data5[i];
var TFmsg = "Hi " + cmdrID + ",/n /nThank you for signing up to The Fatherhoods Lost Souls Expedition./n /nYour unique Ship ID is: " + ShipID + "/n /nWe look forward to seeing you on the expedition CMDR!/n /nFly Safe,/nThe Lost Souls Expedition team.";
var htmlTFmsg = "Hi " + cmdrID + ",<br> <br>Thank you for signing up to The Fatherhoods Lost Souls Expedition.<br> <br>Your unique Ship ID is: " + ShipID + "<br> <br>We look forward to seeing you on the expedition CMDR!<br> <br>Fly Safe,<br>The Lost Souls Expedition team.<br><img src='cid:TFlogo'>";
emailSent = data4[i]; // email sent (column Y)
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Lost Souls Expedition Sign up confirmation";
MailApp.sendEmail(emailAddress,subject,TFmsg,{
htmlBody: htmlTFmsg,
inlineImage:
{
TFlogo:TFlogoBlob
}
});
sheet.getRange("Y" + (startRow + i)).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
}
How about this modification?
Modification points:
You cannot retrieve the file blob from this URL var TFlogoUrl = "https://drive.google.com/openid=1nzmvP_zzOms1HiBoFCsVLFjDM6ZzM287";. If you want to retrieve the file blob from URL, please use var TFlogoUrl = "http://drive.google.com/uc?export=view&id=1nzmvP_zzOms1HiBoFCsVLFjDM6ZzM287";. 1nzmvP_zzOms1HiBoFCsVLFjDM6ZzM287 is the file ID.
As an another method, from the file ID, it is found that the values of getSharingAccess() and getSharingPermission() are ANYONE_WITH_LINK and VIEW, respectively. So you can also retrieve the blob using var TFlogoBlob = DriveApp.getFileById("1nzmvP_zzOms1HiBoFCsVLFjDM6ZzM287").getBlob().setName("TFlogoBlob");. I recommend this.
When you want to use the inline image to email, please modify from inlineImage to inlineImages.
The script which reflected above points is as follows.
Modified script:
Please modify your script as follows.
From:
var TFlogoUrl = "https://drive.google.com/openid=1nzmvP_zzOms1HiBoFCsVLFjDM6ZzM287";
var TFlogoBlob = UrlFetchApp.fetch(TFlogoUrl).getBlob().setName("TFlogoBlob");
To:
var id = "1nzmvP_zzOms1HiBoFCsVLFjDM6ZzM287";
var TFlogoBlob = DriveApp.getFileById(id).getBlob().setName("TFlogoBlob");
And
From:
inlineImage: {TFlogo:TFlogoBlob}
To:
inlineImages: {TFlogo:TFlogoBlob}
References:
sendEmail(recipient, subject, body, options)
If I misunderstand your question, please tell me. I would like to modify 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.
I'm trying to create a script that will take a new form response and move it to another sheet based on the information submitted. For example, let's say the form has two answer choices A, B. The spreadsheet has three sheets; Form Responses, Sheet A, Sheet B. If someone submits the form and selects A, I need that new row to be moved from "Form Responses" to "Sheet A." I found someone else's script that does exactly this but using the OnEdit function. I cannot figure out how to modify this script to work when a new form response is submitted.
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Form Responses" && r.getColumn() == 2 && r.getValue() == "A") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Sheet A");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
I used the installable triggers and replaced the OnEdit function with onFormSubmit but that doesn't work. I'd really appreciate it if anyone could help me with this.
Thanks,
To achieve what you want, you will need to:
Create a function write_to_new_sheet that we'll use in a trigger function whenever a new response hits the form. This function will take the form response as an event object e:
function write_to_new_sheet(e){
let responses = e.response.getItemResponses()
let new_row = get_new_response_data_as_row(responses)
let sheet_to_write = SpreadsheetApp.openById('your spreadsheet id').getSheetByName('sheet A') // or 'sheet B', you can set this dynamically by checking the new_row, corresponding to the response as a gsheet row
write_values_in_first_row(sheet_to_write, new_row)
}
this are the auxiliary functions to write_to_new_sheet:
function get_new_response_data_as_row(responses){
let new_row = []
responses.forEach(response => {
new_row.push(response.getResponse())
})
return new_row
}
function write_values_in_first_row(sheet, new_row_values){
let row_to_write_from = 2 // assuming you have a header
let sheet_with_new_row = sheet.insertRowBefore(row_to_write_from)
let number_of_rows = 1
let number_of_columns = new_row_values.length
let range = sheet_with_new_row.getRange(row_to_write_from, 1, number_of_rows, number_of_columns)
let results =range.setValues([new_row_values])
return new_row_values
}
Set up an installable trigger that works whenever you submit a new response to the form:
function setup_write_to_new_sheet_on_form_submit(){
ScriptApp.newTrigger('write_to_new_sheet')
.forForm('your form id goes here')
.onFormSubmit()
.create();
}
Run the above function once, to set up the trigger.
try submitting a new response on the form, and check the changes in the sheets you want it to be written.
Try something a little less broad in your comparing of variables,, For instance the sheet that submissions are sent to is a constant and already address.
function formSubmission() {
var s = SpreadsheetApp.getActiveSheet();
var data = range.getValues(); // range is a constant that always contains the submitted answers
var numCol = range.getLastColumn();
var row = s.getActiveRow;
var targetinfo = s.getRange(row,(Yourcolumn#here).getValue);
if(targetinfo() == "Desired Sheet Name") {
var targetSheet = ss.getSheetByName("Sheet A");
var targetrow = targetSheet.getLastrow()+1);
var Targetcol = numCol();
targetSheet.getRange(targetrow,1,1,Targetcol).setValues(data);
}
}
I didn't test that but hopefully it helps look up Event Objects in the developer guide i just recently found it and it clarifies a lot
the triggers can be set by going to:
then set it:
I have a spreadsheet that collects the form submissions and then has extra sheets that have filtered out these submission based on the answers. All this is just with formulas. Could that do the trick also?
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.