I have this code to send Google Form responses to email.
function sendFormByEmail(e) {
Logger.log("e: " + e);
var email = "email#gmail.com";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
var subject = "New Hire Form Submission: ";
for(var i in headers)
message += headers[i] + ': '+ e.namedValues[headers[i]].toString() + "\n\n";
// Insert variables from the spreadsheet into the subject.
// This creates an email subject like "New Hire: Jane Doe - starts 4/23/2013"
subject += e.namedValues[headers[2]].toString() + " - starts " + e.namedValues[headers[15]].toString();
// Send the email
MailApp.sendEmail(email, subject, message);
}
This is tied to the spreadsheet not the form and e is returning undefined. I saw someone else have this issue and disabling the new Chrome V8 worked for them but is not working for me.
trigger settings
By the time the function is called, the data is already in the spreadsheet, so you could just read the last now
var row = SpreadsheetApp.getActiveSheet().getLastRow();
var columns = s.getLastColumn()
var range = s.getRange(row, 1, 1, columns).getValues();
Related
As of two days ago a script that was embedded in a google spreadsheet that ran without fail for years has suddenly started failing with the following error:
TypeError: Cannot read property 'toString' of undefined
at sendFormByEmail(Code:15:62)
The script itself is:
function sendFormByEmail(e){
var email = "myLNCF.testemail#gmail.com";
var subject = "Employee Call Out: \n" + e.namedValues["Employee's First and Last Name"] + "\nDept: \n" + e.namedValues["Employee's Department"];
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]].toString() + "\n\n";
MailApp.sendEmail(email, subject, message);
}
Any help is appreciated, as I am a very novice coder.
function sendFormByEmail(e){
var email = "myLNCF.testemail#gmail.com";
var subject = "Employee Call Out: \n" + e.namedValues["Employee's First and Last Name"] + "\nDept: \n" + e.namedValues["Employee's Department"];
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getDisplayValues()[0];
var message = "";
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]][0] + "\n\n";
MailApp.sendEmail(email, subject, message);
}
If you have changed the questions in the form that could also change which e.namedValues you want
I am trying to send an automatic email to my students with feedback on the coursework. I have developed a google form with the marking scheme where I enter the student number, but the script doesn't read the named values method.
I have tried to do one by one student numbers and the rest of the code it works.
The code is as follows:
function sendNotification(e){
var s = SpreadsheetApp.getActiveSheet();
var message = "";
var headers =s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
message += "This automated email includes the marks and feedback for
your Main report Assignment.\n\n";
var studentNumber = e.namedValues[headers[3]].toString();
Logger.log("column 3: " + studentNumber);
message += "Student Number: " + studentNumber + "\n\n";
var recipients = studentNumber + "#email.com";
var subject = "Test Email";
MailApp.sendEmail(recipients, subject, message);
}
I want to be able to gather the student email from the google form, that is already saved in column 3 of the spreadsheet that is attached to the form.
Sorry my answer is a little rushed as I am literally leaving. (As is my code.) Normally don't do this, but since you are a teacher willing to make an exception.
Hope the below code helps. (This is how I would accomplish the task you are trying to do.)
function helpingTheTeacher() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("YOUR_SHEET_NAME_HERE");
var values = sheet.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
for (var i = 0; i < values.length; i++){
var timeStamp = values[i][0];
var studentName = values[i][1];
var studentNumber = values[i][2];
var studentGrade = values[i][3];
var message = "Hi " +studentName + " your grade is " +studentGrade + "."
var email = studentNumber + "#email.com";
var subject = "ALERT: MESSAGE FROM TEACHER!!!";
MailApp.sendEmail(email, subject, message)
}//END OF FOR LOOP
}//END OF FUNCTION
My code sends email notifications every time a Google Form is submitted. It works, but I want the collected form data as bold in the email.
for(var i in headers)
message += headers[i] + ': '+ e.namedValues[headers[i]].toString() + "\n\n";
function sendFormByEmail(e)
{
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1, 1, 1, s.getLastColumn()).getValues()[0];
var message = "";
var data = s.getRange(1, 1, 1, s.getLastColumn()).getValues()[0];
var subject = "";
//Get active Spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
//Get Sheet called 'Form responses 1'
var fr1 = ss.getSheetByName("Form responses 1");
//Get all emails from 'Emails' tab
var emails = ss.getSheetByName("Emails");
var numRows = emails.getLastRow();
var emailTo = emails.getRange(2, 2, numRows, 1).getValues();
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body.
for(var i in headers)
message += headers[i] + ': '+ e.namedValues[headers[i]].toString() + "\n\n";
// Insert variables from the spreadsheet into the subject.
// In this case, I wanted the part number as part of the
// email subject. These are the 3rd and 16th columns in my form.
// This creates an email subject like "Parts Inquiry Submission: 729302"
subject += e.namedValues[headers[1]].toString();
// Send the email
MailApp.sendEmail(emailTo, subject, message);
// Based off of a script originally posted by Amit Agarwal - www.labnol.org
// Credit to Henrique Abreu for fixing the sort order
}
First of all, you must use the advanced parameter htmlBody in the 4th parameter of sendEmail() and you need to make the body parameter and empty string.
sendEmail(recipient, subject, body, options)
Code:
message = "<strong>" + message + "</strong>";//Wrap message in bold tags
var options = {
"htmlBody":message
}
// Send the email
MailApp.sendEmail(emailTo, subject, "",options);//Make email body empty string
Thank you all for your help. I ended up changing it up a bit. Here is what I ended up using.
function sendFormByEmail(e)
{
var message = "";
var subject = "";
var emailTo = "";
//Gets the active Spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
//Get Sheet called 'Form responses 1'
var fr1 = ss.getSheetByName("Form responses 1");
var headers = fr1.getRange(1,1,1,fr1.getLastColumn()).getValues()[0];
//Get all emails from 'Emails' tab
var emails = ss.getSheetByName("Emails");
var emailTo = emails.getRange(2, 2, emails.getLastRow()-1, 1).getValues().toString();
// For each column in the spreadsheet, add the column name and it's new entry as a line in the email
message = "<html>";
for(var i in headers)
message += headers[i] + ': <b>'+ e.namedValues[headers[i]].toString() + "</b><br><br>";
message += "</html>";
// Set the subject as the Item Number
subject = e.namedValues[headers[1]].toString();
// Send the email
MailApp.sendEmail({
to: emailTo,
subject: subject,
htmlBody: message
});
}
I am still learning the ropes here. Based on code suggested by other contributors, I put together a script to send reminder emails to consultants who record their time entries using a Google Form. The spreadsheet first imports calendar entries with all the Job information for each consultant. After the calendar entries are imported, if the consultant has not yet recorded their time entry, the following script will send them an email with a reminder to do so:
function sendReminder() {
var rmndrFrom = "XYZ, Inc.";
var myemail = "support#xyz.com";
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Pending");
var numRows = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
var dataRange = sheet.getRange(2, 1, numRows, lastCol); // row 1 is the header row
var sheetData = dataRange.getValues();
for (var i = 0; i < sheetData.length; ++i) {
var row = sheetData[i];
if (row[0]){
var jobNumb = row[0]; // Job Number
var conName = row[2]; // Consultant Name
var conMail = row[3]; // Consultant Email
var jobDate = row[4]; // Date
// format email string
var subject = "Time Entry Reminder: " + conName + " / Job " + jobNumb;
try {
var conMsgH = 'This is a reminder for you to record your time entry for Job #<strong>' + jobNum + '/' + jobDate + '</strong>';
// strip HTML for plain text message
var conMsgP = conMsgH.replace(/\<br\/\>/gi, '\n').replace(/(<([^>]+)>)/ig, "");
// send reminder to consultants
MailApp.sendEmail(conMail, subject, conMsgP, { htmlBody:conMsgH, name:rmndrFrom });
} catch (e) { // error handler
MailApp.sendEmail(myemail, "Error in sending reminder email.", e.message);
}
}
}
}
So basically, this script parses the Pending sheet, if column A has a Job Number, it will send a reminder email to the consultant with that Job Number. However, a single consultant may have several job numbers to their name. I would like the script to send a single email to each consultant with a list of the Job Numbers for which they have to record their time entries.
Thanks in advance for your kind help. Any suggestions on how to optimize the code will also be very much appreciated.
There are a number of ways that you can approach this. One way is to keep a sheet with the consultants emails, names and a list of their job numbers. Load this data into your script, a list of all job ids and the job info. Then filter the job ids based on the consultants list and build your email, or you could just send that list of numbers for a very short script.
Another way is to do all of that sorting per consultant in the code and send out the emails that way. This is the approach I've taken, and I've also made use of the iterative JS functions map, filter and reduce more details at MDN.
The code is posted below, but if you would like to take a look at it attached to a spreadsheet and commented (as well as the functions to build that extra sheet with just the consultants info on it) take a look here.
Below is my iteration of your function. I hope it is helpful for your situation:
var rmndrFrom = "XYZ, Inc.";
var myemail = "me#emailisawesome.com";
var subject = "Time Entry Reminder";
function sendReminder() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Pending");
var numRows = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
var sheetData = sheet.getRange(2, 1, numRows-1, lastCol).getValues();
var cons = sheet.getRange(2,3,numRows-1,1).getValues().reduce(flatten_).filter(getUniqueConsultants_);
cons.forEach(sendEmail_, sheetData);
}
function sendEmail_(consultant) {
var consultantsJobs = this.filter(getJobsForConsultant_, consultant);
var jobList = consultantsJobs.map(buildJobLine_).join("<br>");
try {
var conMsgH = "Hi " + consultant + ",<br>";
conMsgH += "This is a reminder for you to record your time entry for the following jobs:<br><br>";
conMsgH += jobList;
conMsgH += "<br><br>Thank you for your cooperation.";
var conMsgP = conMsgH.replace(/\<br\/\>/gi, '\n').replace(/(<([^>]+)>)/ig, "");
MailApp.sendEmail(consultantsJobs[0][3], subject, conMsgP, {htmlBody:conMsgH, name:rmndrFrom});
} catch (e) {
MailApp.sendEmail(myemail, "Error in sending reminder email.", e.message);
}
}
function buildJobLine_(job) {
return "Job #" + job[0] + " on " + Utilities.formatDate(job[4], Session.getTimeZone(), "MMM dd yyyy");
}
function getJobsForConsultant_(row) {
return row[2] == this;
}
function getUniqueConsultants_(v,i,a) {
return a.indexOf(v) == i;
}
function flatten_(a,b) {
return a.concat(b);
}
I must say that fooby's answer is far beyond my JS skills, I'm sure it will work nicely but I still feel like proposing something different (and simpler from my pov), just for the fun of it ;-)
The main difference with your original script is the sorting of the array that allowed me to detect duplicate names and threat it accordingly. The html composition could be far better for sure but that was not your main request.
Here is the code
function sendReminder() {
var rmndrFrom = "XYZ, Inc.";
var myemail = "support#xyz.com";
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Pending");
var initial = "Hi conName,<BR>This is a reminder for you to record your time entry for the following jobs : <BR><BR><table border = 1 cellpadding = 3 bgcolor='#FFFFBB'><TR><TD>";
var sheetData = sheet.getDataRange().getValues();// simplified code to get the data array
sheetData.shift();//skips the headers
sheetData.sort(function(x,y){
var xp = x[2];// sort on column 3 but you can change here...
var yp = y[2];// sort on column 3 but you can change here...
return xp == yp ? 0 : xp < yp ? -1 : 1;// sort ascending, eventually change here...
});
// Logger.log(sheetData);// sorted
var last = sheetData.length
var i = 1;//index 0 is handled outside the loop
var row = sheetData[0];
var subject = "Time Entry Reminder: " + row[2] + " / Job "
var conMsgH = initial
var msgComponent = makeline_(row)
subject += msgComponent[0]
conMsgH += msgComponent[1]
while (i<last){
if(sheetData[i][2]!=sheetData[i-1][2]||i==last-1){
sendData_(sheetData[i-1][3],sheetData[i-1][2],subject,conMsgH)
var subject = "Time Entry Reminder: " + sheetData[i][2] + " / Job "
var conMsgH = initial;
}
msgComponent = makeline_(sheetData[i])
subject += msgComponent[0]
conMsgH += msgComponent[1]
++i
}
}
function sendData_(conMail,conName,subject,conMsgH){
conMsgH = conMsgH.substr(0,conMsgH.length-8)+'</TABLE>'
conMsgH = conMsgH.replace('conName',conName)
var conMsgP = conMsgH.replace(/<\/tr>/ig, '\n').replace(/<br>/ig, '\n').replace(/(<([^>]+)>)/ig, "")
subject = subject.substr(0,subject.length-2);// remove the last '+ '
// Logger.log(subject)
// Logger.log(conMsgH)
Logger.log(conMsgP)
// Logger.log(conMail)
try{
// send reminder to consultants
MailApp.sendEmail(conMail, subject, conMsgP, { htmlBody:conMsgH, name:rmndrFrom });
} catch (e) { // error handler
// MailApp.sendEmail(myemail, "Error in sending reminder email.", e.message);
}
}
function makeline_(row){
var jobNumb = row[0]; // Job Number
var conName = row[2]; // Consultant Name
var conMail = row[3]; // Consultant Email
var descr = row[1]; // description
var FUS1=new Date(row[4]).toString().substr(25,6)+':00';// get timezone of this event, taking care of daylight savings
var jobDate = Utilities.formatDate(row[4], FUS1, "MMM dd yyyy # hh:mm aaa"); // Date
var subject = jobNumb+' + ';
var conMsgH = 'Job #'+jobNumb + '</TD><TD>' + jobDate + '</TD><TD>' + descr + '</TD></TR><TR><TD>';
return [subject,conMsgH];
}
EDIT : made some improvement in the mail format, used a table to show jobs & dates + removed some bugs ;-) (to be honest, I made this also for my personal use as I am having almost the same use case )
I created a form using google docs spreadsheet, and created a script that sends an email when the user fills the form:
function sendFormByEmail(e){
var email = "AAA";
var subject = "XXX";
var message = "";
for(var field in e.namedValues)
message += field + ' = '+ e.namedValues[field].toString() + "\n\n";
var advancedArgs = {replyTo:e.namedValues['E-mail'].toString()};
MailApp.sendEmail(email, subject, message, advancedArgs);
}
the script works,
but when it sends the email, data is not sorted as the fields of the form.
how can I modify my script to sort the values as they are in the Spreadsheet (form)?
You could get the columns order from the spreadsheet. Something like this:
function sendFormByEmail(e){
var email = "AAA";
var subject = "XXX";
var message = "";
var s = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]].toString() + "\n\n";
var advancedArgs = {replyTo:e.namedValues['E-mail'].toString()};
MailApp.sendEmail(email, subject, message, advancedArgs);
}
Naturally, you have to change the sheet name Sheet1 to your actual sheet name.
By the way, I have written a script that does this a lot more, maybe you want to check it out (if this is not only a programming exercise). It's called FormEmailer and you can find it in the Script Gallery and in its site.