How to send email to only selected emails from google sheet? - google-apps-script

new to google script, I have a google script with a button on the sheet which sends out emails from a google sheet, it works fine.
however I want to send emails to those emails that I checkmark manually, I have a column (F) with a checkmark, so I want to checkmark emails then send emails to those emails that have been check-marked only.
I stuck in the completion of the coding for the checkmark part, I appreciate your help.
I have commented out my 2 lines of code for filtering the checkmarks.
the code check for send email quote as well as writes timestamp and email sent note every time email has been sent.
Thanks.
these are columns, one header:
A1: timestamp
B1: email address
C1: Name
D1: Email Sent?
E1: Data emaill sent
F1: check box
function sendEmails(){
var sheet = SpreadsheetApp.openById("mySheetid");
var ss = sheet.getSheetByName("Emails");
var lr = ss.getLastRow();
var EMAIL_SENT = 'Email has been sent';
var messageSubject =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("BodyTextSheet").getRange(2, 1).getValue();
var messageText = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SubjectSheet").getRange(2, 2).getValue();
var quotaLeft = MailApp.getRemainingDailyQuota();
if ((lr-1) > quotaLeft){
Browser.msgBox("you have " + quotaLeft + "left and you're trying to send " + (lr-1) + "emails. Emails were not sent.");
} else{
for (var i = 2; i<=lr; i++){
var currentEmail = ss.getRange(i, 2).getValue();
var currentName = ss.getRange(i, 3).getValue();
var messageBody = messageText.replace("{name}",currentName);
//var selected = ss.getRange("F2:F" + ss.getLastRow()).getValues();
//data = selected.filter(function(r){ return r[6] == true});
MailApp.sendEmail(currentEmail, messageSubject, messageBody);
var EmailSent = ss.getRange(i, 4).setValue(EMAIL_SENT);
var TimeEmailSent = ss.getRange(i, 5).setValue(new Date());
SpreadsheetApp.flush();
}
}
}

This worked out when i tested it. In your code you have BodyTextSheet with the var: messageSubject and viseversa... This is a bit confusing. So you need to change those ranges in this code.
function sendEmails() {
const ss = SpreadsheetApp.openById("mySheetid");
const emailSheet = ss.getSheetByName("Emails");
const bodyText = ss.getSheetByName("BodyTextSheet").getRange(2, 1).getValue()
const subjectText = ss.getSheetByName("SubjectSheet").getRange(2, 2).getValue()
const emails = emailSheet.getDataRange().getValues();
const filterdRows = [];
for (i = 0; i < emails.length; i++) {
const row = emails[i]
if (row[5] == true) {
row.unshift(i+1)
filterdRows.push(row)
}
}
const quotaLeft = MailApp.getRemainingDailyQuota();
if (filterdRows.length > quotaLeft) {
Browser.msgBox(`you have ${quotaLeft} left and you're trying to send ${filterdRows.length} emails. Emails were not sent.`);
} else {
filterdRows.forEach(email => {
const messageBody = bodyText.replace("{name}", email[3]);
MailApp.sendEmail(email[2], subjectText, messageBody);
emailSheet.getRange(email[0], 4, 1, 2).setValues([['Email has been sent', new Date()]])
})
SpreadsheetApp.flush();
}
}
So i made some modifications:
const emails: Get all the emails at once (much quicker)
Loop over the data and check if column F (arrays are 0 indexed so column 5) is true
If is true then add i+1 (rownumber) to the beginning of the array
Then forEach filtertEmail send the mail and set set text and date in the right row (in one call) That is why i pushed the rownumber in the beginning.

Related

Sending an Email from google sheets only once

The code below works perfectly and sends the email I need it to send on an "OnChange" trigger. However, it sends an email for EVERY checked box in row 7 which is overload, it just needs to send an email for newly checked boxes.
Any advice on how to add a condition in the below code for this?
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Service');
var data = sheet.getDataRange().getValues();
for (var i = data.length - 1; i >= 1; i--) {
if (sheet.getRange(i,7).isChecked()){
var name = sheet.getRange(i,1).getValue();
var last = sheet.getRange(i,2).getValue();
var body = name + " " + last
var subject = 'New Service Item in Stock'
MailApp.sendEmail('me#mycompany.com', subject, body);
}
}
}
I haven't tried anything because there is nothing I could find online to get me in the right direction.
https://i.stack.imgur.com/cKfLv.png
Try unchecking them after you send them:
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Service');
var data = sheet.getDataRange().getValues();
for (var i = data.length - 1; i >= 1; i--) {
if (sheet.getRange(i, 7).isChecked() && sheet.getRange(i,8).getValue() != "Sent") {
var name = sheet.getRange(i, 1).getValue();
var last = sheet.getRange(i, 2).getValue();
var body = name + " " + last
var subject = 'New Service Item in Stock'
MailApp.sendEmail('me#mycompany.com', subject, body);
sheet.getRange(i, 8).setValue("Sent");
}
}
}
Performance improvement:
function sendEmails() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('Service');
var vs = sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getValues();
vs.forEach((r, i) => {
if (sh.getRange(i + 2, 7).isChecked() && r[7] == "Sent") {
let body = `${r[0]} ${r[1]}`;
let subject = "New Service Item in Stock";
MailApp.sendEmail('me#mycompany.com', subject, body);
sh.getRange(i, 8).setValue("Sent");
}
});
}

Google Script: sending email as thread instead of individual emails

Currently have this script to send out approval request emails to relevant approvers. However would want for this to be sent out as a thread instead of spamming individual emails. Is there anything I could insert into my script to help with this? Thanks in advance!
function sendEmail(){
//drawing from the active sheet.
var sheet = SpreadsheetApp.getActiveSheet();
//setting variables & getting the data from the sheet you are on
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow(); // Number of rows to process
var numColumns = sheet.getLastColumn(); //Number of columns to process
var dataRange = sheet.getRange(startRow, 1, numRows-(startRow-1), numColumns);
var data = dataRange.getValues();
var complete = "sent";
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var aemail = row[16]; //approver’s email
var approval = row[13]; //approval column
var reqrow = row[17]; //req row number
var emailed = row[18]; //already emailed
//check to see if an email has NOT been sent
if (emailed != complete){
//check to see if not yet approved
if(approval == ""){
//When done, it will mark it as sent in the last column
var sent = sheet.getRange(startRow + i, numColumns);
//Setting it to send the email to the approver's email
var email = aemail;
//Change the text as desired
var subject = "Quotation Request";
// \n is a line break
var emailtext = "Hi, " +
"\n\nYou have quotation request pending your review and approval on row " + reqrow + ".\n" +
"\nPlease go to the link below for your further action.\n" +
"\nhttps://docs.google.com/spreadsheets/d/x123/edit?usp=sharing \n" +
"\nThis is an automated email. Thanks."
//Send the email
GmailApp.sendEmail(email, subject, emailtext);
//Assign “sent” to to the last cell in the row so the email does not send again
sent.setValue(complete);
}
}
}
}
You would need to add parameter Message-Id in every email to achieve threading in recipient's mailbox.
However, GmailApp.sendEmail does not support this feature.
https://developers.google.com/apps-script/reference/gmail/gmail-app#sendEmail(String,String,String)

Sending automatic emails to specific email addresses once rows are edited in google sheet

I'm new to g-scripts and facing some issues in coming up with the code for the below. My goal is:
Want to send an automatic email to specific people once the information in any of the rows in the google sheet are edited.(note: the range is the whole sheet)
For each row in the google sheet, there's an email address next to it (under a new column) which specifies the person this automatic email should be sent to.
Can the changes be compiled once per day and sent via 1 email per email address?
Thank you in advance for your help.
Currently, this is my code:
function onEdit(e){
var rows = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet1").getRange(30000,30).getValue();
var headerRow = rows.shift();
var editedRow = e.range.getRow();
var template = HtmlService.createTemplateFromFile("Template1.html");
template.headerRow = headerRow;
template.editedRow = editedRow;
template.rows = rangeValues;
var html = template.evaluate().getContent();
function sendEmails(){
var ss=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet1").activate();
var ss=SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr=ss.getLastRow();
//getting email body:
var sheet2Text = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet2").getRange(1,1).getValue();
// Logger.log(emailText);
var quotaLeft = MailApp.getRemainingDailyQuota();
Logger.log(quotaLeft);
if((lr-1)>quotaleft){
Browser.msgBox("You have"+quotaLeft+"left & you're trying to send"+(lr-1)+"emails. Emails not sent");
} else{
for(var i=2; i<lr; i++){
var currentEmail = ss.getRange(i,26).getValue();
var currentClientName = ss.getRange(i,1).getValue();
var currentTeamName = ss.getRange(i,27).getValue();
var messageBody = sheet2Text.replace("{name}",currentTeamName);
var subjectLine = "notification on" + currentClientName + "process list", html;
MailApp.sendEmail(currentEmail, subjectLine, messageBody);
//26 is the column number that contains the emails in the google sheet
} //closing the for loop
} // closing the else loop
} // closing the function sendEmails
} // closing the onEdit function

"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()

Sending automatic email on specific day of the month based on day entered in a cell

I am trying to send an email from Google Apps Script on a specific day of the month based on the day that a user enters into a cell on the Sheet.
Currently I use a formula as below to send emails which sends to users based on cell values:
function sendChangeDetailsEmail() {
var sh = SpreadsheetApp.getActive().getSheetByName("BALANCE SHEET");
var data1 = sh.getRange("G2").getValues(); //USED AS DATA IN THE EMAIL BODY from values in the sheet
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("BALANCE SHEET").getRange("G2");
var emailRange1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("BALANCE SHEET").getRange("G1");
var emailAddress = emailRange.getValues();
var recipient = emailRange1.getValues();
var message = 'Hello ' + recipient + "\r\r" + 'Please see the current amount that needs paying off: ' + data1 + "\r\r" + 'Many Thanks';
var subject = 'REMINDER - Amount Due';
MailApp.sendEmail(emailAddress, subject, message);
}
As the sheet will be used as a separate doc for each user, the user would enter the date in cell M3 on configuration for when they want the reminder to be sent, and they would only enter the date number of the month e.g. 25
Does anyone know of a way that I could do this please?
Send email once a month
function sendChangeDetailsEmail() {
var ss=SpreadsheetApp.getActive();
var sh = ss.getSheetByName("BALANCE SHEET");
var dt=new Date();
var today=dt.getDate();
var days=new Date(dt.getFullYear(),dt.getMonth()+1,0).getDate();//number of days in this month
var emailDay=sh.getRange('M3').getValue();
if(emailDay>0 && emailDay<=Days && emailDay==today) {
var data1 = sh.getRange("G2").getValue();
var emailRange = ss.getSheetByName("BALANCE SHEET").getRange("G2");
var emailRange1 = ss.getSheetByName("BALANCE SHEET").getRange("G1");
var emailAddress = emailRange.getValue();
var recipient = emailRange1.getValue();
var message = 'Hello ' + recipient + "\r\r" + 'Please see the current amount that needs paying off: ' + data1 + "\r\r" + 'Many Thanks';
var subject = 'REMINDER - Amount Due';
MailApp.sendEmail(emailAddress, subject, message);
}
}
Run the next function just once and check Edit/Current Project Trigger to make sure that there is one and only one trigger created.
function createSendChangeDetailsEmail() {
ScriptApp.newTrigger('sendChangeDetailsEmail').timeBased().everyDays(1).atHour(6).create();
}
I have now got a script as below:
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('Sheet1');
var rng = sh.getDataRange();
var val = rng.getDisplayValues();
var lr = rng.getLastRow();
var compare = sh.getRange('A9').getValue();
var match = false;
var body = "Hello, "+"\n\n"+"Please remember the below:";
for (var i = 1; i < lr; i++) {
if (val[i][2] == compare) {
var bodyVal = val[i][0];
body = body+"\n - "+bodyVal;
match = true;
Logger.log(body);
}
}
if(match) {
MailApp.sendEmail({
to: "mail#example.com",
subject: "Reminder",
body: body
});
}
}
I hope this helps someone who may be looking for the same thing :)