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
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 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));
}
}
I have a form, linked to a spreadsheet. On this spreadsheet I have a script working on the answers of the form.
The script have to generate a mail to the user who answered the form, and sometimes ask him to modify his answer.
I want to generate a pre-filled-form link (pre-filled with the answer of the user), to send it by mail and so let him change only what i want him to change (not have to fill all the form again)
I saw there is a way to do that using the function
getEditResponseUrl()
--> var 'responses' = 'myform'.getResponses();
--> var 'modificationUrl' = 'responses'[?].getEditResponseUrl()
I don't know which 'responses' of the form to take. (because I have less line in my spreadsheet than number of form response...
Please, is there any way to know which response to use to do the getEditResponse (using the time for exemple..; but I don't know how)
Thank you in advance.
instead of using the link from the form to the spreadsheet, you could maybe write your own the data from the form into the spreadsheet. In the object given by the form you will retrieve his id and with his id you'll then have the ability to link efficiently the entry of your spreadsheet to your form answer.
You can look at this ticket
to learn a bit more how to handle form answers. And if you need specific informations (you will do) on how manipulate the response of a form when triggered on form submit you can check this issue.
exemple:
// for a form with 2 question named "question 1" and "question 2"
function submitFormFunc(e) {
var items = e.response.getItemResponses();
var responses={};
for(var i = 0; i< items.length; i++) {
responses[items[i].getItem().getTitle()]=items[i].getResponse();
}
var responseTable = [];
var responseIndex = ["Timestamp","ID","question 1","question 2"];
responseTable.push(e.response.getTimestamp().toString());
responseTable.push(e.response.getId());
responseTable.push(responses["question 1"]);
responseTable.push(responses["question 2"]);
responseTable.push(FormApp.getActiveForm().getResponse(e.response.getId()).getEditResponseUrl());
SpreadsheetApp.openById("your spreadsheetId").appendRow(responseTable);
}
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);
}
}