Wazzup guys, thanks to this website, I was able to get a code that allows sending email reminders. Now, I wanted to send only reminders based on date, particularly when the Reminder date matches the date today. I found out this awesome post, but was still not able to make it work.
I tried several attempts to google similar cases, but to no avail. The code is actually working without the "based on date" condition, but I can't seem to work it out. I tried changing formats, used the "Utilities" in the script, but still nothing.
Below is how the sheet looks like and as well the code. So on the current data, I should be receiving an email reminder for the "Go to gym" task, but I don't get any (I've included my correct email in column A though).
Where could have this gone wrong? Hoping for your insights and guidance on this. Thanks!
var EMAIL_SENT = "Yes";
function sendEmails() {
var now = new Date().toLocaleDateString();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var startRow = 2;
var sheet = ss.getSheetByName ('Tasks')
var numRows = sheet.getLastRow();
var dataRange = sheet.getRange(startRow, 1, numRows, sheet.getLastColumn());
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0];
var message = row[2];
var ReminderDate = row[3];
var emailSent = row[4];
var subject = "Task reminder: "+row[1];
if (ReminderDate != now)
continue;
if (emailSent != EMAIL_SENT) {
message = "Good day! This is to remind you of a spefic task: "+ message +". \n\nThis reminder was triggered by the task monitoroing sheet: "+ ss.getUrl()
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 5).setValue(now);
SpreadsheetApp.flush();
}
}
}
Issue:
At Spreadsheet, when the date is used, the value retrieved by getValue() and getValues() is the date object. In your script, when row[3] of var row = data[i] is the date object, if (ReminderDate != now) is always false.
Modified script:
In order to avoid above issue, please modify as follows, because now of if (ReminderDate != now) is var now = new Date().toLocaleDateString();.
From:
var ReminderDate = row[3];
To:
var ReminderDate = row[3].toLocaleDateString();
Reference:
toLocaleDateString()
Related
I've just started with Javascript in AppScripts and I'm trying to piece together a system that will send emails based on the type of resident we have (owner, renter, renewal). Right now, this code is sending the same email to everyone on the spreadsheet when I run the script or click the assigned "sendEmails" button. I want co-workers to be able to send the emails to the appropriate resident type after they have made an appointment for them, individually. I have a data validation drop down column with the different types. Is there a way that upon clicking the resident type in the drop-down that the appropriate email will go out according to resident type? Any assistance is appreciated! Complete novice here, but this would really help our workflow immensely.
function sendEmail() {
//Email for New Tenant Only
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Schedule Residents");
var lr = ss.getLastRow();
var templateText = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1,1).getValue();
for (var i = 2;i<=lr;i++){
var currentEmail = ss.getRange(i, 11).getValue();
var currentDate = ss.getRange(i, 1).getValue();
var currentName = ss.getRange(i, 3).getValue();
var messageBody = templateText.replace("{name}",currentName).replace("{date}",currentDate);
var subjectLine = "Reminder: " + currentDate + " Upcoming Appointment";
MailApp.sendEmail(currentEmail, subjectLine, messageBody);
}
}
You can use the onEdit that allows you to send an email when an edit is taking place in the sheet
Triiger allow you to use event objects that are tied to the event causing the trigger to fires
That is you can query which range has been edited, what is the new value etc.
You can implement that an email is automatically sent when a resident type is set and retrieve dynamically the correct template
For sending limits you cannot use the simple onEdit trigger due to limitations
Instead, bind to your function manually an installable onEdit trigger
Mind that functions containg event objects (e) will error if you try to run them manually - they run automatically on trigger event
Sample function to be bound to a trigger:
function sendOnEdit(e) {
//Email for New Tenant Only
var ss = e.range.getSheet();
var typeColumn = 4;
if (sheet.getName() == "Schedule Residents" && e.range.getColumn() == typeColumn){
var row = e.range.getRow();
var value = e.value;
var templates = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1,1,3,1).getValues();
var templateText;
switch (value){
case "Email New Owner":
templateText = templates[1][0];
break;
case "Email New Tenant":
templateText = templates[0][0];
break;
case "Email Renewal":
templateText = templates[2][0];
break;
}
var currentEmail = "ziganotschka1#egs-sbt015.eu"//ss.getRange(row, 11).getValue();
var currentDate = ss.getRange(row, 1).getValue();
var currentName = ss.getRange(row, 3).getValue();
var messageBody = templateText.replace("{name}",currentName).replace("{date}",currentDate);
var subjectLine = "Reminder: " + currentDate + " Upcoming Appointment";
MailApp.sendEmail(currentEmail, subjectLine, messageBody);
}
}
I have a code that sends an email to different recipients based on a google sheet. However, the code keeps on sending emails to the "owner" recipient, which I hope to stop. To explain further, please see below details.
Here's where people put in their email addresses, tasks, etc.:
These data are then processed in a hidden sheet that uses several array functions to consolidate tasks for similar emails:
Now, I'm currently using this code, which perfectly works, except for one flaw:
function sendEmails() {
var now = new Date().toLocaleDateString();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var startRow = 2;
var sheet = ss.getSheetByName ('Tasks')
var numRows = sheet.getRange("H1").getValue();
var dataRange = sheet.getRange(startRow, 1, numRows, sheet.getLastColumn());
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0];
var message = row[1];
message = message.replace(/\n/g, "</li><li>");
var ReminderDate = row[2].toLocaleDateString();
var Status = row[4];
var subject = "Task reminders";
if (ReminderDate > now)
continue;
if (Status == 1) {
var Email = {
to: emailAddress,
subject: "Task reminders | "+now,
htmlBody:
"Good day! This is to remind you of the following specific task/s:"+
"<br />"+
"<ul><li>"+message+"</li></ul>"+
"<br />"+
"You can access the Task monitoring sheet by clicking here.",
name: "Taks monitoring",
};
MailApp.sendEmail(Email);
sheet.getRange(startRow + i, 4).setValue(now);
SpreadsheetApp.flush();
}
}
}
And here's what is happening:
Tasks for email2 are sent to email2 (Yes!)
Tasks for email1 and email2 are sent to email1 (Oh no!)
I don't like the second bullet from happening, since I only want what's email1 to be sent to email1. I've analyzed the code step-by-step, but I'm not really sure what's wrong in here as to why it keeps doing the second bullet. I tried entering a new email3, and the code also sends email3's tasks to email1.
Any ideas on why this is happening, and suggestions to prevent it?
Just to note: email1 owns the google sheet (I think it has something to do with that).
I have an emailer script that I would like to run for specified tabs and also make sure it skips any rows with blank values as it currently seems to break down as soon as it hits a blank row.
I have successfully built the script to work for one tab, but it seems to break down as soon as I try and get it to work for multiple tabs.
function reminders() {
var ss = SpreadsheetApp.openById("SHEET-ID");
var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName(("sheet_1","sheet_2","sheet_3")));
var editedCell = sheet.getActiveRange().getColumnIndex();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var text1 = 'Insert body of email here';
for (var i = 1; i < data.length; i++)
(function(val) {
var row = data[i];
var recipient = row[4];
var name = row[2];
var replyto = 'reply_to#email.com';
var body = 'Dear' + ' ' + name + ',' + '\n\n' + text1;
var subject = 'Hello World';
GmailApp.sendEmail(recipient, subject, body, {from:'reply_to#email.com', replyto:'reply_to#email.com'});
})(i);
}
This currently works for sheet_1 but does not work for sheet_2 or sheet_3.
Does anyone have any suggestions for how I can improve this script to send to multiple sheets and also skip blank rows?
You want to send emails using the values of column "C" and "E" from the Spreadsheet.
You want to run your script for the sheet names of "sheet_1", "sheet_2" and "sheet_3".
You want to skip the rows which have no values of the column "C" and/or "E".
If my understanding is correct, how about this modification?
Modification points:
It seems that when var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName(("sheet_1","sheet_2","sheet_3"))); is run, only "sheet_3" is retrieved.
In your case, I think that setActiveSheet() might not be required to be used.
Number of arguments of getSheetByName(("sheet_1","sheet_2","sheet_3")) is one.
When you want to use multiple sheets, please use each sheet name in the loop.
var editedCell = sheet.getActiveRange().getColumnIndex(); is not used in your script.
val of (function(val) { is not used in your script.
When you want to skip the empty rows, please put the if statement before GmailApp.sendEmail(). By this, the error is removed at GmailApp.sendEmail().
When above points are reflected to your script, it becomes as follows. Please think of this as just one of several answers.
Modified script:
Please copy and paste the following modified script to the script editor.
function reminders() {
var sheets = ["sheet_1","sheet_2","sheet_3"]; // Please set the sheet names here.
var ss = SpreadsheetApp.openById("SHEET-ID");
for (var s = 0; s < sheets.length; s++) {
var sheet = ss.getSheetByName(sheets[s]);
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var text1 = 'Insert body of email here';
for (var i = 1; i < data.length; i++) {
var row = data[i];
var recipient = row[4];
var name = row[2];
if (!recipient || !name) continue; // Here, the empty rows are skipped.
var replyto = 'reply_to#email.com';
var body = 'Dear' + ' ' + name + ',' + '\n\n' + text1;
var subject = 'Hello World';
GmailApp.sendEmail(recipient, subject, body, {from:'reply_to#email.com', replyto:'reply_to#email.com'});
}
}
}
Note:
In this modified script, when "recipient" or "name" are not existing, the row is skipped.
When you send a lot of emails, please be careful the quotas of "Email read/write". You can see it at here.
References:
getSheetByName(name)
Quotas for Google Services
If I misunderstood your question and this was not the result you want, I apologize.
I'm trying to send a reminder for a weekly webinar with emails that live on a Google Sheet using Google's script editor/codelab. The link for the tutorial it's based off of is here: https://developers.google.com/apps-script/articles/sending_emails
In their second section of code they post, it is an improved version because after the email is sent it populates a column with "EMAIL_SENT" and should prevent a duplicate email being sent out because "EMAIL_SENT" occupies that space (as I understand it).
My problem is that after I run the script, I'm able to get the emails to send off (I used three email accounts and each one received it), but I also get an error that reads:
Failed to send email: no recipient (line 24, file "macros").
Macros is the name of the file. The other issue I'm having is that if I run the script again after EMAIL_SENT has populated, it still sends an additional email even though it's not supposed to.
I've tried making the object in the first portion of the code different numbers to try and capture the right data. After I got the right data in there I don't understand why the other portions won't work.
`// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = 'EMAIL_SENT';
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails_w_verification() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 116; // First row of data to process
var numColumns = 8;
var startColumn = 1;
// Fetch the range of cells as object
var dataRange = sheet.getRange(startRow, startColumn,
sheet.getLastRow(), numColumns);
// 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[1]; // Second column
var message = "Thank you for registering for the webinar"; // Second
column
var emailSent = row[8]; // ninth column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = 'AFWERX Webinar Reminder';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 9).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is
interrupted
SpreadsheetApp.flush();
}
}
}
Expected duplicates not to send and no error message of "Failed to send email: no recipient (line 24, file "macros")" when the email sent.
Your first no recipient error seems to be caused by how you're starting your for loop, if you switch it to i++ instead, the script runs fine. This is because by using ++i you're picking up an extra row which doesn't have any email address in it, causing it to throw the "no recipient" error you're getting.
The second issue with the script not being able to check against column 9 is because the range you defined is only 8 columns wide, not 9. I found this by using a simple Logger.log(emailSent) which came back as undefined, which is what you'd expect to see if the value isn't even being defined in the range at all.
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = 'EMAIL_SENT';
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails_w_verification() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 1; // First row of data to process
var numColumns = 9;
var startColumn = 1;
// Fetch the range of cells as object
var dataRange = sheet.getRange(startRow, startColumn, sheet.getLastRow(), numColumns);
// 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[1]; // Second column
var message = "Thank you for registering for the webinar"; // Second column
var emailSent = row[8]; // ninth column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = 'AFWERX Webinar Reminder';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 9).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
I've changed the for statement to use i++ rather than ++i which fixes the "no recipient" error message.
for (var i = 0; i < data.length; i++) {
Then changed your var numColumns to 9 rather than 8 so that it can see the column you're trying to check with your if statement.
var numColumns = 9;
I am trying to write a script in google sheets that will send one of two different emails based on the response to a multiple choice question. I can get my if/else statement to send either one or the other of the emails but it will not recognize the text of the multiple choice answer and send the correct email.
Here is the full script:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1;
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
// 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 title = row[1]; // First column
var startDate = row[3]; // Second column
var endDate = row[4];
var description = row[2];
var location = row[6];
var eventImport = row[5];
var emailAddress = row[7];
var multchoice = row[8];
if (multchoice == "Part Time") {
var subject = "New Hire Part Time Email - " + startDate;
var emailBody = "Congradulations"
var htmlBody = "Congradulations! Part time person"
MailApp.sendEmail (emailAddress, subject, emailBody);
} else {
var subject = "New Hire Appointment - " + startDate;
var emailBody = "Congratulations! We are excited"
var htmlBody = "Congratulation! </i><br/> <br/> We are excited"
MailApp.sendEmail(emailAddress, subject, emailBody);
}
}
}
I believe the problem is here:
if (multchoice == "Part Time")
Any help is greatly appreciated! I am a novice
It looks like you are assigning your variables starting with '1' I stead of '0'. Start assigning them with 0 and counting up.
Without an example sheet to use, I won't be able to do a whole lot of debugging for you.
However, Apps Script comes with it's own debugger. Select the function you wish you debug and click the Little bug icon beside the play button.
Click on the sidebar where you want to set a breakpoint, where the code will stop executing.
Once it hits that breakpoint you can see all the variables currently within your scope. So the array, value, and i variables are visible to you.
Use this to your advantage and debug your code to find out where the issue is. Alternatively, you can use Logger.log() to log values at certain points within your code and then read back through the logs to try and determine where the problem lies.
The problem is not with your if/else statement. The problem is with how you are assigning your variables from your row[] array. While you use regular numbers in the getRange() function, the range that is returned is an array of those cells. Arrays always start with an index of [0]. Change var multchoice = row[8] to var multchoice = row[7] and your if/else statement will work (you'll want to change all of your other references, too).