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
}
Related
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
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>';
}
I am trying to send email when value of column 8 matched column 3 for all the rows in a google script .
function sendEmailNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var lrow=ss.getLastRow()
var sheet = SpreadsheetApp.getActiveSheet();
for (var i = 2; i < lrow; i++)
{
if (sheet.getRange(i, 8).getValue() = sheet.getRange(i, 3).getValue())
var emailSubject = 'Value of ' + sheet.getRange(i, 1).getDisplayValue() + ' triggered, now pending your attention';
var emailBody = 'Person1 has approved the item on row ' + ' of spreadsheet "' + '".\n\n';
emailBody += 'To open the spreadsheet, click this link: ' + ss.getUrl() + '\n\n';
emailBody += '(this is an automatically sent message)';
MailApp.sendEmail("sdas22#gmail.com", emailSubject, emailBody);
; }}
The main problem is the IF statement
This is yours which does not work and which is generating an error message
if (sheet.getRange(i, 8).getValue() = sheet.getRange(i, 3).getValue())
This is mine which does work
if ((sheet.getRange(i, 8).getValue()) == (sheet.getRange(i, 3).getValue())){
}
A couple of things to note.
The comparison operator is "==" rather than "="
The each of the getValue statements are encapsulated in brackets
There are no "curly brackets" to indicate the purpose of the IF statement. This is particular important.
There's also semicolon on the last line that seem out of place.
This is my version of your code - which runs
function sendEmailNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var lrow=ss.getLastRow()
var sheet = SpreadsheetApp.getActiveSheet();
for (var i = 2; i < lrow; i++)
{
if ((sheet.getRange(i, 8).getValue()) == (sheet.getRange(i, 3).getValue())){
var emailSubject = 'Value of ' + sheet.getRange(i, 1).getDisplayValue() + ' triggered, now pending your attention';
var emailBody = 'Person1 has approved the item on row ' + ' of spreadsheet "' + '".\n\n';
emailBody += 'To open the spreadsheet, click this link: ' + ss.getUrl() + '\n\n';
emailBody += '(this is an automatically sent message)';
MailApp.sendEmail("sdas22#gmail.com", emailSubject, emailBody);
}
}
}
I am trying to get email via google app script. What I am doing is I get an alert email if a person's birthday is today. I have an google sheets which already have those data. But I am having a problem in few things. First, below is my code which I am running
var activeSheet = SpreadsheetApp.getActiveSpreadsheet();
var birthdaysSheet = activeSheet.getSheetByName("Data");
var settingsSheet = activeSheet.getSheetByName("Settings");
var sendEmailTo = settingsSheet.getRange("B4").getValue();
function emailAlert() {
if (turnOnEmailNotice.toLowerCase() == "no")
{
Logger.log("The Email Notification is NOT turned ON. System will Exit.");
exit
}
//Get the total number of filled row in the sheet.
var currentRowAT = 2;
var currentCellValueAT = "start";
while (currentCellValueAT != ""){
if (currentCellValueAT = birthdaysSheet.getRange("A" + currentRowAT).getValue() != ""){
currentRowAT = currentRowAT +1;
}
}
var birthdaysSheetLastRow = currentRowAT - 1;
// Get today's Date (with Month, Date and Year)
var today = new Date();
var todayMth = today.getMonth()+1;
var todayDate = today.getDate();
var todayYear = today.getFullYear();
for (k=2; k < birthdaysSheetLastRow + 1; k++)
{
var targetBday = new Date();
targetBday = birthdaysSheet.getRange("P" + k).getValue();
// If Birthday is not speicified, continue with the next row
if (targetBday == ""){continue};
var unadjTargetBday = new Date();
var unadjTargetBdayMth = targetBday.getMonth()+1;
var unadjTargetBdayDate = targetBday.getDate();
var unadjTargetBdayYear = targetBday.getFullYear();
var unadjTargetBday = targetBday;
targetBday.setDate(targetBday.getDate()-daysInAdvance); // Calculating how many days in advance you want to trigger the notification. This is set in Settings Tab.
var targetBdayMth = targetBday.getMonth()+1;
var targetBdayDate = targetBday.getDate();
if (targetBdayMth + " " + targetBdayDate == todayMth + " " + todayDate)
{
var targetBirthDateYearsOld = (today.getYear() - unadjTargetBday.getYear())-1900;
prepareAndSendEmail(k, targetBirthDateYearsOld);
}
}
}
/*
* This method actually prepares the HTML of the email body and send it out.
*/
function prepareAndSendEmail(row, targetBirthDateYearsOld)
{
var firstName= birthdaysSheet.getRange("A" + row).getValue();
var lastName = birthdaysSheet.getRange("B" + row).getValue();
var emailAddress = birthdaysSheet.getRange("D" + row).getValue();
var Birthday = birthdaysSheet.getRange("C" + row).getValue();
var message = "";
message = message + "Hi all," + NEW_LINE + NEW_LINE;
message = message + "Today is <B style=\"color:tomato\">" + firstName + " " + lastName + "</B>'s Birthday." + NEW_LINE + NEW_LINE;
var tableHeader = "";
tableHeader = tableHeader + "<table width=\"40%\" style=\"background-color:#FF8040;align:center;font-family:calibri,arial\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\" >";
tableHeader = tableHeader + "<tr style=\"text-align:center;font-weight: bold;height:5px;\"> <td> </td> <td></td></tr>";
message = message + tableHeader;
var color = "GhostWhite";
message = message + "<TR style=\"background-color:" + color + "\"> <TD style=\"text-align:left;font-weight: bold;\"> Birthday: </TD> <TD>" + formatDate(targetCandidateBirthday) + "</TD>";
message = message + "<TR style=\"background-color:" + color + "\"> <TD style=\"text-align:left;font-weight: bold;\"> Age: </TD> <TD>" + targetBirthDateYearsOld + "</TD>";
message = message + "<TR style=\"background-color:" + color + "\"> <TD style=\"text-align:left;font-weight: bold;\"> Email: </TD> <TD>" + targetCandidateEmailAddress + "</TD>";
}
Question:
What I am making mistake as I am having error getting range at var firstName= birthdaysSheet.getRange("A" + row).getValue();
--Error: Range not found
I think my code to get age is also seems to be wrong.
If I am using only first row then age is coming as undefined.
I'm wondering if your first loop would be better if structured like this:
//Get the total number of filled row in the sheet.
var currentRowAT = 2;
var currentCellValueAT = "start";
var thisRow, theBirthday = "";
var birthdayData = birthdaysSheet.getRange(1, 1, birthdaysSheet.getLastRow()); //Get all of column A data
for (var i=0;i<birthdayData.length;i+=1) {
thisRow = birthdayData[i];
theBirthday = thisRow[0];
if (theBirthday === "") {
var birthdaysSheetLastRow = currentRowAT - 1;
break; //Stop looping through the data
};
};
Problem was solved. I just ran the script in excel sheet. It worked. Didn't changed anything.
Thank You Guys for your help.