Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Apps Script Class GmailApp Batch Operations?

I've been fooling around with GAS for a month or so now, and I've become fairly familiar with using batch operations to read/write to/from spreadsheets (e.g. getValues(), setValues()). However, I'm currently writing a script that pulls a sizable amount of data out of Gmail using class GmailApp, my code is running very slowly (and even timing out), and I can't seem to figure out how to use batch operations for what I'm trying to do. Here's my code thus far (with the email address and name changed):

 function fetchEmails(){
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var threads = GmailApp.search('in: label:searchedLabel');
  var messages = new Array();

  function Email(message){
  this.date = new Date(message.getDate());
  this.body = message.getBody();
  }

  for(var i=0;i<threads.length;i++){
    for(var j=0;j<threads[i].getMessageCount();j++){
      if(threads[i].getMessages()[j].getFrom()=="firstName lastName <[email protected]>"){
       var message = new Email(threads[i].getMessages()[j]);
       messages.push(message);
      }
    }
  }  
}

As you can see, I'm querying my email for all threads with the given label, making an object constructor for a custom Email object (which will have the body and date of an email as properties). Then I'm looping through each thread and when a given email matches the sender I'm looking for, I create an instance of the Email object for that email and place that Email object into an array. The goal is that in the end I'll have an array of Email objects that are all from my desired sender. However as you've probably noticed the code calls Google's APIs way too often, but I can't seem to figure out batch operations for interfacing with Gmail. Any ideas? Thanks so much.

like image 472
PriceHardman Avatar asked Aug 19 '12 18:08

PriceHardman


People also ask

What is Gmailapp?

About this app The official Gmail app brings the best of Gmail to your Android phone or tablet with robust security, real-time notifications, multiple account support, and search that works across all your mail.

What method pertaining to what class can send emails in Apps Script?

Sends email. This service allows users to send emails with complete control over the content of the email.


1 Answers

I think you are looking for GmailApp.getMessagesForThreads().

function fetchEmails(){
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var threads = GmailApp.search('label:searchedLabel');
  var messages = new Array();

  function Email(message){
    this.date = new Date(message.getDate());
    this.body = message.getBody();
  }

  var gmailMessages = GmailApp.getMessagesForThreads(threads);

  for(var i=0;i<thread.length;i++){
    var messagesForThread = gmailMessages[i];
    for(var j=0;j<messagesForThread.length;j++){
      if(messagesForThread[j].getFrom()=="firstName lastName <[email protected]>"){
       var message = new Email(messagesForThread[j]);
       messages.push(message);
      }
    }
  }  
}

Of course you can also write this a little more concisely (sorry, I can't turn up an opportunity to educate about the wonders of JavaScript):

function fetchEmails(){
  var messages = Array.prototype.concat.apply([], GmailApp.getMessagesForThreads(
      GmailApp.search('label:searchedLabel')).map(function(messagesForThread) {
    return messagesForThread.filter(function(message) {
      return message.getFrom() == "firstName lastName <[email protected]>";
    }).map(function(message) {
      return { date: new Date(message.getDate()), body: message.getBody() };
    });}));
}

This makes a grand total of 2 calls to Gmail, so it's going to be fast.

In fact, if you integrate the 'from' part into the search as was suggested above, all you need is:

function fetchEmails(){
  var messages = Array.prototype.concat.apply([], GmailApp.getMessagesForThreads(
    GmailApp.search('label:searchedLabel from:[email protected]')).map(
      function(messagesForThread) {
        return messagesForThread.map(function(message) {
          return { date: new Date(message.getDate()), body: message.getBody() };
      });}));
}

Finally, since you don't actually care about the thread structure, you can just concat the arrays before the map, which leads to this:

function fetchEmails(){
  var messages = GmailApp.getMessagesForThreads(
        GmailApp.search('label:searchedLabel from:[email protected]'))
      .reduce(function(a, b){ return a.concat(b); })
      .map(function(message) {
         return { date: new Date(message.getDate()), body: message.getBody() }; 
      });
}

(I left in the earlier samples in case you do care about the thread structure and you were just giving a minimal example).

like image 101
Corey G Avatar answered Nov 11 '22 08:11

Corey G