I have google sheet where i would like to have an email notification been sent to a specified user whenever a cell in particular column has been edited.
The sheets contains 15 columns and one of the column is for comments and another for email address.
My requirement is whenever any cells in the comment column is edited, I would like to have an email sent to email address mentioned in a different column of the same sheet.
I did went over few of thread and found this thread had similar problem and has been successfully answered with a code. However, when i used this script it gives a a "Cannot read property 'range' of undefined (line 2, file "Code")" message.
I'm a noob to coding and not sure what does that means.
I also tried Magic Cell Notification addon but to no avail.
Any help will be greatly appreciated.
Send Email
You need to create an installable trigger for onMyEdit.
You need to provide the sheet name, the emailColumn, the commentColumn, the startingRow for data, the and the subject.
And please realize that you can't call this function from the script editor as it requires the event block from the onedit trigger.
`
function onMyEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()!='Your Sheet Name')return;
var emailColumn=1;//you have to tell me what column the email is on
var commentColumn=2;//you have to tell me what column the comment is on
var startingRow=2;//you have to tell me what row the data starts on
var subject='You tell me what the subject is';
if(e.range.columnStart==emailColumn && e.range.rowStart>startingRow && e.value) {
GmailApp.sendEmail(sh.getRange(e.range.rowStart,emailColumn).getValue(), subject, sh.getRange(e.range.rowStart,commentColumn));
}
}
Related
I created a google spreadsheet to track samples from vendors. I added 4 OnEdit functions to send email to two separate email addresses once the sample feedback is provided (approval cell is filled out with "Y" for approved or "N" for not approved. one function for each email address for a total of 4). However, I also tried to create a 5th OnEdit function to trigger an email (recipient based on the row) once the tracking checkbox is clicked. Unfortunately, that 5th OnEdit function is not working properly. Can you please advise how to solve this? Wondering if I should put all of these together in one function (and how, because it's my first time playing around with Apps Script), or if there is something wrong with the coding that is causing this not work properly.
Currently, the email goes out when ANY cells of that specific row are changed, and not just when the checkbox is clicked. Not only that, but the function has a huge error rate and is basically not working at all.
FUNCTION:
function onEdit(e) {
var range = e.range;
var col = range.getColumn();
var row = range.getRow();
var edited_value = e.value;
var ss = e.range.getSheet();
if(col == 5 && edited_value == "TRUE" && ss.getRange("R"+row).getValue() == "")
{
Browser.msgBox("Check If You Have an Email Address in column R ")
}else
{
var to = ss.getRange("R"+row).getValue();
var subject = ss.getRange("G"+row).getValue();
var Email_body = ss.getRange ("D"+row).getValue();
MailApp.sendEmail(to,subject,Email_body)
}
}
The onEdit(e) function is a simple trigger. Simple triggers run in a restricted context where classes such as MailApp and GMailApp are not available, because they require user authorization.
To make it work, you will have to use an installable trigger.
Note that when you have multiple onEdit(e) functions in the same script project,
only one of them will run. Also see onEdit(e) best practices.
I am a teacher and new to programing script. I have a sheet named 'Scores' in a Google spreadsheet that has a list of emails in column A and an array of data in the following columns. When any data in B:R is changed I would like to automatically send an email to the address listed in column A of the row that changed in this sheet that includes the data in that row and associated column headers.
Example.
Send Email to address in 'A4'
Subject line: Undated Scores
A string of text as a greeting.
Create a table with 'column headers' and 'Row Data'
B1 - B4
C1 - C4
D1 - D4
...to last column
Thanks
You will have to compose the subject and the message with the information found in data. The index for data is one less than the column number. If you wish to learn more about the onedit event object try adding console.log(JSON.stringify(e)) to the second line and it will print in the execution log. I like to use Utilties.formatString() when composing text mixed in with merged data.
//function will only run with you in the correct sheet and you edit any cell from b to r or 2 to 18
function sendEmailWhenBRChanges(e) {
const sh=e.range.getSheet();
const startRow=2;//wherever your data starts
if(sh.getName()=='Your Sheet Name' && e.range.columnStart>1 && e.range.columnStart<19 e.range.rowStart>=startRow) {
let data=sh.getRange(e.range.rowStart,1,1,18).getValues()[0];//data is now in a flattened array
//compose subject and message here if you want html then use the options object
GmailApp.sendEmail(data[0],Subject,Message);
}
}
on edit event object
Note you will have to create an installable trigger because sending email requires permission. You can create the trigger programmatically using ScriptApp.newTrigger() or go to the triggers section of the new editor or the edit menu in the legacy editor and don't forget to put the e in the parameters section of the function declaration.
Also please note that you cannot run this function directly from the script editor because it requires the event object that it gets from the trigger.
I know this is what you asked for but your not going to like it because it will trigger the email to be send whenever to edit any of the columns. You will probably prefer changing it later to accommodate putting a column of checkboxes which can be used as buttons for sending the emails.
I need the code that will send e-mail to some Google mail account whenever some data is entered to Google spreadsheet. I also need that data to be presented in e-mail, if possible.
I have found the answer for my question here How to put a username to the cell , who made the last modification of the row?
But this code for some reason do not work for me.
1 I open Google Spreadsheet script editor and paste that code
2 I change e-mail addresses to appropriate ones
3 I am asked for authorization
4 Then when I enter some data in Google spreadsheet I have display
notification but no e-mail
Actually sometimes I received e-mail, but not always and I do not understand why it was working before, because I didn't change anything.
I tried to create new spreadsheet with a new code but there e-mail notifications are still not working.
I checked postini e-mail firewall and it's clear - no messages there and Spam folder is also clear.
There is absolutely no simple tutorials on the Web on how to send e-mail on data entering to Google spreadsheet, except the question here, which I posted on the beginning.
Here is the code that I used:
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = event.source.getActiveSheet();
var r = event.source.getActiveRange();
r.setComment("Last modified: " + (new Date())+' by '+Session.getActiveUser());
ss.toast('Dernière cellule modifiée = '+r.getA1Notation()+' par '+Session.getActiveUser());
}
function alert(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell().getA1Notation()
if(Session.getActiveUser()!='me#mymail.com'){
MailApp.sendEmail('me#mymail.com', 'Modification dans le planning', 'la case '+cell+' du document a été modifiée par '+Session.getActiveUser());
}
}
Thank you for your time and answers.
EDIT
After some more investigation I wrote this code. It send e-mail, but for some reason there is no user.id in e-mail, only cell.id.
function sendSimpleTextEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell().getA1Notation();
var user = Session.getActiveUser();
MailApp.sendEmail('me#mymail.com',user,cell);
}
I finally managed to make it working
The code is:
function sendSimpleTextEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
Logger.log(ss);
var name = ss.getName();
Logger.log(name);
var url = ss.getUrl();
Logger.log(url);
var cell = ss.getActiveCell().getA1Notation();
Logger.log(cell);
var result = ss.getActiveCell().getValue();
Logger.log(result);
var email = Session.getActiveUser().getEmail();
Logger.log(email);
MailApp.sendEmail('my#mymail.com','Data was changed in a spreadsheet `' +name+ '` in a cell ' +cell+ ' by user ' +email+ ' New Data=`' +result+ '`','Data was changed in a spreadsheet `' +name+ '` in a cell ' +cell+ ' by user ' +email+ ' New Data=`' +result+ '` Spreadsheet URL is ' +url);
}
After creating this script you need to configure manual triggers by pressing Current project's triggers button. You need only On Edit trigger.
Remark1 - difference between On Change and On Edit triggers:
An installable edit trigger runs when a user modifies a value in a spreadsheet.
An installable change trigger runs when a user modifies the structure of a spreadsheet itself — for example, by adding a new sheet or removing a column. More info https://developers.google.com/apps-script/guides/triggers/installable
Remark2 - Session.getActiveUser().getEmail() works only inside GoogleApps domain. If I share spreadsheet with anybody outside of the domain - it will return empty string.
EDIT: typos
I'm not that well versed in Javascript, but just covering the obvious.
When you are testing your script, are you using an account OTHER than the one you've entered in the script in the changes?
I'm assuming you've changed me#mymail.com to your email?
if(Session.getActiveUser()!='me#mymail.com')
That part of the code says, If the user logged in ISNT this email, then send the mail judging by the next bit.
So when testing, use an account that isn't me#mymail.com
EDIT
Should have read the origianl posters question more.
So after reading properly the code.
unless I'm really mistaken, you should only have one on edit script ideally.
And the part of the script the OP wants isn't on the on edit trigger, it's just a function. The on edit part of the code simply adds comments to the sheet. So maybe a better answer for OP is to put the alert() function in the onEdit() function
Something like
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell().getA1Notation();
if(Session.getActiveUser()!='me#mymail.com'){
MailApp.sendEmail('me#mymail.com', 'Modification dans le planning', 'la case '+cell+' du document a été modifiée par '+Session.getActiveUser());
}
}
This is untested by the way, just hoping to help you get on track
If I have a Google Spreadsheet e.g.
https://docs.google.com/spreadsheet/ccc?key=0AjAdgux-AqYvdE01Ni1pSTJuZm5YVkJIbl9hZ21PN2c&usp=sharing
And I have set up notifications on it to email me immediately whenever a cell changes.
And I make a change to that spreadsheet via the spreadsheet API - i.e. not by hand.
Then I get an email like this:
Subject: "Notification Test" was edited recently
See the changes in your Google Document "Notification Test": Click
here
other person made changes from 10/01/2014 12:23 to 12:23 (Greenwich
Mean Time)
Values changed
If I open the 'Click here' link then I get this URL which shows me the cell that has changed in the spreadsheet:
https://docs.google.com/a/DOMAINGOESHERE/spreadsheet/ver?key=tn9EJJrk6KnJrAEFaHI8E3w&t=1389356641198000&pt=1389356621198000&diffWidget=true&s=AJVazbUOm5tHikrxX-bQ0oK_XEapjEUb-g
My question is:
Is there a way to get the information about which cell has changed in a format that I can work with programmatically- e.g. JSON?
I have looked through the Google Spreadsheet API:
https://developers.google.com/google-apps/spreadsheets/
and at the Drive API Revisions:
https://developers.google.com/drive/manage-revisions
I have also tried setting up an onEdit() event using Google Apps Script: https://developers.google.com/apps-script/understanding_triggers
I thought this last approach would be the answer.
The problem with this approach is that whilst onEdit can be used to email details of changes, it appears to only be fired if the spreadsheet is edited by hand whereas mine is being updated programmatically via the spreadsheet API.
Any ideas?
You could build a function that checks for changes. One way to do this is by comparing multiple instances of the same spreadsheet. If there are differences, you could email yourself. Using the time driven trigger, you can check every minute, hour, day, or week (depending on your needs).
var sheet = **whatever**;//The spreadsheet where you will be making changes
var range = **whatever**;//The range that you will be checking for changes
var compSheet = **whatever**;//The sheet that you will compare with for changes
function checkMatch(){
var myCurrent = sheet.getRange(range).getValues();
var myComparison = compSheet.getRange(range).getvalues();
if(myCurrent == myComparison){//Checks to see if there are any differences
for(i=0;i<compSheet.length;++i){ //Since getValues returns a 'multi-dimensional' array, 2 for loops are used to compare each element
for(j=0;j<compSheet[i].length;++i){
if(myCurrent[i][j] != myComparison[i][j]){//Determines if there is a difference;
//***Whatever you want to do with the differences, put them here***
}
}
myEmailer(sheet.getUrl());//Passes the url of sheet to youur emailer function
compSheet.getRange(range).setValues(myCurrent);//Updates compSheet so that next time is can check for the next series of changes
}
}
Then from Resources>Current project's triggers you can set checkMatch to run every minute.
Also check out https://developers.google.com/gdata/samples/spreadsheet_sample for pulling data as json
I'd like to know if there's a way to get the original value of the cell from within the onEdit() event.
For example:
Cell A1's current value is "hello"
I edit A1 it by changing it to "world"
Right now, when I try to get the value from the active range, I'd get "world"
But I would also like to have the possibility to get the original value, i.e. "hello". Is that currently possible?
You can use onEdit(e) and e.oldValue if you're dealing with a single cell. The example below adds the original value to A1 when any cell is edited. 'undefined' if the cell was blank.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getActiveCell();
var origValue = e.oldValue
sheet.getRange('A1').setValue(origValue);
}
The only code that would come close to this is to use an onOpen exit to save
the initial value. The initial value could be saved in several ways. There
are "user properties". I don't know how they work, yet. I am new to this.
You could also use a "hidden" sheet to save the value, in the "onOpen" exit.
There may be other ways, that I don't know about.
The problem becomes more difficult with an increasing number of cells for which
you want to save the original value.
By-the-way, you should understand that the "onOpen" routine fires at the time
the spreadsheet is opened. It so happens, that the end-user also has access and
can change cell values before the onOpen handler finishes its execution. You may
not capture all of your initial values.
One final thing you should know. The onEdit trigger is NOT fired when an UNDO or REDO
event occurs. The cell's contents could change and you will not know it.
I don't know how a validation routine works. If the routine rejects a value, will
the spreadsheet restore the original value? If it does, then this might get around
the onOpen problem. If it only tells the user the value is invalid, it will not be
of much help.
A really round about way that may work, but is very complicated is to save the image
before the spreadsheet closes. You post all the "after" images to a second spreadsheet.
Then in your onEdit handler you look at the corresponding cell in the other spreadsheet.
You then decide to restore the previous image or allow the new image to proceed.
Lastly a wild idea of using a data table in place of the second spreadsheet.
I am just learning about all of these concepts, so don't ask me how to implement them.
I just understand that they MIGHT be possible. For coding and support purposes they
may not be the best options. But since the current script service does not provide
before image access, it is about the best I could do. You have to understand that this
google interface is a client-server application. Your scripts run on the server. The data changes occur in the "clients" (end-users) browser.
One final note: the onEdit trigger does not fire for an UNDO or REDO change to a cell.
So the cell could change and your script is not aware of it.
I don't think that's possible.
I imagine you could get that functionality by having a exact copy of your sheet on a second sheet that updates automatically when your 'onEdit' functions ends.
Until that update, data on the second sheet will have the former value.
A bit tricky but why not ?-)
EDIT : seems to be the 'question of the day', see this post and Henrique Abreu's pertinent comment.
When you change the value of a cell diagrammatically, you can use the setComment method to store the original value as a comment in that cell.
What you basically need to do is to create a shadow sheet (which you can protect and hide or even have it in a totally separate spreadsheet) and use the IMPORTRANGE function to get the values of the original sheet into the shadow sheet (This gives enough delay time to get the old value that was in the cell before it got edited).
=IMPORTRANGE("enter your original sheet's ID","enter the range you wish to get from the sheet")
Please note that using this code, when editing multiple cells at the same time, the function will only work on the first cell.
function onEdit(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var originalSheet = sheet.getSheetByName('Original');
var shadowSheet = sheet.getSheetByName('Shadow');
var editedCell = originalSheet.getActiveCell();
var cellColumn = editedCell.getColumn();
var cellRow = editedCell.getRow();
var oldValue = shadowSheet.getRange(cellRow, cellColumn).getValue();
var cellValue = editedCell.getValue();
var editorMail = Session.getActiveUser().getEmail(); \\getting the editor email
if ("The condition you want to meet for the onEdit function to activate"){
editedCell.setNote(editorMail + "\n" + new Date + "\n" + oldValue + " -> " + cellValue);
}
}