I have a function that takes a table's range and then emails it every day. Currently it is set up to get a fixed range (G2:H38). The process currently works, but every day I send the email, I have a handful of blank cells that are also sent out. I am new to this and hoping someone can help me solve for this.
var rowData = data[i];
var emailAddress = "example#gmail.com";
var recipient = rowData[0];
var yesterdayDate = rowData[5];
var message1 = rowData[2] + yesterdayDate;
var message2 = rowData[3]
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = sh.getRange("G2:H38").getValues();
//var htmltable =[];
var TABLEFORMAT = 'cellspacing="2" cellpadding="2" dir="ltr" border="1" style="width:100%;display:table;max-width:400px;table-layout:fixed;font-size:10pt;font-family:arial,sans,sans-serif;border-collapse:collapse;border:1px solid #ccc;font-weight:normal;color:black;background-color:white;text-align:center;text-decoration:none;font-style:normal;margin-top:30px'
var htmltable = '<table ' + TABLEFORMAT +' ">';
var tablehead = 'style="background-color:#6aa84f;color:white;';
for (row = 0; row<data.length; row++){
htmltable += '<tr>';
for (col = 0 ;col<data[row].length; col++){
if (data[row][col] === "" || 0) {htmltable += '<td>' + '' + '</td>';}
else
if (row === 0) {
htmltable += '<th ' + tablehead +' ">' + data[row][col] + '</th>';
}
else {htmltable += '<td>' + data[row][col] + '</td>';}
}
htmltable += '</tr>';
}
In your second for loop, first condition catches and appends empty table cells for cell values that have no data in them. Adding a 0 check does not help here as you should check for data[row][col]===0 if you want to match values that equal 0, not ||0.
Otherwise, your code works as intended and testing it on a sample Spreadsheet works - "if cell in Range is empty, append empty cell to table". Do you want to filter out all empty cells?
Update
I am still unsure why you would like to filter out empty cells from the HtmlTable, but if you want only the ones with data to be shown, change your if...else statement a little to account for that:
if (row===0&&data[0][col]!=='') { //filter out empty header cells;
htmltable += '<th>' + data[row][col] + '</th>';
}else if(data[row][col]!=='') { //filter out empty entries cells
htmltable += '<td style="border:1px solid black;">' + data[row][col] + '</td>';
}
Related
I have a program in Apps Script & The purpose is to send an email alert for multiple recipients from Google Sheet when a condition is met. The email body should contain an HTML table.
The Google Sheet has data in 3 columns (A, B & C). Email should trigger when the following condition is met: Column C > 10
As per the below program, I am getting the alert in table format, But I am unable to add this condition to trigger an email. Recipients should not receive the email if the above condition is not met.
function sendMail(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Status")
var data = sh.getRange("A1:C20").getValues();
//var htmltable =[];
var TABLEFORMAT = 'cellspacing="2" cellpadding="2" dir="ltr" border="2" style="width:100%;table-layout:fixed;font-size:10pt;font-family:arial,sans,sans-serif;border-collapse:collapse;border:3px solid #ccc;font-weight:normal;color:Black;background-color:white;text-align:center;text-decoration:grid;font-style:Times;'
var htmltable = '<table ' + TABLEFORMAT +' ">';
for (row = 0; row<data.length; row++){
htmltable += '<tr>';
for (col = 0 ;col<data[row].length; col++){
if (data[row][col] === "" || 0) {htmltable += '<td>' + '' + '</td>';}
else
if (row === 0) {
htmltable += '<th>' + data[row][col] + '</th>';
}
else {htmltable += '<td>' + data[row][col] + '</td>';}
}
htmltable += '</tr>';
}
htmltable += '</table>';
Logger.log(data);
Logger.log(htmltable);
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Email").getRange("A1:A20");
var emailAddress = emailRange.getValues();
GmailApp.sendEmail(emailAddress, 'Order Status Update','' ,{htmlBody: htmltable});
}
Link to a sample Google Sheet: https://docs.google.com/spreadsheets/d/1NpA3kTJFnUFRJ4CTNeSwJNEfSGAezchEuwfMi6ZGQoc/edit?usp=sharing
I believe your goal is as follows.
You want to send an email including all rows that the value of column "C" is more than 10.
In this case, how about the following modification?
From:
var data = sh.getRange("A1:C20").getValues();
To:
var data = sh.getRange("A1:C20").getValues().filter((r, i) => i == 0 || (i > 0 && r[2] > 10));
if (data.length == 1) return;
By this modification, an email including all rows that the value of column "C" is more than 10 is sent. And, when there are no rows where the value of column "C" is more than 10, no email is sent.
Reference:
filter()
I have an function that sends an email if requested in the menu. The body of that email contains two columns. What I need is to only choose rows from the table that equal "PASS" in column C. How do I alter my function to do that?
function SendEmail() {
var data = rpt.getRange("B:C").getValues();
//var htmltable =[];
var TABLEFORMAT = 'cellspacing="2" cellpadding="2" dir="ltr" border="1" style="width:100%;table-layout:fixed;font-size:10pt;font-family:arial,sans,sans-serif;border-collapse:collapse;border:1px solid #ccc;font-weight:normal;color:black;background-color:white;text-align:center;text-decoration:none;font-style:normal;'
var htmltable = '<table ' + TABLEFORMAT + ' ">';
for (row = 0; row < data.length; row++) {
htmltable += '<tr>';
for (col = 0; col < data[row].length; col++) {
if (data[row][col] === "" || 0) {
htmltable += '<td>' + 'None' + '</td>';
} else
if (row === 0) {
htmltable += '<th>' + data[row][col] + '</th>';
} else {
htmltable += '<td>' + data[row][col] + '</td>';
}
}
htmltable += '</tr>';
}
htmltable += '</table>';
Logger.log(data);
Logger.log(htmltable);
MailApp.sendEmail(Session.getActiveUser().getEmail(), 'Keyword Blueprint Report', '', {
htmlBody: htmltable
})
}
How about the following modification?
From:
var data = rpt.getRange("B:C").getValues();
To:
var data = rpt.getRange("B1:C" + rpt.getLastRow()).getValues().filter(([,c]) => c == "PASS");
Or, if you want to leave the 1st row (header row), you can also use the following script.
var data = rpt.getRange("B1:C" + rpt.getLastRow()).getValues().filter(([,c], i) => i == 0 || c == "PASS");
In this modification, the retrieved values are filtered.
I thought that when the range is modified to "B1:C" + rpt.getLastRow(), the process cost will be reduced.
References:
getLastRow()
filter()
I've pulled together the following script that successfully extracts a range of data from a Sheets workbook, puts it in a HMTL table, and emails that table to the recipient.
The only problem is that, try as I might, I cannot have the email display rounded numbers; they will show in excess of 15 decimal places. Is there a way to clean this up? I have tried a range of solutions, from numberformatting in Script and changing the cell display format in sheets. Nothing will work!
A screenshot of the output is below.
function SendEmail() {
// Fetch the ingredients
var ingredients = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = ingredients.getRange("F2:G11").getValues();
var TABLEFORMAT = 'cellspacing="2" cellpadding="2" dir="ltr" border="1" style="width:100%;table-layout:fixed;font-size:10pt;font-family:arial,sans,sans-serif;border-collapse:collapse;border:1px solid #ccc;font-weight:normal;color:black;background-color:white;text-align:center;text-decoration:none;font-style:normal;'
var htmltable = '<table ' + TABLEFORMAT +' ">';
for (row = 0; row<data.length; row++){
htmltable += '<tr>';
for (col = 0 ;col<data[row].length; col++){
if (data[row][col] === "" || 0) {htmltable += '<td>' + 'None' + '</td>';}
else
if (row === 0) {
htmltable += '<td>' + data[row][col] + '</td>';
}
else {htmltable += '<td>' + data[row][col] + '</td>';}
}
htmltable += '</tr>';
}
htmltable += '</table>';
Logger.log(data);
Logger.log(htmltable);
// Fetch the email address
var email = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2").getRange("E21");
var emailAddress = email.getValues();
// Fetch the date
var date = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2").getRange("E24").getValues();
// Send Email
var message = {htmlBody: htmltable};
var subject = 'Ingredients - '+ date;
MailApp.sendEmail(emailAddress, subject, '', {htmlBody : htmltable});
}
The simplest way may be to use
.getDisplayValues() instead of .getValues().
So:
var data = ingredients.getRange("F2:G11").getDisplayValues();
This way you can format the data on the sheet as you like.
And the script will use the numbers as they appear on the sheet and not what their real values may be.
===========================
Your other options are to use Math.round(), Math.ceil() or Math.floor() functions in the loop when processing data[row][col].
I am trying to send an email contains a fixed message and below it a formatted HTML table which gets the range values only if the total column "row[23]" is not empty, which means he's on shift.
Simply I am trying to send the productivity to my team in a table containing the members in duty, in the Google Sheet formula to reflect the internal productivity, but I need the script to only contain the row with values in the table format, I've tried to create a new HTML page and link it with the .gs script, I've tried to use library, I've tried to generate formatted HTML table script using websites and combine them.
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet6')
var startRow = 1;
var numRows = sheet.getLastRow()
var dataRange = sheet.getRange('A2:x18' );
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = 'sherif.gamal1611#gmail.'
var message = "Hi team, kindly check our prod till now as below "
var Date= row[0];
var subject = 'Productivity Report' + " " + Date;
if (row[23] !="" ); {
//var htmltable =[];
var TABLEFORMAT = 'cellspacing="10" cellpadding="10" dir="ltr" border="1" style="width:100%;table-layout:fixed;font-size:10pt;font-family:arial,sans,sans-serif;border-collapse:collapse;border:1px solid #ccc;font-weight:normal;color:black;background-color:white;text-align:center;text-decoration:none;font-style:normal;'
var html table = '<table ' + TABLE FORMAT +' ">';
for (row = 0; row<data.length; row++){
htmltable += '<tr>';
for (col = 2 ;col<data[row].length; col++){
if (data[row][col] === "" || 0) {htmltable += '<td>' + '' + '</td>';}
else
if (row === 0) {
htmltable += '<th>' + data[row][col] + '</th>';
}
else {htmltable += '<td>' + data[row][col] + '</td>';}
}
htmltable += '</tr>';
}
htmltable += '</table>';
Logger.log(data);
Logger.log(htmltable);
MailApp.sendEmail(emailAddress, subject, message,{ htmlBody: htmltable});
SpreadsheetApp.flush();
}
}
The spacing and padding in the mail I receive is in a bad shape, I wonder if it's possible to be aligned and have the same format in the sheet and the mail to contain a message before the HTML table and the table to only contains the rows which has values in the total column row[23] " column X".
Make everything a table and then make the borders around your initial message clear
Below code sends out emails including a table in the body with data rows and header in html. It also attaches the same data into an xlsx and pdf file. Some like it in pdf, some like it in the body of the email, some like it in xlsx so ...
I have 2 issue's with below code:
The result of the loop, table/rows, should be written to a google sheet (Export). This sheet will then be attached as PDF & XLSX to the email sent.
Currently the "Export" sheet is already attached but it's "empty" as the data is not yet written to the Export Sheet, that is the question how to?
I tried to add already the lines "xlsxTable += data[row][col];" in the code to catch the data but I don't think it's the proper way to do so.
Second issue is that sometimes the attachment (xlsx) is not "correctly" formatted and contains the following words: "This file might be un". (Google preview) When downloading the xlsx it's saying, file format not correct ... but the strange thing is, when sending out to 3 different emails 2 of them are OK, 1 is not, sometimes all are OK. Maybe this is timing issue and should include a pause.
Any help is welcome, Thanks!
Below code uses google sheets, with 4 sheet inside: Data, Emails, Parameters, Export.
Data Sheet
ID Name Amount Date
1000 Company 500.23 01/01/2019
2000 Company 500.23 01/01/2019
1000 Company 500.23 01/01/2019
3000 Company 500.23 01/01/2019
1000 Company 500.23 01/01/2019
2000 Company 500.23 01/01/2019
Emails Sheet
ID To Cc Bcc FirstName Subject Language BodyStart BodyEnd Sent SentDate
1000 Company1#email.com
2000 Company2#email.com
3000 Company3#email.com
Parameters Sheet contains just the ReplyTo & ReplyToName
Actual Code
function Statements_Attachments() {
//This section specifies the sheet and some fixed variables.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataRange = ss.getSheetByName("Data").getDataRange();
var emailRange = ss.getSheetByName("Emails").getDataRange();
var param = ss.getSheetByName("Parameters");
var data = dataRange.getValues();
var nameData = emailRange.getValues();
var lastCol = dataRange.getLastColumn();
var lastRow = emailRange.getLastRow();
var replyEmail = param.getRange("B2").getValue();
var replyName = param.getRange("B3").getValue();
var sentRange = ss.getSheetByName("Emails");
var startRow = 1;
var sent = "Y";
var ssA = SpreadsheetApp.getActive();
var ssID = ssA.getId();
var ssName = ssA.getName();
var sheetName = "Export"; //Fill in Sheet Name you want to Email
var shID = getSheetID(sheetName); //Get Sheet ID of Sheet Name
//This section below starts the loop comparing the key between the 2 sheets.
for (var i = 1; i < nameData.length; i++) {
var rows = nameData[i];
var emailAddress = rows[2];
var keyID = rows[0];
var ccMail = rows[3];
var bccMail = rows[4];
var bodyStart = rows[8];
var bodyEnd = rows[9];
var keyName = rows[1];
var subject = rows[6] ;
var emailSent = rows[10];
var xlsxTable = ""; //Variable used to collect the Data for pasting in "Export Sheet"
var exportTable = ""; //Variable used to paste Data in "Export Sheet"
var htmlTable = ""; // HTML body Table created to paste in Email
var htmlMessage = "";
var preTable = '<!DOCTYPE html><html>' + bodyStart ;
var postTable = '</html>';
for (row = 0; row < data.length; row++) {
if (row == 0){
for (col = 0; col < data[row].length; col++) {
if (col == 0) {
htmlTable += '<tr><th style="border-collapse: collapse;border: 1px solid black;background-color:#558EDB">' + data[row][col] + '</th>';
xlsxTable += data[row][col];
} else
if (col == lastCol - 1) {
htmlTable += '<th style="border-collapse: collapse;border: 1px solid black;background-color:#558EDB">' + data[row][col] + '</th></tr>';
xlsxTable += data[row][col];
} else {
htmlTable += '<th style="border-collapse: collapse;border: 1px solid black;background-color:#558EDB">' + data[row][col] + '</th>';
xlsxTable += data[row][col];
}
}
}
else if (data[row][0] == keyID) {
for (col = 0; col < data[row].length; col++) {
if (col == 0) {
htmlTable += '<tr><td style="border-collapse: collapse;border: 1px solid black">' + data[row][col] + '</td>';
xlsxTable += data[row][col];
} else
if (col == lastCol - 1) {
htmlTable += '<td style="border-collapse: collapse;border: 1px solid black">' + data[row][col] + '</td></tr>';
xlsxTable += data[row][col];
} else
if (col == 6) {
htmlTable += '<td align="right" style="border-collapse: collapse;border: 1px solid black">' + data[row][col] + '</td>';
xlsxTable += data[row][col];
} else
if (col == 20 || col == 21) {
htmlTable += '<td style="border-collapse: collapse;border: 1px solid black">' + Utilities.formatDate(data[row][col], "GMT", "dd-mm-yyyy") + '</td>';
xlsxTable += data[row][col];
} else {
htmlTable += '<td align="right" style="border-collapse: collapse;border: 1px solid black">' + data[row][col] + '</td>';
xlsxTable += data[row][col];
}
}
}
}
//The section below closes the table in the body and constructs the complete body.
htmlTable += '</tbody></table>';
htmlMessage = preTable + htmlTable + bodyEnd + postTable;
//The section below should paste the Data into the Export Sheet, to be used as basis for the xlsx & pdf attachment to the email.
exportTable = xlsxTable;
//How to write the result to the Export Sheet in columns and rows.
//The section below sets the variables for the Attachment.
var url = "https://docs.google.com/spreadsheets/d/"+ ssID + "/export?format=xlsx&id="+ ssID +"&gid="+ shID;
var urlPdf = url + "&portrait=true" + "&exportFormat=pdf";
var paramsP = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions: true
};
var paramsX = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions: true
};
var blobPdf = UrlFetchApp.fetch(urlPdf, paramsP).getBlob();
var blobP = blobPdf.setName(sheetName + ".pdf");
var blobXlsx = UrlFetchApp.fetch(url, paramsX).getBlob();
var blobX = blobXlsx.setName(sheetName + ".xlsx");
//The section below retrieves alias email address to send as
var me = Session.getActiveUser().getEmail();// Log the aliases for this Gmail account.
var aliases = GmailApp.getAliases(); // Gets the alias from account
Logger.log(aliases); // Logs the alias
// The section below sends the actual emails
if (emailAddress != "" && emailSent != sent){ //If next email address needs to be different add: && nextEmail != emailAddress
if (aliases.length > 0){ // Prevents sending duplicates
GmailApp.sendEmail(emailAddress, subject, '', {
htmlBody: htmlMessage,
from : aliases[1],
cc : ccMail,
bcc : bccMail,
replyTo : replyEmail,
name : replyName,
attachments : [blobP, blobX],
});
// The section below puts a "Y" next to the row already processed.
sentRange.getRange(startRow + i, 11).setValue(sent);
sentRange.getRange(startRow + i, 12).setValue(new Date ());
//Utilities.sleep(1000);
SpreadsheetApp.flush(); // Make sure the cell is updated right away in case the script is interrupted
}
}
}
}
function getSheetID(name){
var sheetName = SpreadsheetApp.getActive().getSheetByName(name)
var sheetID = sheetName.getSheetId().toString()
return sheetID
}