Ive created below script to automatically send emails when the checkbox is ticked. My problem is, the sheet is being used by two users and I want to change the sender so that the email will be sent out from the user who triggered the script.
I've tried adjusting the "Deployment" settings so that the app script runs as the "User accessing the Web app", also asked the other user to create a trigger of his own, which is working fine. But we are getting two emails (probably because of the two triggers?) Looking for advice on how do I go about it.
function onCheckboxEdit(e) {
var source = e.source;
var sheet = source.getActiveSheet() ;
var range = e.range;
var row = range.getRow();
var column = range.getColumn();
console.log("column:: ", column);
var targetRange = sheet.getRange(row, 13, 1, 7);
var targetValues = targetRange.getValues();
console.log("targetRange:: ", targetValues);
var recipient = targetValues[0][2];
var checkboxValue = targetValues[0][4];
var body = targetValues[0][1];
var Replacement = targetValues [0][0];
var subject = "Replacement for " + Replacement;
var ccmail = targetValues[0][3];
var Rname = targetValues[0][5];
var EMAIL_SENT = 'E-mail sent';
var emailDupe = targetValues[0][6];
if(emailDupe !== 'E-mail sent' && checkboxValue == true) {
console.log("checkbox marked true")
GmailApp.sendEmail(recipient, subject, body, {cc:ccmail,
name: Rname})
sheet.getRange(row, 19).setValue(EMAIL_SENT)
}else if (column = 17 && checkboxValue == false) {
console.log("checkbox marked false")
}else {
console.log("No clue")
}
}
In the case of Google workspace domain, you may be able to get the email of the effective user and the active user and compare it to stop double triggers.
function onCheckboxEdit(e) {
const eUser/*User who owns the trigger*/ = Session.getEffectiveUser().getEmail();
const aUser/*current user at the keyboard*/ = Session.getActiveUser().getEmail();
console.log({time: new Date(), aUser, eUser});
if (aUser !== eUser) return;
/*rest of the code*/
var source = e.source;
/*...*/
}
Check the logs for actual logged value and change the if statements accordingly.
Related
New to GAS. I have a Google Form feeding into a spreadsheet. After watching tutorial videos and reading other posts, I attempted to create a script that will send an email to an address in column 2, and send a different email based on either a yes or no in another column (column 25). It also includes another column (26) that I want to have the date populated into when the email is sent, ensuring that every time I run this script, there are no duplicates sent. I have debugged and nothing comes up as an error, but it's not working - I have not received an email. Help would be greatly appreciated! Here is an example spreadsheet: https://docs.google.com/spreadsheets/d/1AKaSOk1ZbnfKeadgB_mugnqplKzJJ3bDQ_KsRY0sMvQ/edit?usp=sharing
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var responses = ss.getSheetByName("Field Trip Requests");
var data = responses.getRange(2,1,responses.getLastRow()-1,25).getValues();
data.forEach(function(row,i) {
// variables
var recipient = row[1];
var destination = row[6];
var approval = row[24];
var emailSent = row[25];
if(emailSent == ' ') {
if(approval == "Y") {
var body = "Your field trip request for " +
destination +
" has been approved! If you requested transportation, Najma will make arrangements and contact you if she requires more information." +
"<br><br>" +
"Cheers," +
"<br><br>" +
"Boaty McBoatface";
}
else if(approval == "N") {
var body = "Your field trip request for " +
destination +
" has not been approved. Please come and see me and we can chat!" +
"<br><br>" +
"Cheers," +
"<br><br>" +
"Boaty McBoatface";
}
var subject = "Your Field Trip Request";
MailApp.sendEmail(recipient, subject, body)
var d = new Date();
responses.getRange(i + 1, 25).setValue(d);
}
})
}
One problem of the script is that you it's using 1 based indexes when it should be using 0 based in
var recipient = row[1];
var destination = row[6];
var approval = row[24];
var emailSent = row[25];
The above is because JavaScript uses 0 based indexes for Array elements (as well as for other things), so intestead of the above use
var recipient = row[0];
var destination = row[5];
var approval = row[23];
var emailSent = row[24];
Another problem is the following condition:
emailSent == ' ' /* is emailSent equal to a blank space? */
it should be
emailSent == '' /* is emailSent equal to an empty string? */
the above because getValues() returns an empty string for empty cells
If this var data = responses.getRange(2,1,responses.getLastRow()-1,25).getValues(); is correct then there is no row[25] as shown below:
data.forEach(function(row,i) {
// variables
var recipient = row[1];
var destination = row[6];
var approval = row[24];
var emailSent = row[25];
row starts at zero and ends at 24
row is an array
Perhaps this is what you wish:
function sendEmail() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName("Field Trip Requests");
var data=sh.getRange(2,1,responses.getLastRow()-1,25).getValues();
data.forEach(function(row,i) {
var recipient=row[0];
var destination=row[5];
var approval=row[23];
var emailSent=row[24];
if(emailSent=='' && approval=='Y') {
var body=Utilities.formatString('Your field trip request for %s has been approved! If you requested transportation, Najma will make arrangements and contact you if she requires more information. <br><br>Cheers<br><br>Boaty McBoatface',destination);
}else if(emailSent=='' && approval == "N") {
var body=Utilities.formatString('Your field trip request for %shas not been approved. Please come and see me and we can chat!<br><br>Cheers,<br><br>Boaty McBoatface',destination);
}
var subject="Your Field Trip Request";
MailApp.sendEmail(recipient, subject, body);
sh.getRange(i+1,25).setValue(Utilities.formatDate(new Date, Session.getScriptTimeZone(), "MM/dd/yyyy"));
})
}
I want the script to send an email to those mail addresses where unchecked boxes are in the row - This works fine. But I want the value of the checkbox to be set “True” after the mails were sent.
My Problem is that I need the last for-loop to stop after all checkboxes are checked. In other words: The last loop has to stop when an empty cell appears.
First of all I manually trigger the script - later I will start it with the help of a button in the menu (function onOpen...)
Appreciate any help – thanks a lot!
Check out the sheet and the code below:
function sendmail() {
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Sheet1');
var r = s.getRange('C:C'); //Checkboxes
var v = r.getValues();
for(var i=v.length-1;i>=0;i--)
if(v[0,i]=='false') {
var range = ss.getRange("A1:D4");
var UserData = range.getValues();
var UserData = range.getValues();
var row = UserData[i];
var name = row[0];
var email = row[1];
MailApp.sendEmail(row[1], "Test", "Hello " + name + ", This is an email");
var response = ui.alert("mail was send to ", ui.ButtonSet.OK);
}
for (k=1; k < 20; k++) { //loop which has to stop
s.getRange(k, 3).setValue("True");
}
}
A couple of major changes in your script.
The condition for the loop is wrong. Change to:
for(var i=v.length-1;i>0;i--)
The UI response is missing the recipient name. Change to:
var response = ui.alert("mail was send to "+name, ui.ButtonSet.OK);
var UserData = range.getValues(); is declared twice: delete one row
Immediately after the UI alert (and still within the IF loop), add a line to update the checkbox: UserData[i][2] = true;
Simplify the updating of checkboxes.
Delete the existing lines:
for (k=1; k < 20; k++) {
s.getRange(k, 3).setValue("True");
}
Substitute:
range.setValues(UserData)
Revised Script
function sosendmail() {
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Sheet1');
var r = s.getRange('C:C'); //Checkboxes
var v = r.getValues();
for(var i=v.length-1;i>0;i--)
if(v[0,i]=='false') {
var range = ss.getRange("A1:D4");
var UserData = range.getValues();
var row = UserData[i];
var name = row[0];
var email = row[1];
// MailApp.sendEmail(row[1], "Test", "Hello " + name + ", This is an email");
Logger.log("mail sent")
var response = ui.alert("mail was send to "+name, ui.ButtonSet.OK);
UserData[i][2] = true;
}
range.setValues(UserData)
}
Alternative Script
The following script is offered as an alternative. It avoids multiple getRange()/getValue statements and uses a more conventional top-down loop.
function sosendmail01() {
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Sheet1');
// get the number of rows (Alast)
var Avals = ss.getRange("A2:A").getValues();
var AlastRow = Avals.filter(String).length;
// Logger.log("DEBUG: number of rows = "+AlastRow)
// get the data range
var r = s.getRange(2, 1, AlastRow, 3);// get all the data
// Logger.log("DEBUG: the data range = "+r.getA1Notation())
var v = r.getValues(); // get the data
// loop through the rows of data
for (var i = 0;i<AlastRow;i++){
if (v[i][2] != false) {
// the checkbox is ticked Don't sent an email
// Logger.log("DEBUG: i:"+i+", name = "+v[i][0]+" - the checkbox is ticked");
} else{
// the checkbox IS NOT ticked - send an email
//Logger.log("DEBUG: i:"+i+", name = "+v[i][0]+" checkbox = "+v[i][2]+" - the checkbox is NOT ticked");
var name = v[i][0];
var email = v[i][1];
//MailApp.sendEmail(email, "Test", "Hello " + name + ", This is an email");
Logger.log("DEBUG: mail sent to "+name+" at "+email)
var response = ui.alert("mail was send to "+name, ui.ButtonSet.OK);
v[i][2] = true;
}
}
r.setValues(v);
}
I currently have this script for a Google Sheets file I'm working on:
function myAlerts() { // this runs based on daily trigger
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Reminders");
var range = sheet.getDataRange(); var values = range.getDisplayValues();
var lastRow = range.getLastRow();
var curDate = values[1][5]
var anyMatches = false;
var message = ""; var sheetUrl = ss.getUrl();
var email = Session.getActiveUser().getEmail();
var optionalEmail = values[2][1];
if (optionalEmail != "") { email = email + "," + optionalEmail; }
for (var i = 5; i < lastRow; i++) {
// if today matches the alert date, send an alert
if (values[i][3].toString() == curDate.toString()) {
// add a message for this row if date matches
message = message + values[i][0] + " will expire on " + values[i][1] + "<br />\n";
// if there is a match, set anyMatches to true so and email gets sent
anyMatches = true;
}
} // ends for loop
// footer for message
message = message + "<br />\nThis is an auto-generated email to remind you of your document expiration. <br />\n"
if (anyMatches) { // send an email
MailApp.sendEmail({
to: email,
subject: 'Document Expiration Notice!',
htmlBody: message});
}
}
In my sheet, the script sends an email to me (owner of the sheet) and an additional person if I enter an email address in B3. The script looks at F2, and checks column D to see if any dates match. If they do it sends an email with information from the other columns, in that same row.
How can I edit this script so that it will not only send the email to me, and the email address in B3, but ALSO the email address in that same row, which has a matching date??
Just remove your { email = email + "," + optionalEmail;} from the first if statement, and move it after the second, adding the email value just like you did for the optionalEmail variable.
if (values[i][3].toString() == curDate.toString()) {
email = email + "," + optionalEmail + "," + values[i][2];
UPDATE for comment:
Valid point that I didn't catch when I made the change suggestion. That requires a little more work. You need to move the whole MailApp.sendEmail chunk into the second if statement. Then you need to 'clear' your variables each iteration so that they don't carry over into the next iteration. To do this effectively, you will need to create a new variable to hold the email recipients (recip). The code will throw an error if you clear the email variable, because of the logic you are using to populate it.
Here is the updated code:
function myAlerts() { // this runs based on daily trigger
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Reminders");
var range = sheet.getDataRange(); var values = range.getDisplayValues();
var lastRow = range.getLastRow();
var curDate = values[1][5]
var message = ""; var sheetUrl = ss.getUrl();
var email = Session.getActiveUser().getEmail(); var optionalEmail = values[2][1];
for (var i = 5; i < lastRow; i++) { // if today matches the alert date, send an alert
if (values[i][3].toString() == curDate.toString()) {
var recip = email + "," + optionalEmail + "," + values[i][2];
//changed variable to allow for clearing.
// add a message for this row if date matches
message = message + values[i][0] + " will expire on " + values[i][1] + "<br />\n";
MailApp.sendEmail({
to: recip,
subject: 'Document Expiration Notice!',
htmlBody: message});
recip = ""; // clears email recipients for next iteration.
message = ""; // clears message for next iteration.
}
} // ends for loop
}
// footer for message message = message + "<br />\nThis is an auto-generated email to remind you of your document expiration. <br />\n"
I also removed the anyMatches variable, and the first if statement, because they aren't really needed for this to work.
Let me know if it still doesn't do what you need.
I have a problem with a script I wrote for GMail. I want to reformat and then forward every mail from a specific sender to a Mail2SMS provider.
When I receive the mail it will be tagged with an label - "Alarmanlage".
The formating works fine, but my script don't use the last mail from the sender the format and forward. I don't find the failure to get the last mail of a thread.
I hope someone can help!
function sendsms(){
var label = GmailApp.getUserLabelByName("Alarmanlage");
if(label == null){
GmailApp.createLabel('Alarmanlage');
}
else{
var threads = label.getThreads(0,1);
for (var i = 0; i < threads.length; i++) {
var count = threads[i].getMessageCount();
var message = threads[i].getMessages()[count];
var from = message.getFrom();
var subject = message.getSubject();
var date = message.getDate();
var msg = message.getBody();
msg = msg.replace("<div><br>","");
var endofmsg = msg.indexOf("<br>");
msg = msg.substring(0, endofmsg);
GmailApp.sendEmail("xxxh#mail2sms.com", msg)
message.moveToTrash()
}
label.removeFromThreads(threads);
}
}
For your var message use :
var thread = threads[i];
var messages = thread.getMessages();
var message= messages[thread.getMessageCount()-1];
Stéphane
I often have something on my mobile phone that I'd like to keep for future reference. Maybe a photo or an interesting link to an article to read later on a computer.
How can I save this information via email on my phone so that the email content is stored in a Google Sites page using Google AppsScript
This apps script code works. Have it trigger on a timer (say every 5mins) and any emails sent to your gmail account with emailarch in the subject will be added to the page as child pages with attachments. The parent page list will be updated.
The Sites page should be of type List with two text columns Date and Item.
/**
*/
function createEmailArch() {
var site = 'YOURSITE';
var page_name = 'APAGEINYOURSITE';
var site_url = 'https://sites.google.com/site/'+site+'/'+page_name;
var site = SitesApp.getSite(site);
var page = site.getChildByName(page_name);
var curr_date = new Date();
var curr_date_fmt = Utilities.formatDate(curr_date,'Australia/Melbourne','yyyy-MM-dd HH:mm:ss');
var threads = GmailApp.search('subject:"emailarch" is:unread');
for ( var j = 0 ; j<threads.length;j++) {
var messages = threads[j].getMessages();
for ( var i = 0 ; i < messages.length; i++ ) {
var message = messages[i];
var subj = message.getSubject();
var body = message.getBody();
var mdte = message.getDate();
var mfrm = message.getFrom();
var meto = message.getTo();
var atta = message.getAttachments();
var cont = "Subject : "+subj+"<br/>"+
"To : "+meto+"<br/>"+
"From : "+mfrm+"<br/>"+
"Date : "+mdte+"<br/>"+
body;
var dte2 = Utilities.formatDate(curr_date,"Australia/Melbourne","yyyy_MM_dd_HH_mm_ss")+"_"+j+"_"+i;
for ( var k=0;k<atta.length;k++) {
var iname = atta[k].getName();
if ( atta[k].getContentType().indexOf('image')>=0 ) { // If attachment is an image show inline
cont = cont +"<hr/>"+
"<div style='display:block;text-align:left'>"+
"<a href='"+site_url+"/"+dte2+"/"+iname+"?attredirects=0' imageanchor='1'>"+
"<img src='"+site_url+"/"+dte2+"/"+iname+"?height=400&width=224' border='0' height='400' width='224'>"+
"</a></div><br/>";
}
}
var p = page.createWebPage(curr_date_fmt,dte2,cont);
for ( var k=0;k<atta.length;k++) {
p.addHostedAttachment(atta[k]);
}
page.addListItem( [curr_date_fmt, "<a href='"+site_url+"/"+dte2+"'>"+subj+"</a>"]);
message.markRead();
}
}
};