59

I have created a Google Apps Script that checks if an email has an attachment then send it to another email address.

It's working fine, but I would like to create a trigger that would launch the script as soon as a new email arrives in the inbox.

I have been able to create a trigger that launch the script every hour, but it's not what I want

AziCode
  • 2,510
  • 6
  • 27
  • 53
  • why not change it to launch every 5 minutes? – Bryan P Mar 19 '16 at 23:46
  • 1
    I tried but I get a report at the end of the day saying that my scrip ran too many times. And it's not what I want, I want to run the script as soon I receive an email – AziCode Mar 19 '16 at 23:54
  • 4
    Spencer offered some sample code from [this post](https://plus.google.com/u/0/+SpencerEastonCCS/posts/AwnJQWoD396) after [this announcement](http://googleappsdeveloper.blogspot.com/2015/05/gmail-api-push-notifications-dont-call.html) – Bryan P Mar 20 '16 at 00:11
  • That pubsub from Bryan P's comment looks interesting. Too bad there's not just an easy option to "run after each email" or what not. FWIW the most frequent it can trigger (if you go the trigger route) is "every minute" (and total cpu must be >= 90 min. per day)... – rogerdpack Mar 29 '18 at 21:03
  • 1
    The blog post from Bryan P's comment went away when Google+ did, but the author has posted an updated example at https://github.com/Spencer-Easton/Apps-Script-Gmail-Push-Notifications-v2 – Tripp Lilley Oct 21 '19 at 02:18

3 Answers3

52

After some research and some help from other google-apps-script developers, the best solution is to use a combination of Gmail filtering system in addition to a time-driven-trigger.

So basically for a normal Gmail account there is a 1 hour/day computing time as mentioned in the documentation.

So what I did is set up a filter that adds a Label and a star to the incoming emails that need to be processed.

In my script I add the Labels in an array, I loop over the array of labels so that I process only the desired emails and not the whole inbox.

Once processed, the script removes the star from the processed email.

This way you don't lose your precious compute time, and you don't reach the daily limit.

I then set a time driven trigger that runs every 10 minutes.

You can also set up the time driven trigger to send you a daily "Summary of failures " so that you can see what went wrong with your script and fix what has to be fixed.

halfer
  • 19,824
  • 17
  • 99
  • 186
AziCode
  • 2,510
  • 6
  • 27
  • 53
  • 14
    Please may you share your script – GeorgeButter Nov 19 '17 at 23:59
  • How does this work today? Also, what kinds of volumes are you processing? – frostymarvelous Apr 03 '18 at 11:44
  • 2
    I’ve read in related articles that labels are only applied at the thread level, so new incoming emails on a pre-existing thread might get missed with the above approach. Does your implementation resolve that somehow? – sarora Aug 24 '18 at 20:35
  • Like me, at first, you might think "why this question is even upvoted so much" while it has no use probably.., but later you will eventually upvote, as you will find it useful :) yeah, unfortunately no script shared, but still good advise. – T.Todua Feb 21 '21 at 18:24
  • 1
    @T.Todua, I’m glad the answer is helping. I’m sorry I haven’t seen all the comment asking for the script. I will have a look in my archives and see if I can find the script – AziCode Feb 21 '21 at 18:30
8

This answer is adapted from the answer of @AziCode but includes code.

Components of the solution:

  • A code-free Gmail filter that catches emails with the desired condition; for actions choose “star it” and “apply the label” (enter your desired label)
  • A trigger configured to run often; this trigger loops through your emails, catching ones that are starred and have the label, performing your desired action on them, and then removing the star.

Here’s the code to have in your Google Apps Script project (you must give the script permission to access your GMail inbox):

// Configure this trigger to run often
// (*how* often depends on the desired response time *and* how willing you are to risk hitting Google Apps Script’s rate limits;
// 10 minutes is probably good)
function triggerScriptForEmail() {
  const threads = GmailApp.search('is:starred label:"<your desired label>"');

  for (const thread of threads) {
    const messages = thread.getMessages()

    for (const message of messages) {
      // we know the thread *has* starred messages, but not *all* messages are necessarily starred
      if (message.isStarred()) {
        // THE CODE SPECIFIC TO YOUR CASE GOES HERE
        // THEN...
        message.unstar()
      }
    }
  }
}
Mattias Martens
  • 1,369
  • 14
  • 16
1

You're probably better off running something like the following, it's not perfect and may need tinkering but this is how i'd achieve it:

function YourAutoEmailReplier() {
  var ureadMsgsCount = GmailApp.getInboxUnreadCount();
  if (ureadMsgsCount > 0) {
    var threads = GmailApp.getInboxThreads(0, ureadMsgsCount);
    for (var i = 0; i < threads.length; i++) {
      var message = threads[i].getMessages()[0]; 
      //this 0 above means it only replies to the first email message in reply chain
      //You can adjust this get the latest if you like
      var email = message.getFrom();
      var body = message.getPlainBody();
      var subject = message.getSubject();
      var date = message.getDate();
      date = date.toString();
      var fulldate = date.split(' ');
      var day = fulldate[0];
      var month = fulldate[1];
      var numday = fulldate[2];
      if (numday.charAt(0) === '0') {
        numday = numday.slice(1);
      }
      var year = fulldate[3];
      var time = fulldate[4];
      var brokentime = time.split(':');
      var hour = brokentime[0].replace(/^0+/, '');
      var minute = brokentime[1];
      var second = brokentime[2];
        if (subject.indexOf('RE:') > -1) {
          var subject = subject;
        } else {
          var subject = "RE: " + subject;
        }
        var fulldetails = email.split(' ');
        var firstname = fulldetails[0];
        var surname = fulldetails[1];
        var replyBody = "Hello there " + firstname + "!,\nThank you ever so much for your email at " + hour + " on " + day + " the " + numday + " of " + month + ". I will be sure to get back to you as soon as possible.\nKind Regards\n\n";
        GmailApp.sendEmail(email, subject, replyBody);
        message.markRead();
      }
    }
  }

Then go to Triggers -> Add Trigger -> Set your event source to time-driven -> select minutes timer and choose the least amount of minutes available to your account

John
  • 168
  • 3
  • 11