Sending email using Google spreadsheet - google-apps-script

I am creating a simple email notification using 2 conditions in Google spreadsheet. I created for I function so that it will scan the rows I needed for my if condition. If challengeStatus and challengeSent are met, it will send an email notification. The email works fine, however, every time I run the function, it won't be finished running the code. Looks like there is a problem with my loop statement somewhere but can't figure it out. Here is my code please help.
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Challenges");
var lr= ss.getLastRow();
for (var i = 2;i<=lr;i++) {
var qaEmail = ss.getRange(i, 1).getValue()
var adminEmail = ss.getRange(i, 2).getValue()
var VideoId = ss.getRange(i, 3).getValue()
var QA1comment = ss.getRange(i, 10).getValue()
var QA2comment = ss.getRange(i, 11).getValue()
var QA3comment = ss.getRange(i, 12).getValue()
var challengeStatus = ss.getRange(i, 13).getValue()
var challengeSent = ss.getRange(i, 14).getValue()
var subject,mailbody
subject = "Challenge Result: ("+ VideoId + ")";
mailbody = 'Hi, ' +adminEmail+ ' <br><br>This email is to notify you that we have completed to process your dispute on Video Id: <b>' +VideoId+ '</b> and the result is <b>' +challengeStatus+ '</b>.<br><br> Scores will be updated based on the result. <br><br>Comments: <br><br> QA 1: ' +QA1comment+' <br><br>QA 2: ' +QA2comment+'<br><br> QA 3: ' +QA3comment+' <br><br>Thank you. <br><br>Quality Team';
if (challengeStatus =="Non Revert" && challengeSent ==""){
MailApp.sendEmail(adminEmail,subject," ",{
name: 'Quality Team (No Reply)',
cc: qaEmail,
htmlBody: mailbody,
});
//Logger.log(VideoId);
}
}
sendstatus = ss.getRange('N' + i).setValue('Sent')
}

Related

MailApp sendEmail in google sheets

been using MailApp script to automatically send emails from within a google sheet for several years. developed my script from an example i found online and reverse engineered it until i could make it work (i am not a coder!). worked brilliantly for months/years...
but recently it is no longer functioning. i get a daily email summary of errors which states that EMAIL_SENT is not defined, but when running the script in debug mode it times out after the logger.log(user) - so does appear to hang on the EMAIL_SENT variable.
As i say, this has been running brilliantly for many months, but appears to have stopped around july 22nd.
i have included the script below in case it is something simple:
function autoemailES() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ESautoemail");
//var lastRow = sheet.getLastRow();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow() -1; // Number of rows to process
var EMAIL_SENT = 'EMAIL_SENT';
// Fetch the range of cells A2:G
var dataRange = sheet.getRange(startRow, 1, numRows, 30);
// 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 emailSent = row[7]; // 8th column
if (emailSent !== EMAIL_SENT) { // Prevents sending duplicates
var superMail = row[2]; // 3rd column
var responseNo = row[3]; // 4th column
var user = row[0]; // 1st column
var firstName = row[1]; // 2nd column
var pdfLink = row[5]; // 6th column
var pdfID = row[6]; // 7th column
Logger.log(responseNo) //these logger lines just display the values for each of the variables in debugging
Logger.log(superMail)
Logger.log(user)
Logger.log(pdfLink)
Logger.log(pdfID)
var file = DriveApp.getFileById(pdfID);
var subject = 'IBTPHEM MSF results for ' + user;
var message = 'Dear Educational Supervisor,' + "\n" +
'This is an automated notification that your trainee, ' + firstName + ', has now received a quorate number of MSF responses.'+"\n"+
'The anonymised summary of responses is attached in PDF format, or can be downloaded from the link below.'+"\n" + pdfLink +"\n"+
'Further submissions will be added automatically (the trainee is notified for each), but the pdf will need downloading again'+"\n"+
'Please feel free to share this with your trainee however you see fit - we are now releasing the results via the ES in case there is any feedback that may require debriefing or handling more delicately.'+"\n"+
'Please do let me know of any problems or concerns?'+"\n"+
'Kind Regards,' + "\n" +
'IBTPHEM MSF'
MailApp.sendEmail(superMail,subject, message,{
name: 'IBTPHEM MSF',
replyTo: 'dr_nick#doctors.org.uk',
attachments: [file.getAs(MimeType.PDF)]});
sheet.getRange(startRow + i, 8).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
}
I would be really grateful for any help to identify my problem.
thanks!
dr_nick
(i cannot easily share the sheet in its entirity as it contains a fair bit of senstive/confidential information - though I suppose I could make an anonymised version if this is necessary/helpful?)
This is the same script with a try catch block. It will only log things if you have an error.
function autoemailES() {
const ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("ESautoemail");
var startRow = 2;
var EMAIL_SENT = 'EMAIL_SENT';
var dataRange = sheet.getRange(startRow, 1, sheet.getLastRow() - startRow + 1, 30);
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
try{
var row = data[i];
var emailSent = row[7];
if (emailSent !== EMAIL_SENT) {
var superMail = row[2];
var responseNo = row[3];
var user = row[0];
var firstName = row[1];
var pdfLink = row[5];
var pdfID = row[6];
var file = DriveApp.getFileById(pdfID);
var subject = 'IBTPHEM MSF results for ' + user;
var message = 'Dear Educational Supervisor,' + "\n" +
'This is an automated notification that your trainee, ' + firstName + ', has now received a quorate number of MSF responses.' + "\n" +
'The anonymised summary of responses is attached in PDF format, or can be downloaded from the link below.' + "\n" + pdfLink + "\n" +
'Further submissions will be added automatically (the trainee is notified for each), but the pdf will need downloading again' + "\n" +
'Please feel free to share this with your trainee however you see fit - we are now releasing the results via the ES in case there is any feedback that may require debriefing or handling more delicately.' + "\n" +
'Please do let me know of any problems or concerns?' + "\n" +
'Kind Regards,' + "\n" +
'IBTPHEM MSF'
MailApp.sendEmail(superMail, subject, message, {
name: 'IBTPHEM MSF',
replyTo: 'dr_nick#doctors.org.uk',
attachments: [file.getAs(MimeType.PDF)]
});
sheet.getRange(startRow + i, 8).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
catch(e){
Logger.log('responseNo: %s\nsuperMail: %s\nuser: %s\npdfLink:%s\npdfID: %s',responseNo,superMail,user,pdfLink,pdfID);
Logger.log(e);
}
}
}
Try setting up another spreadsheet and adjust the data so that it doesn't send data to your clients and see if it will generate any errors. Also if you could share a copy of the new spreadsheet as a markdown table that would enable us to test it a little. But be careful about sharing private information

How to send email to only selected emails from google sheet?

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.

Send Email with Inline Image AND text in body

I'm using this code to send emails that include an inline image and some text (both fetched from a sheets tab). The script runs well but the debug is not clean. Could you please help me find a better syntax?
The error I get is:
"Unexpected error while getting the method or property getBlob on
object DriveApp.File."
Thank you
function sendEmails() {
var ss = SpreadsheetApp.getActive().getSheetByName('SendMail')
var lr = ss.getLastRow();
var quotaLeft = MailApp.getRemainingDailyQuota();
//Logger.log(quotaLeft);
if((lr-1) > quotaLeft) {
Browser.msgBox("You have " + quotaLeft + " left and you're trying to send " + (lr-1) + " emails. Emails were not send.");
} else {
for (var i = 2;i<=lr;i++){
var currentEmail = ss.getRange(i, 1).getValue();
var currentSubject = ss.getRange(i, 2).getValue();
var templateText = ss.getRange(i, 3).getValue();
var currentname = ss.getRange(i, 4).getValue();
var reply = ss.getRange(i, 5).getValue();
var image = DriveApp.getFileById(ss.getRange(i, 6).getValue()).getBlob();
var message = templateText.replace("{name}",currentname);
message += "<br/><br/><img src=\"cid:sampleImage\">";
//Logger.log(currentEmail);
MailApp.sendEmail({
to: currentEmail,
replyTo: reply,
subject: currentSubject,
htmlBody: message,
inlineImages: {sampleImage: image},
});
} //close for loop
} //close else statement
} //close sendEmails`
The error means:
No item with the given ID could be found, or you do not have permission to access it.
Or in other words:
ss.getRange(i, 6).getValue() does not contain a valid file ID.
For debugging purposes add the following two logs before retrieving the image and observe the results:
...
Logger.log("Cell: " + ss.getRange(i, 6).getA1Notation());
Logger.log("Image: "+ DriveApp.getFileById(ss.getRange(i, 6).getValue()));
var image = DriveApp.getFileById(ss.getRange(i, 6).getValue()).getBlob();
...
How to make sure the cell containing the image ID is not empty?
Implement an if statement verifying if the cell is blank. If so, continue with the next loop iteration:
...
if(ss.getRange(i, 6).isBlank()){
continue;
}
var image = DriveApp.getFileById(ss.getRange(i, 6).getValue()).getBlob();
...

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 :)

attach multiple file types(pdf, xlsx) from Gdrive to email using appscript

I am trying to figure out a way to attach multiple types of files(pdf, xlsx) from drive to my emails using appscript. I have the below code which attaches .xlsx file type to emails based on the name of the file in a specific Gdrive folder.
So, i have a spreadsheet which has the following headers:
name, email address, header3, header4, status, filename
So basically i did a for loop to go through each line and attach the file mentioned in header: filename, to the email and it registers the header: status as "Email Sent".
I understand the logic behind, but not sure what or how to code in to make sure it picks up even if the file type is pdf, word, etc for different rows in the spreadsheet. I also am guessing that something needs to be done in
var email = GmailApp.sendEm.............................spreadsheetml.sheet")]});
the code:
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Info");
var lr = ss.getLastRow();
var email_Sent = "EMAIL SENT" // This constant is written in column 5 for rows for which an email has been sent successfully.
var dailyQuota = MailApp.getRemainingDailyQuota();
var alias = GmailApp.getAliases();
var replyTo = ss.getRange(1, 10).getValue();
if((lr-1) > dailyQuota) {
Browser.msgBox("Your daily quota is " + dailyQuota + " emails and you are trying to send " + (lr-1) + " emails." + " Hence the emails were not sent!!");
} else {
for (var i = 2;i<=lr;i++) {
var currentEmail = ss.getRange(i, 2).getValue();
var productPurchase = ss.getRange(i, 3).getValue();
var dueDate = ss.getRange(i, 4).getValue();
var currentName = ss.getRange(i, 1).getValue();
var emailSent = ss.getRange(i, 6).getValue(); //fetch if email has been sent or not
var fileName = ss.getRange(i, 5).getValue(); //fetch file name from column 6 from spreadsheet
var fileFromDrive = DriveApp.getFolderById("1oa2Yw3A7n4vbTKAgQVEfNjVxgBi0MaP8").getFilesByName(fileName); //fetch from drive by file name
if (emailSent != "EMAIL SENT") {
var templateText = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1, 1).getValue(); //fetch template from sheet
var messageBody = templateText.replace("{name}",currentName).replace("{product}",productPurchase).replace("{date}",dueDate); //body of the message, replace with var in sheet "template"
var email = GmailApp.sendEmail(currentEmail, "Reminder: Payment due on " + productPurchase + " purchase", messageBody, {from: alias[0], replyTo: replyTo,
attachments: [fileFromDrive.next().getAs("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")]}); //send email with attachment
var cellUpdate = ss.getRange(i, 6).setValue(email_Sent); //to update column 5 once email sent
SpreadsheetApp.flush(); //to flush out pending actions on spreadsheet
} //close for if statement
Logger.log(cellUpdate);
} //close for loop statement
} //close else statement
Logger.log(dailyQuota);
}