I'm very new to script writing, but I'm trying to set up a script to send an email once a certain cell (A4) is populated within a certain sheet.
The trouble I'm having is getting the script to trigger - I understand that running it when not in the spreadsheet generates an error, I get no error message, but no email appears to be sent using this code:
function onEdit(e) {
var name = SpreadsheetApp.getActiveSpreadsheet().getName();
var cell = e.range.getA1Notation();
var spreadSheet = e.source;
var sheet = spreadSheet.getSheetByName('Scanned');
var range = getRange('A4');
var column = e.range.getColumn();
var row = e.range.getRow();
if(sheet == 'Scanned' && column == 1 && row == 4)
MailApp.sendEmail('joey#gmail.com', 'Tipping Notification: '+(name), 'Notification email body '+(name));
}
An onEdit trigger always requires a 'manual' edit of the spreadsheet. If the spreadsheet(cell) is populated by a formula, it will not fire the onEdit trigger.
Also, in order to send emails, you'll have to use an installable onEdit trigger. Simple onEdit triggers cannot access services that require authorization.
There are some restrictions for using simple trigger, One is simple trigger cannot access services that require authorization. For example, a simple trigger cannot send an email because the Gmail service requires authorization.
In order to use services that requires authorization, you need to create an Installable trigger. See this link on how to create Installable Trigger.
Also, getSheetByName() returns a Sheet Object and not the name of the edited Sheet. This causes your code to skip sending email.
Try this:
Code:
function onEditA4(e) {
var editedSheet = e.range.getSheet().getName();
var editedCell = e.range.getA1Notation();
var name = e.source.getName();
if(editedSheet == 'Scanned' && editedCell == "A4")
MailApp.sendEmail('insert email here', 'Tipping Notification: '+(name), 'Notification email body '+(name));
}
Example Trigger:
Related
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if( sheet.getSheetName() != 'Sheet1' ) {
return 0;
}
var selectedCell = ss.getActiveCell();
if( selectedCell.getColumn() == 1) {
var dateTimeCell = selectedCell.offset(0, 2);
dateTimeCell.setValue('auto');
GmailApp.sendEmail('12345#gmail.com', selectedCell.getRow(), 'hello')
}
if I modify column A and run script, Gmail sent.
but if I modify column A only (don't run code), then Gmail not sent.
'auto' is inserted in both case. I suspect only GmailApp.sendEmail is not working.
why?
Do you have a trigger set up for it? The function you have only shows a simple trigger onEdit() which cannot send emails. See Restrictions here.
Vytautas is right. It says that:
They cannot access services that require authorization. For example, a simple trigger cannot send an email because the Gmail service requires authorization, but a simple trigger can translate a phrase with the Language service, which is anonymous.
I am a newbie and have been using a simple App Script to send out emails with triggers onEdit and onChange. However, my Worksheet has over ten sheets and any edits/changes (done by me or by computations) in any of the sheets sends out an email, causing unintended spam! To avoid this, if I could use some code that sends the email based only on ANY CHANGE to a specific cell's value, in a specific sheet, my problem would be solved. My outgoing email message is short and the whole message is in just ONE cell (C2). If I can add a line of code which monitors for ANY change in that cell C2, and sends out an email if there is a change, that's it! I'd be done. My Script is as follows:
function sendEmail(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet1=ss.getSheetByName('Email');
var emailAddress = sheet1.getRange(2,1).getValue();
var subject = sheet1.getRange(2,2).getValue();
var message = sheet1.getRange(2,3).getValue();
MailApp.sendEmail(emailAddress, subject, message);
}
Answer:
You can do this with an onEdit() and a conditional.
Code Example:
function onEdit(e) {
const specificSheet = "Email" // for example
const specificCell = "C2" // for example
let sheetCheck = (e.range.getSheet().getName() == specificSheet)
let cellCheck = (e.range.getA1Notation() == specificCell)
if (!(sheetCheck && cellCheck)) {
return
}
else {
sendEmail()
}
}
Rundown of this function:
Defines the sheet and A1 notation of the specific cell to check
Gets the Sheet and the A1 notation of the cell which was just edited
Returns if either the Sheet or the Cell are not the defined specific cell (using De Morgan's law)
Runs sendEmail() if the cell and Sheet are correct
References:
Event Objects | Apps Script | Google Developers
Simple Triggers | Apps Script | Google Developers
De Morgan's laws - Wikipedia
Working from the answer, this is how it ended up for me since I had several ranges to check:
function onEdit(e){
if(wasEdited(e, range1)){ // e.g. range1 = "Sheet1!A5"
// handle range1 change
}
if(wasEdited(e, range2)){ // e.g. range2 = "Sheet1!A7"
// handle range2 change
}
}
function wasEdited(e, range){
let tab = getTabFromA1Range(range)
let cell = getRangeFromA1Range(range)
return e.range.getSheet().getName() == tab && e.range.getA1Notation() == cell
}
function getTabFromA1Range(a1Range){
return a1Range.substring(0, a1Range.indexOf("!"))
}
function getRangeFromA1Range(a1Range){
return a1Range.substring(a1Range.indexOf("!")+1)
}
On further research, the following solution seems to work the best:
function sendEmail(){
Utilities.sleep(30000);
var ss=SpreadsheetApp.getActiveSpreadsheet();
var data=ss.getActiveSheet().getActiveCell().getA1Notation();
var sheetname = ss.getActiveSheet().getName();
var sheet1=ss.getSheetByName('Email');
var emailAddress = sheet1.getRange(2,1).getValue();
var subject = sheet1.getRange(2,2).getValue();
var message = sheet1.getRange(2,3).getValue();
if(data.indexOf('A:C')!=-1.23456789) {
MailApp.sendEmail(emailAddress, subject, message);
}
};
The key seems to be the "if statement" on line 10. Please note the time delay of half a minute I added to the script. This is because without it, on the trigger activating, the previous email was going out instead of the current one. Obviously my app has a slight delay in syncing and the trigger fired before all the current data got populated in the relevant cell!
In google sheets, I am trying to get one data to copy from one sheet to another.
I have this code which is working however I would like it to run onEdit when changing cell E4 in Googlesheet1. I am new at this and doesn't seem to get it to quite work with the solutions I found online.
function ExportRange() {
var destination = SpreadsheetApp.openById('googlesheet1');
var destinationSheet = destination.getActiveSheet();
var destinationCell = destinationSheet.getRange("AC3");
var cellData = '=IMPORTRANGE("https://docs.google.com/spreadsheets/googlesheet2", "AE10:AE9697")';
destinationCell.setValue(cellData);
}
Chose between a simple and installable onEdit trigger, depending on your requirements
For most applciaitons a simple onEdit trigger is sufficient, to use it you just need to rename your function ExportRange() to onEdit()
Take advantage of event objetcs that give you informaiton about the event that fired the trigger
So, the trigger onEdit can give you among others information about the event range - that is the range that has been edited
Now you can implement an if statement to specify that the rest of the funciton shall only be run if the event range and the corresponding sheet are as required
Sample:
function onEdit(event) {
var range = event.range;
var sheet = range.getSheet();
if(range.getA1Notation() == "E4" && sheet.getName() == "Googlesheet1"){
var destination = SpreadsheetApp.openById('googlesheet1');
var destinationSheet = destination.getActiveSheet();
var destinationCell = destinationSheet.getRange("AC3");
var cellData = '=IMPORTRANGE("https://docs.google.com/spreadsheets/googlesheet2", "AE10:AE9697")';
destinationCell.setValue(cellData);
}
}
Please note that this function can only be fired by the trigger in
case of an edit. If you try to run it manually, it will give you an
error because event (and thus event.range) will be undefined if
the funciton was not called by an edit event.
I want to automate my work of sending email.
For this i created google apps script, but it is not working.
my goal is : if i update column I of any row to "Yes" than email must be send to email id of that row only by adding their username and password. and if possible email status will also change to "email sent on date"
This is my table
Code:-
function onEdit(e) {
var ss= SpreadsheetApp.getActiveSpreadsheet();
var range = e.Range;
if(range.getColumn()== 9 && e.getValue()=="Yes")
{
var celladdress = 'E'+ e.getRowIndex();
var emailid= ss.getRange(celladdress).getValue();
var sub = 'πͺπππ
πππππππ - πππ';
var uname = ss.getRange('G'+ e.getRowIndex()).getValue();
var pass = ss.getRange('H'+ e.getRowIndex()).getValue();
var b = "Your details are as follows: \n Username :" +uname+ "\n Password : "+pass+ "\nThis is for your information please. \nThanks and Regards";
MailApp.sendEmail(emailid, sub, b);
}
}
Solution
You had a few mistakes in your script like using e.getValue() instad of range.getValue(), I have corrected these mistakes.
Moreover and most importantly, to be able to send emails using triggers you need to use installable triggers as simple ones do have restrictions as the MailApp service requires authorization. Here you can find more information about this.
To create an installable trigger ( if you have not already do so ), go to your script editor and then to Edit->Current Project Triggers and the trigger pannel Add Trigger. Select your function (onEdit) and set the event type to on edit.
This is your piece of code with the typos corrected:
function onEdit(e) {
var ss= SpreadsheetApp.getActiveSpreadsheet();
var range = e.range;
if(range.getColumn()== 9 && range.getValue()=="Yes")
{
var celladdress = 'E'+ range.getRow();
var emailid= ss.getRange(celladdress).getValue();
var sub = 'Credentials-reg';
var uname = ss.getRange('G'+ range.getRow()).getValue();
var pass = ss.getRange('H'+ range.getRow()).getValue();
var b = "Your details are as follows: \n Username :" +uname+ "\n Password : "+pass+ "\nThis is for your information please. \nThanks and Regards";
GmailApp.sendEmail(emailid, sub, b);
}
}
I hope this has helped you. Let me know if you need anything else or if you did not understood something. :)
I need a solution to enable all editors to leave their name stamps after they make changes in a sheet. I was able to come up with script code which does work ONLY FOR OWNER.
I tried to authorize the script by running the script manually from editors accounts - the app has the authorization but even though it doesn't work for Editors.
Norbert Wagner: "However authorizing from the script editor did not work for me. But as soon as I added a menu in the document and executed the function from there, I got an authorization request in the document. From then on also the onEdit function works, for all users. I did this as the documents owner though. " -
maybe this is the solution? But how can I run the onEdit from the
document? Simple edit doesn't work, but how about this menu? Is there
a way to execute ALL SCRIPTS AND FORCE AUTHORIZATION from document level?
function onEdit(e) {
// Your sheet params
var sheetName = "Arkusz1";
var dateModifiedColumnIndex = 3;
var dateModifiedColumnLetter = 'C';
var range = e.range; // range just edited
var sheet = range.getSheet();
if (sheet.getName() !== sheetName) {
return;
}
// If the column isn't our modified date column
if (range.getColumn() != dateModifiedColumnIndex) {
var row = range.getRow();
var user = Session.getActiveUser().getEmail();
user = String(user);
user = user.replace('#gmail.com', '');
var dateModifiedRange = sheet.getRange(dateModifiedColumnLetter + row.toString());
dateModifiedRange.setValue(user);
};
};
This function works only when using owner account.
Even after Editor has authorised script manually from script editor - the onEdit user stamp function doesn't trigger.
Below is another function which I used for testing. When I run it manually from editors account IT WORKS - it saves editor's name in A1.
function USERNAME(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; // this will assign the first sheet
var cell = sheet.getRange('A1');
var d = new Date();
d.setHours(d.getHours() +1);
var user = Session.getActiveUser().getEmail();
user = String(user);
user = user.replace('#gmail.com', '');
cell.setValue(user);
}
In fact you have to use installable trigger.
Rename your function onEdit(e) with another name for example customFunction(e)
Then you setup an installable trigger using this function :
function createTrigger(){
ScriptApp.newTrigger('customFunction')
.forSpreadsheet(SpreadsheetApp.openById('YOU_SHEET_ID'))
.onEdit()
.create();
}
Or you can setup the trigger manually by going to 'Edit >> Current project's triggers >> Click on + button (bottom right)'
By this way trigger will run each time there is an Edit no matter the user.
StΓ©phane