0
votes

The following script for the Gmail API (script.google.com) works without any problems when I run it manually, but when it's triggered by Google using a time-based trigger it fails.

function noSend(e) {  
  var drafts = GmailApp.getDrafts();
  var callback = function(draft) {
    function isMyEx(draft) {
      var recipient = draft.getMessage().getTo();
      var isTheirEmail = /nameofmyex/.test(recipient);
      return isTheirEmail; };
    if(isMyEx(draft)) {
      draft.update('', '', ''); 
      draft.deleteDraft(); 
    } else {  } };

  drafts.forEach(callback); return;
};

Question: How can I debug this when the error doesn't occur when I run the script manually?

I.e. adding Logger.log() doesn't help, because the only way I get to see its output is when I run the script manually -- but the script works without any problems when I run it manually.

The error in question, as far as I can tell from Google's website (I don't understand the layout) is:

TypeError: Function getMessage in Object [object Object] was not found

which doesn't make any sense to me, sine the only time the getMessage method is called is by draft in the function isMyEx, which shouldn't have Object as its prototype, but instead should have GmailDraft as its prototype, which most definitely does have a getMessage method.

My only guess so far is that it has something to do with function hoisting, whose rules I don't understand very well. But I've already played around with several ways of ordering the functions and where to define them -- all of them worked when I ran the script manually. Again, this failure is occurring only when the script is triggered automatically by Google, which confuses me to no end.

Related questions: Gmail API message.list from trigger
Function works only when launched manually (not when triggered) in Google Apps Script Form

1

1 Answers

1
votes

This was incredibly stupid, but in case it might help someone else in the future (it won't, because this level of stupidity is probably not replicable but):

In the original version of my script, the function isMyEx was declared in global scope* outside of doSend more or less like the following:

function isMyEx(draft) {
      var recipient = draft.getMessage().getTo();
      var isTheirEmail = /nameofmyex/.test(recipient);
      return isTheirEmail; };

function noSend(e) {  
  var drafts = GmailApp.getDrafts();
  var callback = function(draft) {
    if(isMyEx(draft)) {
      draft.update('', '', ''); 
      draft.deleteDraft(); 
    } else {  } };

  drafts.forEach(callback); return;
};

Since isMyEx was defined before noSend, when I clicked the button to set a trigger for the script, the default function to be triggered was the one to be defined first isMyEx. Which of course will throw the error that I described if it is called outside of doSend, instead of as a callback within.

*This is probably considered bad practice. If so, please understand that I did it out of ignorance, not out of some malicious intent to spread bad coding practices to the visitors of this web site. In particular, please don't yell at me. I've already served my punishment for this bad coding practice, since it has already come back to bite me in the behind, see below.

Moral of the story: The triggers are not for the entire script. It is not only possible, but actually necessary to set a trigger for each function in the script individually. So if you don't bother to look at which function in the script you are setting the trigger for, don't be surprised like I was when you don't get the desired results.

I only figured this out because, after putting the definition of isMyEx inside of noSend (and then inside of callback), when I clicked the trigger button of the script again, there was a red message below the trigger Selected function not found. This didn't make sense to me at first, since I thought the trigger was for the entire script, but then I looked at the buttons more carefully and realized that it meant that the trigger was only trying to run the function isMyEx, not the entire script file (which I guess would make sense for much larger scripts). Anyway, after moving isMyEx from global scope, it made sense that the function could no longer be found.

Anyway, after I changed the trigger to be for noSend instead of isMyEx, everything works fine/perfectly with the automatic trigger, not just when I run the script manually.