Send an email when one cell in a column contains data, but not when it's deleted - email

I would like an email to be sent when something is added to a cell anywhere in column K, but not when that cell is cleared. Is this possible? Here is what I have so far. The email sends okay when I edit cell K1 (it was limited to this single cell for testing) but it also sends an email when I clear this cell. Thank you for any advice, as you can see I'm mostly just guessing here.
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet4 = ss.getSheetByName('Copy');
var emailAddress = sheet4.getRange(2,12).getValue();
var subject = sheet4.getRange(2,13).getValue();
var message = sheet4.getRangeList(['G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8'])
.getRanges()
.map(range => range.getDisplayValue())
.join('\n');
MailApp.sendEmail(emailAddress, subject, message);
}
function onEdit(e) {
if(e.range.rowStart === 1 && e.range.columnStart === 11) {
var sh = e.source.getActiveSheet();
if(sh.getName() === 'Copy') {
sendEmail()
}
}
}

Piggybacking off Karla's answer, generally when you delete single values, the event object (e) is absent of a value key. Therefore,
Try:
function onEdit(e) {
if (e.source.getActiveSheet().getName() === `Copy`) {
if (e.range.rowStart === 1 && e.range.columnStart === 11) {
if (`value` in e) sendEmail()
}
}
}

Maybe add to the "if" that if the value is different to empty it will not execute the code
Not sure which row or range belongs to K, so I name it "Range_in_K"
if(e.range.rowStart === 1 && e.range.columnStart === 11 && Range_in_K != "")

Related

Changing the sender's email address

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.

Script to send email based on value in a column - problem with script

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"));
})
}

Choosing a specific column or cell for data to be entered into?

The script below places a static time stamp into column A whenever column B is edited.
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if (s.getName() == "Sheet1") {
var r = s.getActiveCell();
if (r.getColumn() == 2) {
var nextCell = r.offset(0, -1);
if (nextCell.getValue() === '')
nextCell.setValue(new Date());
}
}
}
However, I would like the timestamp to occur when columns B,C,D,E, etc. are edited.
How do I specify that Column A (or 1) is where I want the date to be placed?
The documentation knows a Method on a Sheet getRange(row, column)
So I guess, this should work:
var firstCell = s.getRange(r.getRow(), 1);
You can use Event object to get information about the cell that was edited. No need to use getActiveSheet, getActiveCell and offset:
function onEdit(e) {
var range = e.range; // Range that was edited
var sheet = range.getSheet(); // Sheet that was edited
var editedRow = range.getRow(); // Row that was edited
var editedCol = range.getColumn(); // Column that was edited
if (sheet.getName() == "Sheet1" && editedCol > 1) { // Check that edited sheet is "Sheet1" and edited column is not A
var colA = sheet.getRange(editedRow, 1); // Get corresponding cell in column A
if (colA.getValue() === "") colA.setValue(new Date()); // Set date if cell is empty
}
}
Reference:
Event objects: onEdit
Sheet.getRange(row, column)

Multiple OR conditions in time difference

I want to make a script that send me mail whith the content of what I've enterd in a form some days after the form is submitted. As a help for students to study. In the form enter what to study, then 1 day, 7 days and 28 days later get that in a mail.
I've made a form that collect time, recipient adress, subject and body for the mail. These are saved in a Google spreadsheet.
The code kind of work. But it send all of the mail from my test input in the sheet. I've added one 6 days ago, one yesterday and one today.
Today I should only get one mail and tomorrow two. But I get all of them today.
I think it's this line:
if (diffDays == 1 || diffDays == 7 || diffDays == 28) continue;
I've trided to change it, searched other ways of writing it, as array for example.
Here's the full code:
function createTimeDrivenTriggers() {
ScriptApp.newTrigger('reminder')
.timeBased()
.everyDays(1)
.atHour(16) // Change time of day here
.inTimezone("Europe/Stockholm")
.create();
}
function reminder() {
var today = new Date(); // Today
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var data = range.getValues();
var headerRows = 1;
for (i=0; i<data.length; i++){
if (i < headerRows) continue;
var row = data[i];
var time = row[0];
// Get time difference
var timeDiff = Math.abs(today.getTime() - time.getTime());
var diffDays = Math.ceil((timeDiff) / (1000 * 3600 * 24)-1);
if (diffDays == 1 || diffDays == 7 || diffDays == 28) continue;
var recipient = row[1];
var subject = row[2];
var body = row[3];
// Send mail
GmailApp.sendEmail(recipient, subject, body)
}
}
Thanks
Make sure to execute the code only when your if statement is true.
Include all code after if statement in the statement itself, only executing it when diffDays = 1, 2 or 28.
function reminder() {
var today = new Date(); // Today
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var data = range.getValues();
var headerRows = 1;
for (i=0; i<data.length; i++){
if (i < headerRows) continue;
var row = data[i];
var time = row[0];
// Get time difference
var timeDiff = Math.abs(today.getTime() - time.getTime());
var diffDays = Math.ceil((timeDiff) / (1000 * 3600 * 24)-1);
if (diffDays == 1 || diffDays == 7 || diffDays == 28) {
var recipient = row[1];
var subject = row[2];
var body = row[3];
// Send mail
GmailApp.sendEmail(recipient, subject, body)
}
}
}
Note that continue means "stop processing this iteration of whatever loop is getting executed, and begin the next iteration." So your script sends reminders on every day except the days you want to remind them.
Changing your test to an "AND NOT", moving the code for reminding inside the existing check, or using a more expressive syntax like switch will satisfy your intent.
switch (diffDays) {
case 1:
case 7:
case 28:
sendReminder(your, Args, Here);
break;
case 0:
sendWelcome(some, other, Args);
break;
...
default:
break;
}
...
function sendReminder(your, Args, Here) {
/* Code that uses function arguments to build and send an email */
}
"And not" meaning if (diffDay != 1 && diffDay != ...), i.e. "if it's not this, and not that, and not this other thing, and not..."

Preventing repetitive data in date fields ActionsScript2

I have four date fields on a form and I need to alert the user when they have entered repetitive dates. I have already created an array that generates and checks the dates, but throwing the alert is not working for me. This is what I have so far.
else if ((dateRow1.text== dateRow2.text) || (dateRow1.text == dateRow3.text) || (dateRow1.text == dateRow4.text)) {
alert.show("You must have unique dates for each field");
Thanks.
You can check if your text fields are all distinct from each other:
var t:Array = [dateRow1, dateRow2, dateRow3, dateRow4];
var l:Number = t.length;
var i:Number;
var j:Number;
for (i = 0; i < l; i++) {
var ti = t[i]; // dateRow1... dateRow4
for (j in t) {
if (ti != t[j] && ti.text == t[j].text) trace(ti + "==" + t[j]);
}
}