Google Apps Script spreadsheet triggers expiring - google-apps-script

I have a shared google spreadsheet with rows representing accounts and the state of those accounts.
Accounts can go from being outlined, to signed, to ordered.
I want it so that when an account is Edited from Outlined -> to Signed, I send an email to the person responsible for the "Ordering" portion.
Because I can't send emails inside the onEdit(e) trigger, I have made a custom function, customOnEdit which will listen to the same events and send the email. This works fine.
function customOnEdit(e) {
process(e);
}
What happens next will shock you:
The trigger will simply stop working
The trigger will go from being regular black, to being greyed out. Any edits will not send any emails:
Trigger greyed out
It can be weeks later. It can be just the next day. But because of this I have to check it daily and reset it otherwise things will stop flowing.
How can I deal with this issue?

Related

Google Calendar Trigger Does Not Fire

The objective is to transfer data from Google Calendar to a Google Sheet whenever the calendar is edited. For this we need a script that transfers the data, and need to set up the Calendar trigger.
Thanks to Oleg Valter and his excellent and exhaustive explanation how to create the script on this page:
Google calendar events to Google spreadsheet automatic refresh onEdit
the data transfer already works fine when the script is started from the Google sheets. I use a modified version of Oleg's script, which works well, and I am not sure if it would make sense to re-post it here (since that is not the problem).
I have tried to create the trigger with Oleg's funtion first:
/**
* Installs Calendar trigger;
*/
function calendarTrigger() {
var trigger = ScriptApp.newTrigger('callback name here')
.forUserCalendar('calendar owners email here')
.onEventUpdated()
.create();
}
but the trigger did not fire when I have added a new event on the calendar. Checked the triggers connected to the project, and the trigger created by the above function was there. Checked the Executions and nothing showed up.
Then I have manually deleted the trigger, and manually crated a new one following the instructions under "Managing triggers manually" section of this page:
https://developers.google.com/apps-script/guides/triggers/installable#google_apps_triggers
The trigger was created again, which basically looked the same as the one created by the above function, but it still did not fire when tested.
Now I am stuck and have no idea what else to try. It supposed to work, but it is possible that I have missed setting up something else that might be required for this to work.
I am using a simple Google account connected to a single email address (not a business suite). Never had any problems with the other triggers related to the sheets before that I could not resolve (sometimes the platform refuses to work as it should, but then later things get back to normal).
I would highly appreciate any advice about what else to try, or if you know what the problem is, even better.
Thanks in advance,
Zoltan
Well, after some trial and error based on ziganotschka's kind answer (thanks again) found the problem. It is caused by a bit of confusion about what the
.forUserCalendar('calendar owners email here') and the
Calendar ID supposed to be.
On my Calendar account there are several calendars, but two are of interest for us here:
"Main Calendar" which is the default calendar associated with the account. If everything else is deleted, then this will remain.
another calendar that I have added for the very purpose to be connected to the spreadsheet, and named it "Auto Billing" (only this is checked and displayed).
The Main Calendar has this on the Settings page (changed my email address):
Integrate calendar
Calendar ID
myAddress#yahoo.com
The Auto Billing calendar has this on the
Settings page (changed the ID):
Integrate calendar
Calendar ID
svj8tu1o458a9s1488xxxxxxxx#group.calendar.google.com
My intent was to use a custom created calendar for this purpose instead of using the default Main Calendar, because this might be full with all kinds of events.
Therefore when the trigger is created manually
svj8tu1o458a9s1488xxxxxxxx#group.calendar.google.com
should be added in the field "Calendar owner email" instead of the calendar owner's email address.
When the trigger is created from script using the above snippet, then
.forUserCalendar("svj8tu1o458a9s1488xxxxxxxx#group.calendar.google.com")
should be used.
In the script that transfers the data from the Calendar to the sheet the
var Calendar = CalendarApp.getCalendarById("svj8tu1o458a9s1488xxxxxxxx#group.calendar.google.com");
should be used. This way the trigger will work when events are edited on the Auto Billing calendar.
Thanks for the guidance Ziganotschka, and also big thanks to Oleg for the original script. Hope this debugging will help others as well.
Google Calendar trigger is a feature for the Google Calendar
It does not work for "myaddress#yahoo.com" calendars

MailApp.sendEmail -> mail coming from different accounts

I am using a script in a shared spreadsheet to send update emails to the working team.
I am using a simple call:
MailApp.sendEmail(mail_address, subject, msg);
It worked fine for some time.. But now I have a strange behavior: the script runs successfully but the emails are actually sent randomly by one of the users which the spreadhsheet is shared with..
I can't understand how that is possible since they are not shared accounts and it shouldn't be possible to send emails like that..
Edit: The script is executed by a trigger based on the editing of the spreadsheet.
Situation:
You have installed an onEdit trigger for all users which have edit access to the spreadsheet.
The function trigged by this trigger sends an email.
You are noticing that the emails are not always being sent by the user that edited the spreadsheet.
Issue:
The problem is that, as you can see here:
Installable triggers always run under the account of the person who created them.
This means the email will not be sent by the user that edited the spreadsheet, but by the one who installed the trigger. Since several users installed this trigger, your project might contain several duplicate triggers, each of which will run on behalf of a different account. Because of this, you might end up receiving multiple emails for one single spreadsheet edition, each of them sent by a different account.
Solution:
If you want to send a single email every time the spreadsheet is edited, and send this email from the account that edited the spreadsheet, you can use the methods getActiveUser() and getEffectiveUser():
Session.getActiveUser() refers to the current user, that is to say, the user that just edited the spreadsheet.
Session.getEffectiveUser() refers to the user under whose authority the script is running. That is to say, the user who installed the trigger.
The idea is to check whether the active user and the effective user are the same one, and send an email only if that's the case. This way, even if multiple functions are trigged by a single edition (one for each account that installed the trigger), only one email will be sent (the one corresponding to the user who edited the spreadsheet).
Code sample:
function onEditTrigger(e) {
var activeUser = Session.getActiveUser().getEmail();
var effectiveUser = Session.getEffectiveUser().getEmail();
if (activeUser === effectiveUser) {
// Rest of code
MailApp.sendEmail(mail_address, subject, msg);
}
}
Note:
If you have installed the trigger, you better not name your function onEdit: this name is reserved for a simple trigger.
Reference:
Installable triggers: Restrictions

Multiple OnFormSubmit trigger to specific spreadsheet

So, we have this task where we have a Google Form where a user submits data as a sign up for a mentoring service that gets passed on to a Spreadsheet and the user gets an e-mail as a sort of like confirmation that the sign-up did indeed happen. During this, the mentor that the user specified also gets an e-mail with some of the information that the user has sent, and a link that redirects them to a pre-filled Google Form that contains some of the information that the user submitted, and a drop-down question that basically serves as an attendance check.
Now, all of that mentioned already works. The problem is, the way it is set-up is that there are 2 Google Forms that direct to the same spreadsheet, just in different tabs. If I try to use OnFormSubmit as a trigger for the functions that allows for the emails to be sent, what happens is both OnFormSubmit triggers occur at the same time. I've seen multiple solutions to this problem here but none of them seem to work for me. Is there a way to manually script the OnFormSubmit function to let it work only when a specific form is passed?

Installable OnEdit not being called in Stock spreadsheet

I have a function (in a Google Apps Script), not called onEdit(), but something else and this has been set up to be called from any on edit events via in the Installable onEdit on a Google Spreadsheet.
The spreadsheet is around stocks and monitors a portfolio and the purpose of the function is to send an email as soon as a stop loss is hit on a stock, i.e. the price of a stock falls to a certain price. The price of the stock is retrieved and updated via the Google Finance API in a column in the spreadsheet.
Now, when running the function from the script or locally editing the spreadsheet, the function is called successfully. However, I am finding that as the stock price is updating automatically throughout the day on Google Drive and falling to the stop loss price, the on edit function is not being called. I read somewhere about it not being called by an "anonymous" user? I know it's not being called as I have an "email counter" column, which decreases every time the function is called, and once at 0 no more mails will be sent to avoid spamming. This not decreasing via the Google Finance API automatic price updates.
Can someone advise what is causing this and if this there is any workaround?
A list of things-that-don't-trigger-onEdit, along with their issue tracking ids, were provided in a previous answer.
Content of a spreadsheet changed by scripts does not trigger onEdit.
A work-around might be to use a time-based trigger, and in the call-back scan for and react ti changes. (Could the updater set a trigger to fire in the near future, perhaps?) Challenges for this will be around balancing responsiveness vs trigger limits.

How to stop duplicate emails from active users?

I need a little guidance!
I have created a simple script for a Google Spreadsheet that is designed to email a user when a specific criteria is met and mark that row as "Emailed"; it runs on the onEdit trigger and works great.
However, if more than one trigger enabled user has the sheet open at the same time it will send the same email from each account.
I tried using:
function onChange(e) {
if (ROW HASN'T BEEN EMAILED ALREADY) {
if (3 CELLS IN A ROW HAVE CONTENT) {
if (Session.getActiveUser().getEmail() == e.user.getUserLoginId()) {
SEND THE EMAIL
MARK ROW AS EMAILED
}
}
}
}
So that only the user that made the change sends the email, however, all users still send the email. I have compared the values Session.getActiveUser().getEmail() and e.user.getUserLoginId() produce manually and in theory it should work ... though clearly I am doing something wrong!
Thanks.
This is a bit of a confusing topic but I believing this is functioning correctly.
Here are some details.
In the onChange(e) function, e.user will always be the person that "owns" the document. Look towards the bottom of this page on events in the document. In essence, you cannot figure out which user's change caused the trigger to fire.
When there are two users each with a trigger on the onEdit event, then both of the triggers will run each time (essentially the function runs twice) even if only one of the user has the spreadsheet open. However, per #1 you can't within the trigger function run figure out which user's change caused the onEdit event
You'll have to rethink your workflow a bit, perhaps as a timed trigger that checks every hour for people to be emailed. Another option is to only have one trigger that runs as the document owner and you can perform the checking logic there. Hope this makes sense.