google sheet email alert if expiry date - google-apps-script

I have a table with 8 columns with dates. I need to track them if they are to expire, but for 3 of them I need to alert alert 3 months before and for the remaining columns, 6 months before.
I think that I am on the right track with the code below, but still not doing what it needs to be done.
I start with one month in the beginning. Can somebody help me?
function emailAlert() {
// today's date information
var today = new Date();
var todayMonth = today.getMonth() + 1;
var todayDay = today.getDate();
var todayYear = today.getFullYear();
var newToday = new Date()
var oneMonthFromToday = new Date(newToday.setMonth(newToday.getMonth()+1));
var oneMonthMonth = oneMonthFromToday.getMonth() + 1;
var oneMonthDay = oneMonthFromToday.getDate();
var oneMonthYear = oneMonthFromToday.getFullYear();
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = 100;
var dataRange = sheet.getRange(startRow, 1, numRows, 999);
var data = dataRange.getValues();
//looping through all of the rows
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var expireDateFormat = Utilities.formatDate(
new Date(row[6]),
'ET',
'MM/dd/yyyy'
);
var subject = '';
var message = ' You have expiring pass. ' + '\n';
MailApp.sendEmail('lubomira.petkova88#gmail.com', subject, message);
}

It is not clear on your post but the code below assumed only 1 column needs to be checked. Feel free to adjust the conditions but this should be the main idea of your code.
Code:
function checkPasswordExpiry() {
// today's date information
var today = new Date();
today.setHours(0,0,0,0);
// 3 months before
var prev3Months = new Date();
prev3Months.setMonth(today.getMonth() - 3);
prev3Months.setHours(0,0,0,0);
// 6 months before
var prev6Months = new Date();
prev6Months.setMonth(today.getMonth() - 6);
prev6Months.setHours(0,0,0,0);
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
// get number of rows/columns in sheet instead of manually setting it
var numRows = sheet.getLastRow();
var numCols = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows, numCols);
var data = dataRange.getValues();
//looping through all of the rows
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var expireDateFormat = Utilities.formatDate(
new Date(row[6]),
'ET',
'MM/dd/yyyy'
);
var date = new Date(row[6]);
date.setHours(0,0,0,0);
var subject = 'Password Expiry';
var message = 'Hi ' + row[0] + ', \nYour password is expiring';
var email = 'lubomira.petkova88#gmail.com';
if(date.getTime() === prev6Months.getTime()) {
message += " in 6 months. ( " + expireDateFormat + " )";
MailApp.sendEmail(email, subject, message);
}
else if(date.getTime() === prev3Months.getTime()) {
message += " in 3 months. ( " + expireDateFormat + " )";
MailApp.sendEmail(email, subject, message);
}
else if(date.getTime() === today.getTime()) {
message += " today. ( " + expireDateFormat + " )";
MailApp.sendEmail(email, subject, message);
}
}
}
The code above does check column G whether it is already 6 months before today, 3 months before today or exactly the date. If you need to check multiple columns, just replace the conditions inside and it should still work.
Sample email:
Note that the code above should be triggered every day so it can check the data daily.
Code:
function createTimeDrivenTriggers() {
ScriptApp.newTrigger('checkPasswordExpiry')
.timeBased()
.everyDays(1)
.atHour(0)
.create();
}
Function createTimeDrivenTriggers needs to be run just once. Please see reference below.
Reference:
Time driven triggers
everyDays()
If I wasn't able to provide you the answer you are hoping for, I sincerely apologize. Feel free to comment below what are the changes that are needed to be done.

Related

Send an reminder email after 5 days compare with the timestamp

I am intending to send an email after 5 days comparing the timestamp in my google sheet. But it is not working.
Below is my code:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow();
var dataRange = sheet.getRange(startRow, 2, numRows, 15)
var data = dataRange.getValues();
for (var i = 0; i < data.length; i++) {
var row = data[i];
var Timestamp = row[0];
var todaydate = new Date();
var secondDate = new Date();
secondDate.setDate(todaydate.getDate()+5);
if (Timestamp <= secondDate){
var messageHtml = "Hi " +
"<br><br>Test " +
"<br><br>test" +
"<br>Thank You<br><br>";
var message = messageHtml.replace(/\<br\/\>/gi, '\n').replace(/(<([^>]+)>)/ig, "");
// clear html tags and convert br to new lines for plain mail
var subject = "Uniform Order Form Pending Process";
MailApp.sendEmail("test#gmail.com", subject,message);
}
}
};
Sorry that maybe it might be something very simple but hope you guys can advise me.
Thanks
Try
secondDate.setDate(todaydate.getDate()+5 * 86400000);
one day is: 1000 * 60 * 60 * 24, which is 86400000 milliseconds.

how do I add todays date plus 7 days in a cell with script editor

I have the a script to send emails and place a "Email_Sent" in a column to stop re-sends, what I an trying to do is have it enter todays date plus 7 days instead of "Email_Sent" so I can use if date = Today() for reminders this is the bit I am trying to change no avail this is what I have and the second snippet is what I need but work:
Working:
if (emailSent !== "EMAIL_SENT" && Send == "TRUE") {
var subject = 'Your Movie Link';
MailApp.sendEmail(emailAddress, subject, messagebody);
sheet.getRange(startRow + i, 8).setValue("EMAIL_SENT");
Change to this but not working:
if (emailSent == Today()) {
var subject = 'Your Movie Link';
MailApp.sendEmail(emailAddress, subject, messagebody);
sheet.getRange(startRow + i, 9).setValue(Today()+7);
Explanation:
To create a date after 7 days from today:
const dt = new Date()
dt.setDate(dt.getDate() + 7)
To use the following solution, you need to make sure that emailSent is a date object. Go to the sheet and use =isdate(A1). The latter will return TRUE if the value of A1 is indeed a date object. If it is a date object, then you can create a new Date() object. Namely, if emailSent is a date in your sheet, then you should be able to do: new Date(emailSent).
Solution:
function SendEmails() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Send Email');
var lastRow =sheet.getLastRow();
var startRow = 2;
var numRows = lastRow-1;
var dataRange = sheet.getRange(startRow, 1, numRows, 5000);
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[1];
var Name = row[5];
var Amount = row[6];
var message = row[7];
var emailSent = row[8];
var subject = "Reminder fom spreadsheet";
messagebody = message.replace("{Name}",Name).replace("{Amount}",Amount)
ssTimeZone = SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone();
const dt = new Date();
if (Utilities.formatDate(new Date(emailSent), ssTimeZone, 'yyyy-MM-dd') == Utilities.formatDate(dt, ssTimeZone, 'yyyy-MM-dd')) {
dt.setDate(dt.getDate() + 7);
var subject = 'Your Movie Link';
MailApp.sendEmail(emailAddress, subject, messagebody);
sheet.getRange(startRow + i, 9).setValue(Utilities.formatDate(dt, ssTimeZone, 'yyyy-MM-dd'));
SpreadsheetApp.flush();
}
}
}

Comparing Dates in Google Sheets Script Editor

I am very new to this, so please bear with me. I am trying to get my code to look at each cell in a column, then compare that date to the current date, and if they match send an email. I am aware I will need a loop of some sort to get it to look through the column, but I haven't even gotten that far. I've tried every method I can find online to just get it to compare one cell to the date and send the email.
I tested the email function prior to adjusting it to compare the date, so I know that is working. Put something definitely isn't working...
function sendEmail() {
//Fetch the date
var removalDateRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Expirations").getRange("E2");
var removalDate = removalDateRange.getValue();
var currentDateRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Alerts").getRange("C2");
var currentDate = new Date();
var ui = SpreadsheetApp.getUi();
//Check Date
if (removalDate == currentDate) {
//Fetch the email address
var emailRange =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Alerts").getRange("B2");
var emailAddress = emailRange.getValue();
//Fetch Item Brand
var itemBrandRange =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Expirations").getRange("B2");
var itemBrand = itemBrandRange.getValue();
//Fetch Item Name
var itemNameRange =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Expirations").getRange("A2");
var itemName = itemNameRange.getValue();
//Fetch Item Location
var itemLocationRange =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Expirations").getRange("H2");
var itemLocation = itemLocationRange.getValue();
// Send Alert Email
var message = 'The ' + itemBrand + ' ' + itemName + ' in ' + itemLocation + ' will expire in 2 months. Please use and replace item.';
// Second Column
var subject = 'Pantry Alert';
MailApp.sendEmail(emailAddress, subject, message);
}
}
EDIT
Okay, I had it working late last night and even got it to loop through, and somehow I've broken it again. I've been looking at answers for hours trying to adjust things to make it work. What am I doing wrong?
function emailAlert() {
// today's date information
var today = new Date();
var todayMonth = today.getMonth() + 1;
var todayDay = today.getDate();
var todayYear = today.getFullYear();
// 2 months from now
var oneMonthFromToday = new Date(todayYear, todayMonth, todayDay);
var oneMonthMonth = oneMonthFromToday.getMonth() + 2;
var oneMonthDay = oneMonthFromToday.getDate();
var oneMonthYear = oneMonthFromToday.getYear();
// getting data from spreadsheet
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Exp");
var startRow = 2; // First row of data to process
var numRows = 500; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 999);
var data = dataRange.getValues();
//looping through all of the rows
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var expireDateFormat = Utilities.formatDate(new Date(row[5]),
'ET',
'MM/dd/yyyy'
);
//email Information
var subject = 'Pantry Item Needs Attention!';
var message1 =
row[6] + ' ' + row[3] + ' of ' + row[2] + ' ' + row[1] + ' will expire on ' + expireDateFormat + '. Item can be found in ' + row[7]
+ '. Please Remove and Replace Item.' +
'\n' + 'Thanks Steve!';
var message2 =
row[6] + ' ' + row[3] + ' of ' + row[2] + ' ' + row[1] + ' will expire on ' + expireDateFormat + '. Item can be found in ' + row[7] +
'. Please ensure item has been replaced, removed from the pantry, and deleted from inventory.' +
'\n' + 'Thanks Steve!'
//expiration date information
var expireDateMonth = new Date(row[5]).getMonth() + 1;
var expireDateDay = new Date(row[5]).getDate();
var expireDateYear = new Date(row[5]).getYear();
//checking for today
if (
expireDateMonth === todayMonth &&
expireDateDay === todayDay &&
expireDateYear === todayYear
) {
ui.alert(message1);
}
}
}
Dates can be frustrating to work with, so consider doing the whole thing (loop, if then statement...) with an integer first and then returning to the date part if you're having trouble. That said, try adjusting the top of your code to look like the following:
var ss =SpreadsheetApp.getActiveSpreadsheet();
var removalDateVal = ss.getSheetByName("Expirations").getRange("E2").getValue();
var removalDate = new Date(removalDateVal);
var currentDateVal = ss.getSheetByName("Alerts").getRange("C2").getValue();
var currentDate = new Date(currentDateVal);
That will give you two date objects. But BEWARE! These dates contain time as well as calendar date so they may not equal each other even when they appear to. Use setHours() to zero out the date as seen below.
currentDate.setHours(0,0,0);
removalDate.setHours(0,0,0);
Other notes, it's best practice to set a variable for a spreadsheet and worksheet as shown by Google here. It makes the code much more readable.

How to send several rows of google sheet table via email if cell match today's date

daily I have to send different qty of google sheet table rows (it depends on how many trucks were departed) via e-mail to a few recipients.
Could you help me, please, with an example of how to collect several rows of google table if cell match today's date and then send it via email?
For example, I need to grab all rows with today's date and send data from columns A, B, C, E via e-mail.
Thanks for any help in advance :)
Let's go step by step. I'm supposing the column A contains the dates. Change it if it's not correct:
Declare the variables we will use for this
function main() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sheet.getActiveSheet();
var row_count = sheet.getLastRow() - 1;
var today = Utilities.formatDate(new Date(), "UTC", "dd.MM.yyyy"); //You can use the date format you prefer
var data = sheet.getRange("A2:E"+ (row_count + 1)).getValues(); //We get all the values from A to E and from row 2 to the last one.
countToday(sheet, today, row_count, data);
sendEmails(data);
}
Since we have each row in each position of data, we will compare
each date with "today", and we will remove (splice) the rows from
other days. The rows with valid dates will remain in the variable:
function countToday(sheet,today, row, data){
var lastrow = "A" + (row + 1);
var col_A = sheet.getRange('A2:'+lastrow).getValues();
for (var i = row; i >= 0; i--){
if (col_A[i] != today){
data.splice(i, 1); //
}
}
}
Now that we got each row of elements, we can send the email. We will create an html table so it will be easier to understand. The Mailapp function makes it very simple:
function sendEmails(data){
MailApp.sendEmail({
to: "example1#mail.com" + "example2#mail.com", //You can put as many emails you want
subject: "Example",
htmlBody:"<html><body>" + createTable(data)+ "</body></html>"});
}
To create the html table, we just make a string coded in html with
the names of the columns from the Sheet. Then we make a table array,
where we will split each element from data separated by coma (that's each sheet cell) and just add it to the end of the variable. < /td> will create the rows for us.
function createTable(data){
var cells = [];
var table = "<html><body><br><table border=1><tr><th>Date</th><th>Column B</th><th>Column C</th><th>Column D</th><th>Column E</tr></br>";
for (var i = 0; i < data.length; i++){
cells = data[i].toString().split(",");
table = table + "<tr></tr>";
for (var u = 0; u < cells.length; u++){
table = table + "<td>"+ cells[u] +"</td>";
}
}
table=table+"</table></body></html>";
return table;
}
Here is my example of code. But I can't figure out how to implement preventing function for duplicating emails sending. EMAIL_SENT is working only with the "for" cycle. But in that case, if the cell doesn't contain "EMAIL_SENT" string, the email is sending as many times as there are the empty cells.
function main() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sheet.getSheetByName("HR-SI B2C");
var row_count = sheet.getLastRow() - 1;
var today = Utilities.formatDate(new Date(), "UTC", "dd/MM/yyyy"); //You can use the
date format you prefer
var data = sheet.getRange("A3:K"+ (row_count + 1)).getValues(); //We get all the
values from A to E and from row 2 to the last one.
var lastrow = "A" + (row_count + 1);
var col_A = sheet.getRange('A3:'+lastrow).getDisplayValues();
var row = data[i];
for (var i = row_count; i >= 0; i--){
if (col_A[i] != today){
data.splice(i, 1);
}
}
if (("K" + (row_count+2)) == "EMAIL_SENT"){
}else if(("D" + (row_count)) == "" || ("F" + (row_count)) == ""){
dontSendEmail();
}else{
sendEmailsQHNBRGR(data);
}
}
//-----------------------------------------------------------------------------------
function dontSendEmail(){
var today = Utilities.formatDate(new Date(), "UTC", "dd/MM/yyyy"); //You can use the
date format you prefer
MailApp.sendEmail({
to: "xxxxxxxxxx#gmail.com", //You can put as many emails you want
subject: "Brak wpisanych ilości dla HR i SI za " + today,
htmlBody:"<html><body> Witam,<br><br>" +
"<span><b>Proszę bardzo wpisać ilości dla HR i SI do tabeli</b></span>" +
"</body></html>"});
}
//-----------------------------------------------------------------------------------
function sendEmailsQHNBRGR(data, platesNum){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sheet.getSheetByName("HR-SI B2C");
var row_count = sheet.getLastRow() - 1;
var today = Utilities.formatDate(new Date(), "UTC", "dd/MM/yyyy"); //You can use the date format you prefer
var data = sheet.getRange("A3:G"+ (row_count + 1)).getDisplayValues(); //We get all the values from A to D and from row 2 to the last one.
var cells = [];
var table = "<html><body><table border=3><tr><th>Date</th><th>Day</th><th>HR [pcs]</th><th>HR [ep]</th><th>SI [pcs]</th><th>SI [ep]</th></tr>";
var lastrow = "A" + (row_count + 1);
var col_A = sheet.getRange('A3:'+lastrow).getDisplayValues();
MailApp.sendEmail({
to: "xxxxxxx#gmail.com", //You can put as many emails you want
subject: "(HR+SI) Orsay prealert " + today,
htmlBody:"<html><body> Dear All,<br><br>" +
"<span style=background-color:rgb(217,234,211)><b>Today we've sent e-com goods in listed quantity:</b></span>" +
createTable(data) + "<br>" +
"<span style=background-color:rgb(255,242,204)><b>#DPD team, could you pick it up
tomorrow at 02:00 PM?</b></span><br>" +
"</body></html>"});
}
//-----------------------------------------------------------------------------------
function createTable(data){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sheet.getSheetByName("HR-SI B2C");
var row_count = sheet.getLastRow() - 1;
var today = Utilities.formatDate(new Date(), "UTC", "dd/MM/yyyy"); //You can use the date format you prefer
var data = sheet.getRange("A3:G"+ (row_count + 1)).getDisplayValues(); //We get all the values from A to D and from row 2 to the last one.
var cells = [];
var table = "<html><body><table border=3><tr><th>Date</th><th>Day</th>
<th>Plates number</th><th>HR [pcs]</th><th>HR [ep]</th><th>SI [pcs]</th>
<th>SI [ep]</th></tr>";
var lastrow = "A" + (row_count + 1);
var col_A = sheet.getRange('A3:'+lastrow).getDisplayValues();
for (var i = row_count; i >= 0; i--){
if (col_A[i] != today){
data.splice(i, 1);
}
}
for (var i = 0; i < data.length; i++){
cells = data[i].toString().split(",");
table = table + "<tr></tr>";
for (var u = 0; u < cells.length; u++){
table = table + "<td>"+ cells[u] +"</td>";
sheet.getRange("K3:K"+ (row_count + 1)).setValue("EMAIL_SENT");
}
}
table=table+"</table></body></html>";
return table;
}
}

Google Script onChange trigger executes when no change made (overnight)

I have a Google Script running the sendEmails() function with the installable onChange trigger. This works well but I'm seeing that it also executes overnight, when no changes are made to the spreadsheet.
Anyone know what may be happening/ how to prevent this?
Here's the code that's running in the script editor:
/**
* Sends emails with data from the current spreadsheet.
*/
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1; // Number of rows to process
// Fetch the range of cells A2:C2
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[4]; // Fifth column
var message = row[0]; // First column
var subject = row[3]; // Fourth Column
MailApp.sendEmail(emailAddress, subject, message);
}
}
In the executions/trigger log I see that a trigger executed last night at 5:07 am and the night before at 1:16am, when no changes were made to the spreadsheet
screenshot of trigger log
Wasn't able to figure out the underlying issue, but created code which prevents the script from sending an email (to Asana to create a task in this case) for any row where an email was previously sent.
var TASK_SENT= "TASK_SENT";
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow();
// Fetch the range of cells UPDATE
var dataRange = sheet.getRange(startRow, 1, numRows, 48);
// 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 message = row[45] //Next Steps Column
var staff = row[1] // Your Name Column
var internal_part = row[7] //Who was the Check-in with? Column
var external_part = row[13] //What Site was your Check-in With? Column
var check_dt = row[2] //Date of Contact Column
var check_dt = Utilities.formatDate(new Date(), "GMT+1", "MM/dd/yy")
var site_disc = row[8] //What site was discussed?
var emailAddress = row[46]; // Email address column
var taskSent = row[47]; // Task_Sent column
if (taskSent != TASK_SENT) { // Prevents sending duplicates
var subject = staff + " " + 'check-in w/' + " " + internal_part + external_part + " " + 're:' + " " + site_disc + " " + check_dt + " " + 'Next Steps';
if (emailAddress == "") {
continue;}
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 48).setValue(TASK_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
Try this to see if it will eliminate the overnight emails.
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = 1;
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
for (var i=0;i<data.length;i++) {
var row = data[i];
var emailAddress = row[4]; // Fifth column
var message = row[0]; // First column
var subject = row[3]; // Fourth Column
if(emailAddress && message && subject) {
MailApp.sendEmail(emailAddress, subject, message);
}
}
}