Google App Script Grouping data in sheet to email - email

I have an action item Google sheet with these columns:
A - ID - a serial # 1, 2, 3, etc.
B - Assigned - date the action item was assigned
C - Product - short text name of the project or area
D - Action Item - text description of the action item
E - Owner - who is the item assigned to, this is usually just a name
like Bob L, or sometimes multiple people Bob/Ted
F - Due Date
G - Status - Pending, In process, etc.
H - Last Updated - updated by onEdit script
I - Last Edited By - updated by onEdit script
J - Owner Email - vlookup to data range to get email address(s) of
owner(s)
K - Last Reminder Sent - date of the last email sent updated by
script
I'm a total newbie with GAS so I've cobbled together snippets to get the script to send 1 email to the owner for each action item but I want to group the action items by column E (Owner) and send one email. I know I need a nested loop but I'm not sure how to proceed.
The format of the resulting email would need to be a table of columns A, B, D, F, G (at least). The current script is below:
SCRIPT
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 3; // First row of data to process
//var numRows = 12; // Number of rows to process *CHANGE AS NEEDED*
//var numItems = getRowsData(sheet, OpenItems);
var numItems = SpreadsheetApp.getActiveSheet().getRange("OpenItems").getValues();
var numRows = numItems[0]
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 11) // must encompass Column K (11)
// 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 actionitemid = row[0];
var assignedon = Utilities.formatDate(new Date(row[1]), "GMT-05:00", "MM/dd/yy");
var assignedto = row[4];
var project = row[2];
var actionitem = row[3];
var duedate = Utilities.formatDate(new Date(row[5]), "GMT-05:00", "MM/dd/yy");
if (duedate == "12/31/69") { // no due date
var duedate = "TBD - please update!!" ;}
var status = row[6];
var emailAddress = row[9]; // Column J = 9 (starts at A=0
var subject = "Action Item Reminder - Project: " + project;
var sheetURL = SpreadsheetApp.getActiveSpreadsheet().getUrl();
var body = "A reminder to do the following:\n\n Project: "+project + "\n Due: "+duedate+"\nAssigned: "+assignedon+"\n Owner: "+assignedto+"\n Status: " + status + "\n\nACTION ITEM: "+actionitemid+"\n=============================\n"+actionitem+"\n=============================\n\nPlease advise if you will not meet the due date ASAP.\n\nAll action items can be found in the Action Item sheet:\n"+sheetURL+".";
var emailSent = row[11]; // Column D = 3
// if (oktosend == "Y") { // Send only for marked rows
var ok = emailAddress.length
if ( emailAddress.length > 0) {
// Send email
// MailApp.sendEmail(emailAddress, subject, body);
// MailApp.sendEmail(emailAddress, "TEST", body);
MailApp.sendEmail({
to: emailAddress,
cc: "rdeloach#rentpath.com",
subject: subject,
body: body
});
// Update EmailSent
var time = new Date();
time = Utilities.formatDate(time, "GMT-05:00", "MM/dd/yy, hh:mm");
sheet.getRange(startRow + i, 11).setValue(time); // Use column for EmailSent + 1 here getRange(startRow + i, X)
// Update oktosend to N
// sheet.getRange(startRow + i, 5).setValue('N'); // Use column for oktosend + 1 here getRange(startRow + i, X)
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
} //oktosend<>N
}
}
OUTPUT/RESULT
​Subject: Action Item Reminder - Project: Project X
A reminder to do the following:
Project: Project X
Due: 3/1/14
Assigned: 02/01/14
Owner: Rick D
Status: Pending
ACTION ITEM: 1
~~~~~~~~~~~~~~~~~~~~~~~
Provide the data requirements for the new database tables on project X.
~~~~~~~~~~~~~~~~~~~~~~~
Please advise if you will not meet the due date ASAP.
All action items can be found in the Action Item sheet:
END OUTPUT
Looking for help on the grouping and producing a table in Gmail.

You can put the table in the body of the message and then send it through the GmailApp service instead of MailApp.
var body = '<table><tr><td>col</td><td>val</td></tr></table>';
GmailApp.sendMail('to#example.com', 'subject', '',
{ cc: 'cc#example.com',
htmlBody: body
});

Related

Apps Script: Send email - Script sends 1 email per row instead of one email with all the info that meets the criteria

Newbie looking for some help... I can't understand what is going wrong in this script!
I am using a sheet similar to this one. My objective is to send and email to a specific address whenever certain conditions are met.
The conditions are Col R (Yesterday = 1) & Col D (Status) is different than "Resgate".
This is the output I am getting from my script. If 2 rows meet these conditions, then I get an email with the first row that meets conditions, and then another email with the first and second row that meets conditions. If there where 5 rows that meet conditions, I would receive 5 emails, and in the last one, I would have all the rows that meet conditions.
What I want to achieve is to receive only the final email with all the rows that meet conditions and avoid receiving the other ones.
Email 1
Email 2
This Is the code I am using
function SENDMAIL() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// set active sheet to Sheet by name
spreadsheet.setActiveSheet(spreadsheet.getSheetByName("Sheet 1"));
var sheet = spreadsheet.getActiveSheet();
// figure out what the last row is
var lastRow = sheet.getLastRow();
var startRow = 2;
// grab all data from user to days left
var range = sheet.getRange(startRow, 1, lastRow - startRow + 1, 19);
var values = range.getValues();
var users1 = [];
var users2 = [];
var users3 = [];
var users4 = [];
var users5 = [];
var users6 = [];
// loop all data per row
values.forEach(function(row) {
if (row[17] == 1 && row[3] !== "Resgate") {
// add user if 4 or more days left
users1.push(row[3]);
users2.push(row[4]);
users3.push(row[5]);
users4.push(row[16]);
users5.push(row[15]);
users6.push(row[14]);
// if users has elements
var message = "<html><body></h1><p><b>New Requests</font2></h1>";
var names = "<ul>";
users4.forEach(function(user, i) {
names += `<p><b><li>${user} -> ${users1[i]} - ${users3[i]} - ${users2[i]} - ${users5[i]} - ${users6[i]}€ `;
});
names += "</ol>"
message = message + names + "</body></html>";
var flexmails = "Example#gmail.com";
MailApp.sendEmail(flexmails, "NEW PPR's", "", {
htmlBody: message,
noReply: true
});
} else {}
})
}
Simply move sendEmail out from the values.forEach loop and put it at the end of the script
MailApp.sendEmail(flexmails, "NEW PPR's","", { htmlBody: message, noReply: true });
values.forEach(function(row) {
if (row[17] == 1 && row[3] !== "Resgate") {
// add user if 4 or more days left
users1.push(row[3]);
users2.push(row[4]);
users3.push(row[5]);
users4.push(row[16]);
users5.push(row[15]);
users6.push(row[14]);
}
});
// if users has elements
var message = "<html><body></h1><p><b>New Requests</font2></h1>";
var names = "<ul>";
users4.forEach(function(user, i) {
names += `<p><b><li>${user} -> ${users1[i]} - ${users3[i]} - ${users2[i]} - ${users5[i]} - ${users6[i]}€ `;
});
names += "</ol>"
message = message + names + "</body></html>";
var flexmails = "Example#gmail.com";
MailApp.sendEmail(flexmails, "NEW PPR's", "", {
htmlBody: message,
noReply: true
});

I want to use the content of a cell in a google sheet to control whether to send an e-mail out or not

I have a spreadsheet for recording customer samples. A column [I] is used to calculate when the original entry date is over a certain period which then displays an overdue message using an if statement. I want to trigger a script to check this column daily and if 'overdue' is found to send an email to an address contained in another column [C]. I am also using another column [J] to return a message when an email has been sent. I am using the script below but am returning errors
The script marks all rows in column J with the sent email message
I appear to be collecting a bigger array of data have needed [adding two rows the the bottom]
Anyone any ideas?
//Setup the function
function autoMail () {
var ss = SpreadsheetApp.getActiveSpreadsheet(); //Get the active spreadsheet
var sheet = ss.getSheetByName( 'TS_Requests' ); //Get the active spread
var startRow = 3; // Start of row that going to be process considering row 2 is header
var lastRow = sheet.getLastRow(); // Get the last row of data to be process
var lastColumn = sheet.getLastColumn(); // Get the last column of data to be process
var range = sheet.getRange(startRow,1,lastRow,lastColumn); //Getting the specific cell to be process
var data = range.getValues(); // Get the values inside the cell
for(var i=0;i<data.length;++i){
var row = data[i];
var email = row[2]; // Grab the email column. C in this case
var customer = row[3]; // Grab data for Email body
var item = row[5]; // Grab data for Email body
var description = row[6]; // Grab data for Email body
var status = row[8]; // Grab the column containing the value needed to be checked.
var EmailSent = row[9]
if (EmailSent != 'Email_Sent') { //Prevents e-mail being sent in duplicate
if(valstatus ='Overdue'){ // Check the values, if it's what's needed, do something
MailApp.sendEmail(email, 'Your sample request is overdue', customer + ' - ' + item + ' - ' + description); // if condition is met, send email
sheet.getRange(startRow + i, 10).setValue('Email_Sent');
}
}
}
}

Send email only when first two columns are filled in

I currently have this script working so that when the last row is edited it sends an email with the contents of the first two columns from that row. My issue is that if info is entered into any column of the last row then a blank email gets sent. I've tried a combination of if statements to get the result I want but either end up with the script working as it currently is, or not working at all.
// This function grabs the last row of a inventory sheet and sends the updated range to a specified recipient using a onEdit trigger
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// If edit is not made on "Iventory" sheet then function does not proceed
if (sheet.getSheetName() != "Inventory") return;
// Get last row of sheet
var lastRow = sheet.getLastRow();
// Get range of last row
var lastCell = sheet.getRange(lastRow, 1, 1, 2);
// Fetch values for each row in the Range.
var data = lastCell.getValues();
//empty string
var message =""
//Loop through each row and form CSV data
for (var i = 0; i < data.length; i++) {
var row = data[i];
message = message + row[0] + "-" +row[1] + "\n";
}
// Send one email with all the rows
var subject = "Inventory update";
MailApp.sendEmail("test#test.com", subject, message);
}
try this:
var send=true;
for (var i=0;i<data.length;i++) {
var row = data[i];
message = message + row[0] + "-" +row[1] + "\n";
if(!row[0] || !row[1]){
send=false;
break;
}
}
// Send one email with all the rows
var subject = "Inventory update";
if(send){
MailApp.sendEmail("test#test.com", subject, message);
}

How to send e-mails automatically from a sheet as it updated?

I posted this question on Google Sheets forum and was directed here for help.
*Please note that I am not a coder, I've just started working with things like this.
I've created a workbook with 3 pages. It's connected to a form, so as people submit their reviews the answers are collected on the first sheet, calculated on the second sheet, and any submission with an overall score higher than 3.9 has the email address moved to the third sheet where it will be sent a follow-up email.
Here is a link to a copy of the sheet:
https://docs.google.com/spreadsheets/d/15p7_M4guRWCVHG-acRAheAROmh9t4wk3GWD_x0_rl90/edit?usp=sharing
It all works except the last page: I cannot figure out how to get the emails to send automatically as the sheet is updated. I've set the trigger to have it run when the sheet is updated, but to no avail - I have to manually go in and click the "Run" button to have the emails sent. (When I do, it pops up 'Failed to sent email: no recipient (line 21, file "Code")' but the emails are successfully delivered anyway.)
The formula I am using is this: (I have also tried swapping "sendEmails2" with "autoResponder" but that didn't change anything either.) Can anyone tell me what is wrong with it? Or is there a better way to automatically send the e-mails?
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 20000; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 3)
// 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 emailAddress = row[0]; // First column
var message = row[1]; // Second column
var emailSent = row[2]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is
interrupted
SpreadsheetApp.flush();
}
}
}
This should do it:
function sendEmails2(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Automatic Emails');
var rg=sh.getRange(2,1,sh.getLastRow(), 3);
var vA=rg.getValues();
for (var i=0;i<vA.length;i++){
var emailAddress = vA[i][0];
var message = vA[i][1];
var emailSent = vA[i][2];
var subject = "Sending emails from a Spreadsheet";
if(emailSent != 'EMAIL_SENT'){
MailApp.sendEmail(emailAddress, subject, message);
sh.getRange(2 + i,3).setValue('EMAIL_SENT');
}
}
}
Don't forget the onFormSubmit:

Google script: email with answers given by a single user to a form compiled in google drive

I've created a form using google drive.
In order to provide to answerers a summary of what they wrote I would like to send an email to each of them, using the email they insert in the form.
I think it is possible to do this installing a script in the spreadsheet of the form result that send an email every time a new row is recorded.
I've found (on this forum) the following script that is, unfortunately, an email alert with a modify in a certain spreadsheet.
function sendNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = ss.getActiveCell().getA1Notation();
var row = sheet.getActiveRange().getRow();
var cellvalue = ss.getActiveCell().getValue().toString();
var recipients = "me#gmail.com";
var message = '';
if(cell.indexOf('G')!=-1){
message = sheet.getRange('D'+ sheet.getActiveCell().getRowIndex()).getValue()
}
var subject = 'Update to '+sheet.getName();
var body = sheet.getName() + ' has been updated. Visit ' + ss.getUrl() + ' to view the changes on row: «' + row + '». New comment: «' + cellvalue + '». For message: «' + message + '»';
MailApp.sendEmail(recipients, subject, body);
};
And here is the help I need. The script sends an email to a single predefined address. Is it possible to let the script take the recipient email from a certain cell in the relevant row (for example the email is recorded in the col C of the spreadsheet) and send him a message that contains some text taken by other cells of the same row ( for example col D and E)?
Using the variables you defined in your code (sheet, row):
//returns email address in column C
var recipient = sheet.getRange(row, 3).getValue();
//returns values in column D and E
var info1 = sheet.getRange(row, 4).getValue();
var info2 = sheet.getRange(row, 5).getValue();
Please be aware that this is an 'expensive' way to get the values and you would better served getting all values as an array in one call and then referencing them by index, as below.
//get all required values in one call
var values = sheet.getRange(row, 3, 1, 3).getValues();
//define variables using array index
var recipients = values[0];
var info1 = values[1];
var info2 = values[2];