Iterate through column, find match and send email based on cell value - google-apps-script

I have a spreadsheet (here -> https://docs.google.com/spreadsheets/d/1U0A8PmKYxkXn8SrfKOo6XsJb-XxkJNYZqd0QIKkFsP4/edit?usp=sharing) that collects data from forms and perform several if functions to categorize answers.
What I need to do is to send follow up emails (reminders) based on cell value (sheet "Code extension data + Minimum desc. fill", last column "Reminder Minimum descriptions"). In order to do that, I suppose I must loop through the column, find a match ("Keep sending reminder", "Stop sending reminder") and send mail.
But what ends up happening is that the code shoots 73 follow up messages. I don't know 73, if I have only 2 rows with "Keep sending email".
function sendEmail() {
var ss = SpreadsheetApp.openById("1lzc7-WRxEBQc5D_SR0F-d-
9PhQjmVk37UOgBQTGw3_Q");
var sh = ss.getSheetByName('Code extension data + Minimum desc. fill');
var lastRow = sh.getLastRow();
var data = sh.getRange(1,28,lastRow,28).getValues();
for (i=0; i < data.length;i++){
var num = parseInt(data[i]);
if (num = "Keep sending reminder") {
var emailAddress = "email#email.com";
var message = "test body";
var subject = "test subject";
MailApp.sendEmail({
name: "Your Name",
to: emailAddress,
subject: subject,
htmlBody: message
});
}
}
}

Your if statement is comparing a number to a string ("Keep sending reminder") which will never evaluate as true. There is no need to use parseInt for what you are trying to do. Also, you are looping over string[][], so you have to use data[i][columnIndex] to access the column you expect to find "keep sending reminder" in.
function sendEmail() {
var ss = SpreadsheetApp.openById("1lzc7-WRxEBQc5D_SR0F-d-9PhQjmVk37UOgBQTGw3_Q");
var sh = ss.getSheetByName('Code extension data + Minimum desc. fill');
var lastRow = sh.getLastRow();
var data = sh.getRange(1,28,lastRow,28).getValues();
for (var i=0; i < data.length; i++) {
//var num = parseInt(data[i]);
if (data[i][27] === "Keep sending reminder") {
var emailAddress = "email#email.com";
var message = "test body";
var subject = "test subject";
MailApp.sendEmail({
name: "Your Name",
to: emailAddress,
subject: subject,
htmlBody: message
});
}
}
}

Your if statement only has a single equal sign, use == or === even better.

Related

Send email based on form input

Im looking for a google apps script that can send email based on form input.
I tried this but this is not working:
for(var i in mailCreator){
if(mailCreator[i][0].match("...#abc.nl")!=null){
MailApp.sendEmail({
to: "123#def.com",
subject: ADDED_TO_GROUP_SUBJECT,
htmlBody: emailBody,
})
}
}```
It would be great if i can search for a certain value in the form input instead of an exact match.
What is mailCreator? Is it an array where is the range with the mails? or Or try to capture a field from the form?
EDIT.
Hi Johan, I think this is better for what you need. I understand that your objetive is to send an email with the data collected from the form. I use this.
This takes the range of the form sheet and sends you an email with the data of the defined variables. We can return more data from the range obtained from the form sheet.
function SendMail() {
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var listamail = spreadSheet.getSheetByName("name sheet");
var dataRange = listamail.getDataRange();
// Fetch values for each row in the Range.
var data = dataRange.getValues();
var text = 'Text for body.';
for (var i = 1; i < data.length; i++) {
(function(val) {
var row = data[i];
var emailAddress = row[1]; //position of email header — 1
var name = row[0]; // position of name header — 1
var message = text ;
var subject = 'Write subjet or ne';
MailApp.sendEmail(emailAddress, subject, message);
})(i);
}
}```
You can call this function whenever you submit the form. But u need edit this and only use last value of range.
var ADDED_TO_GROUP_DOC_URL = 'https://docs.google.com/location of your document';
function onFormSubmit(e) {
var mailCreator = formValues['E-mailadres'][0].trim();
var subject = 'Subject title';
var addedToGroupDocId = DocumentApp.openByUrl(ADDED_TO_GROUP_DOC_URL).getId();
var emailBody = docToHtml(addedToGroupDocId);
MailApp.sendEmail({
to: mailCreator,
subject: subject,
htmlBody: emailBody,
});
}```

"Email_Sent" message not updating to the spreadsheet as it should

I'm having trouble with the "Email _Sent" text. It is supposed to appear next to the recipient who received the email from my spreadsheet. However, when I select certain emails to send the message to, the text "Email _Sent" starts filling out the first empty rows in my spreadsheet. In this way, the text appears beside some recipients who didn't receive the message.
I'll post the script that I'm using:
function sendGeneralEmail() {
var Email = 4;
var Name = 3;
var emailSent = 6;
var subject = "Sample Analysis Service"
var html = HtmlService.createTemplateFromFile("SUM.1");
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test");
var data = ws.getRange("A5:G" + ws.getLastRow()).getValues();
data = data.filter(function(r){ return r[5] == true});
var Email_Sent = 'Email_Sent';
var sheet = SpreadsheetApp.getActiveSheet();
var notBlank = sheet.getRange("D5:G5");
var lastRow = notBlank.getLastRow();
data.forEach(function(row){
html.en = row[Name];
var htmlMessage = html.evaluate().getContent();
if(emailSent !=Email_Sent) {
GmailApp.sendEmail(
row[Email],
subject, "Your Email doesn't support HTML", {
name: "MASAR Team",
htmlBody: htmlMessage},
);
sheet.getRange(lastRow, 7, data.length, 1).setValue(Email_Sent);
SpreadsheetApp.flush();
}
});
}
Can someone help me to fix that?
The second issue is that, if I run the script and then stopped and came back and run it again on the same day, the text "Email_sent" stops updating to the spreadsheet. It only appears the first I run the script during the day.
Screenshot
Hope to have a solution to this
I tried to replicate your code and found some issues:
using setValue on range with multiple cells will copy the value to all cells within the range. In your example, all cells in getRange(lastRow, 7, data.length, 1) will have the value "Email_Sent". This causes the unwanted write of "Email_Sent" in your spreadsheet.
if(emailSent !=Email_Sent) will always true because '6' is not always equal to 'Email_Sent'
Based on your example, your goal is to send an email and write "Email_Sent" to the Email Status column of the recipient.
Here, I fixed some part of your code and added features.
Code:
function sendGeneralEmail() {
var subject = "Sample Analysis Service"
// var html = HtmlService.createTemplateFromFile("SUM.1");
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test");
var data = ws.getRange("A5:G" + ws.getLastRow()).getValues();
var sheet = SpreadsheetApp.getActiveSheet();
for(var i=0; i<data.length; i++){
var selected = data[i][5];
var emailStatus = data[i][6];
if(selected && emailStatus != "Email_Sent"){
var email = data[i][4];
// html.en = row[Name];
// var htmlMessage = html.evaluate().getContent();
GmailApp.sendEmail(
email,
subject, "Your Email doesn't support HTML", {
name: "MASAR Team",
message: "ABCD",
// htmlBody: htmlMessage},
}
);
sheet.getRange(i+5, 7, 1, 1).setValue("Email_Sent");
}
}
}
Note: I commented the html parsing since I don't have the sample html and replaced the email message with a string.
Before running the script:
After running the script:
Reference:
setValue()

GOOGLE SCRIPT SEND EMAIL WHEN CONDITION MET

Hi I am doing some codes in google script but the output that I am expecting did not happen.
Here is the code that i came up with hope you can help me solve this problem,
function sendEmail() {
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = activeSheet.getLastRow();
var dRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("March Cycle").getRange("I6")
var rData = dRange.getValue();
var templateTxt = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1,1).getValue();
for (var i = 6;i<=lr;i++) {
if(rData = "Touch Course Completed") {
var frstname = activeSheet.getRange(i,4).getValue();
var lstname = activeSheet.getRange(i,3).getValue();
var gradelvl = activeSheet.getRange(i,5).getValue();
var msgbody = templateTxt.replace("{name of student}",(frstname + " " + lstname)).replace("{Gr Lvl}",gradelvl);
MailApp.sendEmail("email add","Test Email",templateTxt);
}
Logger.log(msgbody);
}
}'
below is the data of picture that i wanted to automate.
enter image description here
Thank you
There are a couple of mistakes you have on your code. Let me show you in my comments on this working code.
Code:
function sendEmail() {
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var templateTxt = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1, 1).getValue();
var lr = activeSheet.getLastRow();
// Compile list of students with "Touch Course Completed" in array before sending
var msgbody = [];
// You need to get the range of all data on column I for it to be optimized
var dRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("March Cycle").getRange("I6:I"+lr);
var rData = dRange.getValues();
// rData is equal to [[Touch Course Completed],[Touch Course Completed],[Not completed]]
// Loop all column I data
rData.forEach(function (data, i){
// Since rData is 2D array, the cell should be accessed by data[0]
if (data[0] == "Touch Course Completed") {
// i is the index of the rData array per loop, so 0 is equivalent to row 6
// We need to offset it to get the correct row
var frstname = activeSheet.getRange(i + 6, 4).getValue();
var lstname = activeSheet.getRange(i + 6, 3).getValue();
var gradelvl = activeSheet.getRange(i + 6, 5).getValue();
// My idea here is optional, but I prefer sending it on 1 email instead of separate per student
// That way, we do it faster and more efficient (note that there are quota/limits on sending mail thus doing this is better)
// But if you need it separate, then do what you did in your script
// I push all message first, then send as bulk outside the loop with join
msgbody.push(templateTxt.replace("{name of student}", (frstname + " " + lstname)).replace("{Gr Lvl}", gradelvl));
}
});
// Send an email only IF there is a "Touch Course Complete" student
if(msgbody)
MailApp.sendEmail("email", "Test Email", msgbody.join("\n"));
}
March Cycle:
Template:
Email:
Note:
Note that the earlier tests did send the email separately. If you need them separate then send it every loop (no need for arrays). But if not, then the code above should be better.
EDIT:
To only send the last row, there can be 2 approach that comes to mind:
Add a column for the identification of the data if it was already sent
You will need to add a column.
If new data doesn't contain "Touch Course Completed", it will not send anything.
If you added multiple rows that contains "Touch Course Completed", all of them will be sent.
Get the last row of msgbody
You will not need to add a column.
If new data doesn't contain "Touch Course Completed", it will send the last row with "Touch Course Completed" that was already sent before.
This will not send multiple rows if ever you added more than 1 "Touch Course Completed"
First approach:
function sendEmail() {
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var templateTxt = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1, 1).getValue();
var lr = activeSheet.getLastRow();
var msgbody = [];
// Get all headers, check if there is "Already Sent" header
var lc = activeSheet.getLastColumn();
var headers = activeSheet.getRange(1, 1, 1, lc).getValues();
var sentColumn;
if(!headers[0].includes("Already Sent")){
// If not found, add header "Already Sent" right to the last column
sentColumn = lc + 1;
activeSheet.getRange(1, sentColumn).setValue("Already Sent");
}
else {
// If found, get column number of existing "Already Sent" header
sentColumn = headers[0].indexOf("Already Sent") + 1;
}
var dRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("March Cycle").getRange("I6:I"+lr);
var rData = dRange.getValues();
rData.forEach(function (data, i){
if (data[0] == "Touch Course Completed") {
var frstname = activeSheet.getRange(i + 6, 4).getValue();
var lstname = activeSheet.getRange(i + 6, 3).getValue();
var gradelvl = activeSheet.getRange(i + 6, 5).getValue();
// Check if column is already populated with "Y"
var isSent = activeSheet.getRange(i + 6, sentColumn).getValue();
if(isSent != "Y"){
// If column value is not "Y", then add row to the email to be sent, also put "Y" on the column after
msgbody.push(templateTxt.replace("{name of student}", (frstname + " " + lstname)).replace("{Gr Lvl}", gradelvl));
activeSheet.getRange(i + 6, sentColumn).setValue("Y");
}
}
});
// Modified condition for checking array
if(msgbody.length > 0)
MailApp.sendEmail("email", "Test Email", msgbody.join("\n"));
}
Sample data:
Output:
Email:
Note:
The script will automatically add/locate the header, so no need to adjust your sheet manually.
But you can still initialize a column to become "Already Sent" by writing the header name on the first row of the column and write "Y" to those rows you don't want to be sent anymore.

Google Apps Script - How to get email addresses from Sheet2 and send email

I have a Spreadsheet that stores Task on on Sheet 1. When a task is completed a email is sent. Sheet 2 holds the specific email addresses for send to, cc, and reply to. I am able to loop through sheet 2 and get the email addresses for each column. I want to be able to get those email address into my options for the send email in MailApp. I am unable to get the email addresses out of the loop for sheet 2. See code below. Any help would be appreciate.
var EMAIL_SENT = "EMAIL_SENT";
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheets()[0];
var sheet2 = ss.getSheets()[1];
var startRow = 2;
var lastRow1 = sheet1.getLastRow()-1;
var lastCol1 = sheet1.getLastColumn();
var lastRow2 = sheet2.getLastRow()-1;
var lastCol2 = sheet2.getLastColumn();
var sh1Range = sheet1.getRange(startRow, 1, lastRow1, lastCol1).getValues();
var sh2Range = sheet2.getRange(startRow, 1, lastRow2, lastCol2).getValues();
var subject = "Test Email";
//sheet2 Email Loop
for (var i = 0; i < sh2Range.length; ++i){
var emails = sh2Range[i];
var to = emails[0];
var cc = emails[1];
var replyTo = emails[2];
}
//sheet1 Data Loop and Send Email
for (var j = 0; j < sh1Range.length; ++j){
var data = sh1Range[j];
var pName = data[0];
var pID = data[1];
var pm = data[2];
var dd = Utilities.formatDate(new Date(data[3]), "America/New_York", "MMMM dd, yyyy");
var team1 = data[4];
var status = data[7];
if (team1 == "Task Completed" && status !== EMAIL_SENT){
var htmlBody;
htmlBody = "Project Name: "+pName+"<br>"+"Project ID: "+pID+"<br>"+"Project Manager: "+pm+"<br>"+"Due Date: "+dd+"<br>";
var optAdvancedArgs = {replyTo: replyTo, cc: cc, name: "Test Email", htmlBody: htmlBody};
//Logger.log(htmlBody);
//Logger.log(optAdvancedArgs);
}
}
}
The question is a little broad, and there are many ways to do what you're looking for. It's tough to say what you should choose when the specifics of your application aren't clear, such as how many addresses are going to be on Sheet 2, and if you really need to go through an 'if' statement, but I'll offer two potential solutions here that may be of use.
Solution 1: What I was trying to ascertain in my comments above was if the email addresses list would be the same length as the list of projects (For example, if there are 10 projects on sheet 1, does that mean there are 10 rows of email addresses in sheet 2). It's still not clear to me, as you have a list of email addresses in your 'CC' address, yet only one in your 'Send to' and 'Reply to' addresses (so you don't really need to loop through the whole range, but perhaps that's required for some other part of the project). However, if that IS the case, then you can actually do all of this in one 'for' loop:
//sheet1 Data Loop and Send Email
for (var j = 0; j < sh1Range.length; ++j){
var data = sh1Range[j];
var pName = data[0];
var pID = data[1];
var pm = data[2];
var dd = Utilities.formatDate(new Date(data[3]), "America/New_York", "MMMM dd, yyyy");
var team1 = data[4];
var status = data[7];
if (team1 == "Task Completed" && status !== EMAIL_SENT){
var emails = sh2Range[i];
var to = emails[0];
var cc = emails[1];
var replyTo = emails[2];
var htmlBody;
htmlBody = "Project Name: "+pName+"<br>"+"Project ID: "+pID+"<br>"+"Project Manager: "+pm+"<br>"+"Due Date: "+dd+"<br>";
var optAdvancedArgs = {replyTo: replyTo, cc: cc, name: "Test Email", htmlBody: htmlBody};
//Logger.log(htmlBody);
//Logger.log(optAdvancedArgs);
}
}
Solution 2: Otherwise, you could place the email addresses into an array when you loop through them:
var addresses = [];
for (var i = 0; i < sh2Range.length; ++i){
var emails = sh2Range[i];
var to = emails[0];
var cc = emails[1];
var replyTo = emails[2];
addresses.push([to,cc,replyTo])
}
Which will then allow you to access them using the bracket notation 'addresses[0][0]' later in the script:
var optAdvancedArgs = {replyTo: addresses[0][2], cc: addresses[j][1], name: "Test Email", htmlBody: htmlBody};
Both these solutions make a lot of presumptions on what you're doing, but they might guide you to either the answer you're looking for, or possible give you a more concrete idea of what kind of question you're asking.

Google Apps Script sendEmail: multiple recipients string?

Using sendEmail, how can I send an email to multiple comma-separated recipients by combining two form fields? It seems to work when (lastrow,4) has only one value (abc#domain.com) but not for more than one (abc#domain.com, xyz#domain.com). Current code is below, and the variable in question is recipientsTo.
function FormEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetform = ss.getSheetByName("Sheet1"); // Name of the sheet which contains the results
var lastrow = sheetform.getLastRow();
var recipientsTO = sheetform.getRange(lastrow,3).getValue() + "#domain.com";
var recipientsCC = ""
var team = sheetform.getRange(lastrow,5).getValue();
var datestamp = Utilities.formatDate(sheetform.getRange(lastrow,1).getValue(), "GMT - 5", "yyyy-MM-dd");
var html = "Intro text;
//The questions order in the email will be the order of the column in the sheet
for (var i = 2; i < 11; ++i) {
html = html + "<b>" + sheetform.getRange(1,i).getValue() + "</b><br>";
html = html + sheetform.getRange(lastrow,i).getValue() + "</p><br>";
}
//Add additional emails if entered in form field
if (sheetform.getRange(lastrow,4).getValue() !== "") {
recipientsTO = recipientsTO + "," + sheetform.getRange(lastrow,4).getValue()
}
//CC if response to a question is "Yes"
if (sheetform.getRange(lastrow,10).getValue() == "Yes") {
recipientsCC = "ccEmaIL#gmail.com"
}
MailApp.sendEmail({
to: recipientsTO,
cc: recipientsCC,
subject: "Subject",
htmlBody: html,
});
}
According to the sendEmail(message) documentation, the TO field only has one recipient.
Whereas the CC field can have multiple recipients separated by comma.
http://goo.gl/CGjiJ
`to - String - the address of the recipient.
cc -String - a comma separated list of email addresses to CC`
Another option would be to use sendEmail(String,String,String,Object) in that function "recipient String the addresses of the recipients, separated by commas".
Hope this helps.
Here is code from my production script:
//check quota and log
const emailsLeft = MailApp.getRemainingDailyQuota();
console.log( emailsLeft + " emails left in quota");
//get list of emails from spreadsheet itself
//filter out empty rows
const emails = getTab("Config").getRange("D2:D").getValues().map(function(el){ return el[0]; }).filter(function(el){ return el != '' });
//send emails from NO_REPLY email, subject and HTML body
MailApp.sendEmail({
to: emails.join(","),
subject: subject,
htmlBody: html,
noReply: true
});
function getTab(name) {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
return sheet.getSheetByName(name);
}
getTab() and other helper functions can be found here
https://github.com/tim-kozak/google-spreadsheet-helpers