Auto Email Google App Script: do while condition - google-apps-script

I been working on this script for long time, it is Google App script, it sends email alert automatically to email provided, and I have script triggered at running every 1 minute.
so if cell total is greater than 201 it will send email to user.
but the problem is it send email every minute script is ran.
I need help with coding where if email has been sent already once, it will not send again unless cell value is less than 201 again and goes back to greater than 201,
I was thinking of making a cell which will contain text "Sent" or "Not Sent"
if it says "Not Sent" let the email code run if total is greater than 201
if is says "Sent" and total is greater than 201 don't let email code run..
I know I am not every clear but It has been very hard to get help on this.
Here is the code.
and if this works I'm sure lots of people can use this script for their use.
function sendEmail(email_address, email_subject, email_message) {
MailApp.sendEmail(email_address, email_subject, email_message);
}
function test_sendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.setActiveCell('A2');
var criterion_cutoff = 201;
var i = 0;
var addr;
var subj;
var msg;
do {
addr = cell.offset(i,0).getValue();
subj = cell.offset(i,1).getValue();
msg = cell.offset(i,2).getValue();
criterion = cell.offset(i,3).getValue();
if(criterion == criterion_cutoff) {
sendEmail(addr,subj,msg);
// Browser.msgBox('Sending email to: ' + addr);
}
i++;
} while( cell.offset(i, 0).getValue().length > 0 )
Browser.msgBox('Done!');
}
so I was think of adding if else condition outside of do while
if(SpreadsheetApp.getActiveSheet().getRange(21,6).getValue() != 'Not Sent') {
do {
//same stuff as above
} while(condition)
}
else
//don't know wht else to do in else condtion so just using googleclock
SpreadsheetApp.getActiveSheet().getRange(2,7).setValue('=GoogleClock()')

I guess I've figured it out on my own. I want to share my solution so other can use it.
so I have added 2 if else condtion
first one will check if cell value is < 201
if it is less than 201 than set somecell example F5 = Not Sent
another if else loop that will check
if value of F5 != Sent and cell value == 201
than it will run the email code
and right after running that email code it will set cell F5 to Sent
so next time loop runs again it will not send email again unless value of cell is
but this has one minor issue it will only work for 1st row out of 3 rows, you can make it for all 3 rows by adding more if conditions, I don't need it so I am not worried about it.
function sendEmail(email_address, email_subject, email_message) {
MailApp.sendEmail(email_address, email_subject, email_message);
}
function test_sendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.setActiveCell('A2');
var criterion_cutoff = 201;
var i = 0;
var addr;
var subj;
var msg;
if((SpreadsheetApp.getActiveSheet().getRange(2,4).getValue() < '201')) {
SpreadsheetApp.getActiveSheet().getRange(2,6).setValue('Not Sent');
}
else
if((SpreadsheetApp.getActiveSheet().getRange(2,6).getValue() != 'Sent') && (SpreadsheetApp.getActiveSheet().getRange(2,4).getValue() == '201')) {
do {
addr = cell.offset(i,0).getValue();
subj = cell.offset(i,1).getValue();
msg = cell.offset(i,2).getValue();
criterion = cell.offset(i,3).getValue();
if(criterion == criterion_cutoff) {
sendEmail(addr,subj,msg);
// Browser.msgBox('Sending email to: ' + addr);
SpreadsheetApp.getActiveSheet().getRange(2,6).setValue('Sent');
}
i++;
} while( cell.offset(i, 0).getValue().length > 0 )
Browser.msgBox('Done!');
}
}

Related

Sending email reminders for Google Sheet tasks

Updated the code based on suggestions below, The email does not contain the summary, any help fix this would be appreciated! The test file is attached below,
function sendEmail(){
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("2021-12 {3600950}").activate();
var ss =
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
//data on sheet, filter for any row where the status is still "assigned"
var data = ss.getDataRange().getValues()
var assigned = data.reduce(function(acc, curr) {
if(curr[5] === "assigned") {
acc.push(curr)
}
return acc
},[])
// unique list of emails
var Assignee = [0]
var Summary = [2]
var compareAssignee = []
for (i=0; i<assigned.length; i++){
compareAssignee.push(assigned[i][0])
}
//loop unique emails, all the tasks for each of those users, and send a simple email with the tasks
for (var i=0; i<Assignee.length; i++){
var Summary = assigned.reduce(function(acc, curr) {
if(curr[0] === Assignee[i])
{
acc.push(String.fromCharCode() + "pending task: " + curr[2] +
Summary[2])
//this puts a line break before each task, so when the email is
sent each one is on its own line.
}
return acc
},[])
console.log(Summary)
MailApp.sendEmail
MailApp.sendEmail(compareAssignee[0],"pending RPP task(s)",Summary[2])
}
}
function scheduleEmails(){
// Schedules for the first of every month
ScriptApp.newTrigger("sendEmail")
.timeBased()
.onMonthDay(28)
.atHour(1)
.create();
}
You want to send an email at the end of every month to users who have tasks that are still in "assigned" status.
The sendEmail script below finds all the tasks for each user and sends an email to them listing each of their tasks that are still "assigned". EDIT: You indicated in a comment above that emails are in Col 1, tasks are in Col 3 and status is in Col6. I updated the code to reflect that below.
Check out this sample email to see the results.
The second function creates a trigger that runs sendEmail every month. You indicated you wanted to send the email on the last day of the month, but it seems Google has a hard time with that. Some other folks came up with workarounds. I like this one: send the reminder on the 1st of the month, but at 1 in the morning! You can see more of their work here
function sendEmail(){
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("status").activate();
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
//grab all the data in the sheet, and then filter for any row where the status is still "assigned"
var data = ss.getDataRange().getValues()
var assigned = data.reduce(function(acc, curr) {
if(curr[5] === "assigned") {
acc.push(curr)
}
return acc
},[])
// From all the tasks still in "assigned" status, get a unique list of emails.
var uniqueEmails = []
var compareEmails = []
for (i=0; i<assigned.length; i++){
compareEmails.push(assigned[i][0])
}
uniqueEmails = [...new Set(compareEmails)]
//loop through the unique emails, grab all the tasks for each of those users, and send a simple email with the tasks listed.
for (var i=0; i<uniqueEmails.length; i++){
var tasksPerUser = assigned.reduce(function(acc, curr) {
if(curr[0] === uniqueEmails[i]) {
acc.push(String.fromCharCode(10) + "pending task: " + curr[2]) //this puts a line break before each task, so when the email is sent each one is on its own line.
}
return acc
},[])
console.log(tasksPerUser)
MailApp.sendEmail(uniqueEmails[i],"pending tasks",tasksPerUser)
}
}
function scheduleEmails(){
// Schedules for the first of every month
ScriptApp.newTrigger("sendEmail")
.timeBased()
.onMonthDay(1)
.atHour(1)
.create();
}

Google Apps Script - Variable Passed Between Functions Shows Up as Undefined

I have some code where there are some if/else if statements to determine the reason that a Google Form has closed. I want to pass this reason to another function which will send an email notifying me that the form has closed and the why. I don't know why the reason, which should be a string, is not getting passed to the function that sends the email.
I'm not dealing with the form at all in this code. For simplicity, I opened a new standalone script, not linked to any Google Form or Sheet, to test just this portion (determine reason and send email). Here is the code:
First function to determine reason the form closed and to call second function to send email:
function FindReason() {
var Day1Seats = 5;
var Day2Seats = 5;
var Day1Responses = 6;
var Day2Responses = 1;
var FormClose = false;
if(Day1Responses >= Day1Seats) {
var reason = "All seats taken for Day 1";
SendAnEmail(reason);
}
else if(Day2Responses >= Day2Seats) {
var reason = "All seats taken for Day 2";
SendAnEmail(reason);
}
else if(FormClose) {
var reason = "Form close date";
SendAnEmail(reason);
}
}
Second function, which sends email (email address obviously changed for privacy):
function SendAnEmail(closereason) {
var recipientTO = "name#example.com";
var subject = "This is the subject";
//var closereason = "All seats taken for Day 1";
MailApp.sendEmail({
to: recipientTO,
subject: subject,
htmlBody: (new Date()) + "<br>Your form has been closed because: <br>" + closereason + "<br>End of message."
});
}
When I run FindReason(), I do get an email but the body doesn't properly show the reason. This is an example of the emails I get:
Sun Feb 24 2019 12:26:01 GMT-0800 (PST)
Your form has been closed because:
undefined
End of message.
I don't know why the reason is shown as undefined. I tried setting the reason inside the SendAnEmail function (the line that has been commented out) and that worked properly, but I need to be able to change the reason.
Edit: It works now. It turns out the "run" button was set to run the "SendAnEmail" function rather than the "FindReason" function. Thanks to everyone who offered suggestions.
What's probably happening is that else if(FormClose = TRUE) is not going to work.
= is the assignment operator, you want equality, which is ===.
TRUE is lowercase in js, so you want true.
You also use False, which should be false.
If you look in the google scripts editor's console, you should see an error of some sort, because it won't know what False or TRUE are (it will think they are undeclared variables).
try else if(FormClose === true) or even more simply, else if (FormClose), because if it evaluates to true, that will do the job.
function FindReason() {
var Day1Seats = 5;
var Day2Seats = 5;
var Day1Responses = 6;
var Day2Responses = 1;
var FormClose = false;
if(Day1Responses >= Day1Seats) {
var reason = "All seats taken for Day 1";
SendAnEmail(reason);
} else if(Day2Responses >= Day2Seats) {
var reason = "All seats taken for Day 2";
SendAnEmail(reason);
} else if(FormClose) {
var reason = "Form close date";
SendAnEmail(reason);
}
}

Find Value in Google Sheet App Script

I've been searching around for a script that finds text within a range. I found a couple and modified this code for my particular needs. All I'm doing is creating a "login" type system. The user inputs their email (E5) on one spreadsheet and then when I hit the button it runs the script to searches another spreadsheet that contains emails (A1:A) and sub status in B - so total range is (A1:B).
Problem is, the script only works if the email matches cell A1. So if Briansmith#hotmail.com is in (E5) or what the user types in, and on the other spreadsheet in A1 Briansmith#hotmail.com is there - it works. But if I moved it down to A5 or something else than A1, it no longer works. I'm confused why the for loop isn't continuing to go down the column to look for matching text.
Here's the code I'm using:
function loginFunction() {
var s = SpreadsheetApp.getActiveSheet();
//Username is in (E5)
var email = s.getRange("E5").getValue();
var data = SpreadsheetApp.openById('Deleted for privacy').getRange("A1:B")
var value = data.getValues();
for (var i = 0; i < value.length; i++) {
if (value[i][0] === email) {
if (value[i][1] === "yes") {
//Email is located (col A) and sub (col B) is yes
Logger.log('Yes');
return SpreadsheetApp.getUi().alert('Connected!');
} else {
//Email is located (col A) and sub (col B) is no
Logger.log('Not Sub');
return SpreadsheetApp.getUi().alert('No Subscription Found');
}
} else {
Logger.log('False');
return SpreadsheetApp.getUi().alert('Not Connected');
//Email not found
}
}
}
You're using return after all three condition checks. You should continue the loop:
Try modifying from:
} else {
Logger.log('False');
return SpreadsheetApp.getUi().alert('Not Connected');
//Email not found
to
} else if(i==value.length-1){ //if i is the last value
Logger.log('False');
return SpreadsheetApp.getUi().alert('Not Connected');
//Email not found

Why is this changed value read as the original after Utilities.sleep?

I have Google Sheets running in OnEdit(). When a cell in a specific row is changed to "completed" an email will be sent to the job owner. For now it pops up a browser message.
But I want to avoid sending an email in the case where the selection is accidental and gets changed again a few seconds later.
The surprising issue is that after running Utilities.sleep(10000) and re-reading the cell's value to make sure it's the same, even if it has been changed, it will read the value again as "completed". Is this something to do with the sleep function?
if (changedColumn == stageColumnIndex) {
var newValue = sheet.getRange(changedRow, changedColumn).getValue(); // read changed cell value before the sleep call
if (newValue.toLowerCase() == "completed") {
// check again in a few seconds in case it was an accidental selection which was quickly changed
Logger.log('Sleeping');
Utilities.sleep(10000);
var checkedValue = sheet.getRange(changedRow, changedColumn).getValue(); // read same cell value after sleep call but it is the same as newValue even when the cell was changed while sleeping
Logger.log('newValue: ' + newValue);
Logger.log('checkedValue: ' + checkedValue);
var announceChange = (checkedValue == newValue);
if (announceChange) {
var streetIndex = 2;
var street = sheet.getRange(changedRow, streetIndex).getValue();
Browser.msgBox("Job completed at " + street + ".");
}
}
}

Create timestamp with script editor when email is sent by Google Spreadsheet

I am currently receiving data through an RSS feed into my spreadsheet. I have a script (below) which I am hoping to run on a time trigger (every minute) to check the data and then in turn send an email out if the data meets certain criteria.
Problem: After the first email is sent out, I want to create a system to check (timestamp?) within the script if an email for that particular row of data has already been sent. Is this the best way to do this? How do I do it? Script is below.
function sendEmail(email_address, email_subject, email_message) {
MailApp.sendEmail(email_address, email_subject, email_message);
}
function test_sendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.setActiveCell('A2');
var criterion_cutoff = 5;
var i = 0;
var addr;
var subj;
var msg;
do {
addr = cell.offset(i,0).getValue();
subj = cell.offset(i,1).getValue();
msg = cell.offset(i,2).getValue();
criterion = cell.offset(i,3).getValue();
if(criterion < criterion_cutoff) {
sendEmail(addr,subj,msg);
Browser.msgBox('Sending email to: ' + addr);
}
i++;
} while( cell.offset(i, 0).getValue().length > 0 )
Browser.msgBox('Done!');
}
If I'm understanding your question correctly, you want some way of marking which rows in the spreadsheet that you've already sent emails for, so that you don't send duplicates. If so, then this tutorial shows one way of doing that: https://developers.google.com/apps-script/articles/sending_emails#section2