我已经在GAS周围呆了一个月左右,并且我已经非常熟悉使用批处理操作读取电子表格(或从电子表格写入)(例如getValues(),setValues())。但是,我目前正在编写一个脚本,该脚本使用类GmailApp从Gmail中提取大量数据,我的代码运行非常缓慢(甚至超时),而且似乎无法弄清楚如何使用批处理操作我想做的。到目前为止,这是我的代码(电子邮件地址和名称已更改):

 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);
      }
    }
  }
}


如您所见,我正在查询电子邮件中具有给定标签的所有线程,
为自定义Email对象(该对象将电子邮件的正文和日期作为属性)创建对象构造函数。然后,我遍历每个线程,当给定的电子邮件与我要查找的发件人匹配时,我为该电子邮件创建电子邮件对象的实例,并将该电子邮件对象放入数组中。目标是最终获得一个来自所有所需发件人的电子邮件对象数组。但是,您可能已经注意到代码经常调用Google的API,但是我似乎无法弄清楚与Gmail进行接口的批处理操作。有任何想法吗?非常感谢。

最佳答案

我认为您正在寻找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);
      }
    }
  }
}


当然,您也可以写得更简洁一些(对不起,我无法提供一个机会来学习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() };
    });}));
}


这样一来,总共有2次对Gmail的呼叫,因此很快。

实际上,如果您按照上面的建议将“ from”部分集成到搜索中,则所需要做的只是:

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() };
      });}));
}


最后,由于您实际上并不关心线程结构,因此可以在映射之前连接数组,从而得出以下结果:

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() };
      });
}


(我留在较早的示例中,以防您确实关心线程结构,而您只是给出一个最小的示例)。

08-06 10:12