忽略具有不同标签的同线程电子邮件

时间:2018-08-16 06:03:18

标签: google-apps-script gmail

我正在将日期主题从特定的新电子邮件写入Google表格的新行。

  1. 我使用过滤器将标签应用于新邮件项目。
  2. 该脚本处理那些带有标签的电子邮件
  3. 标签被删除
  4. 将应用新标签,以便下次不再处理这些电子邮件。

问题:当存在 myLabel 电子邮件时,脚本将处理同一线程(例如,相同的主题和发件人)中的所有电子邮件,而不管其标签(即使是收件箱和垃圾)。

问题:如何仅处理新电子邮件,即带有标签 myLabel 的电子邮件-即使这些邮件的线程超出了 myLabel 夹?

我当前的脚本:

function fetchmaildata() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('mySheetName');

  var label = GmailApp.getUserLabelByName('myLabel');
  var threads = label.getThreads();

  for (var i = 0; i < threads.length; i++)
  {
    var messages = threads[i].getMessages();

    for (var j = 0; j < messages.length; j++)
    {     
      var sub = messages[j].getSubject();
      var dat = messages[j].getDate();

      ss.appendRow([dat, sub])
    }
    threads[i].removeLabel(label);
    threads[i].addLabel(newlabel);
  }
}

我通过将for循环更改为此目的来破解了一个解决方案:

for (var j = messages.length-1; j > messages.length-2; j--)

这表示仅处理线程中的最新电子邮件,即使 myLabel 文件夹中有多个线程的电子邮件也是如此。奇怪的是,脚本仍会更改所有 myLabel 电子邮件中的标签,但是只有最新的一个线程被写入到电子表格中,因此它对我有用。

我不得不对代码进行另一处更改,因为上面的代码不能作为时间触发的计划任务运行。我以这种方式更改了代码,现在它可以按时间表运行了!!

//var ss = SpreadsheetApp.getActiveSpreadsheet();  
var ss = SpreadsheetApp.openById("myGoogleSheetID");

1 个答案:

答案 0 :(得分:0)

由于在该线程中的单个消息中,标签可以在该线程中。您的代码只需进入 label->所有标签线程->所有线程消息,而不是仅访问具有给定标签的线程中的消息。那不是你的错,这是Gmail服务的局限性。您可以使用两种方法来纠正此行为:

(启用前"advanced service")Gmail REST API

REST API支持使用Gmail.Users.Messages.listlabelIds可选参数对消息进行详细的查询,包括每个消息的标签状态。例如:

// Get all messages (not threads) with this label:
function getMessageIdsWithLabel_(labelClass) {
  const labelId = labelClass.getId();
  const options = {
    labelIds: [ labelId ],
    // Only retrieve the id metadata from each message.
    fields: "nextPageToken,messages/id"
  };
  const messages = [];

  // Could be multiple pages of results.
  do {
    var search = Gmail.Users.Messages.list("me", options);
    if (search.messages && search.messages.length)
      Array.prototype.push.apply(messages, search.messages); 
    options.pageToken = search.nextPageToken;
  } while (options.pageToken);

  // Return an array of the messages' ids.
  return messages.map(function (m) { return m.id; });
}

使用REST API后,您可能会使用其他方法,例如批消息标签调整:

function removeLabelFromMessages_(messageIds, labelClass) {
  const labelId = labelClass.getId();
  const resource = {
    ids: messageIds,
    // addLabelIds: [ ... ],
    removeLabelIds: [ labelId ]
  };
  // https://developers.google.com/gmail/api/v1/reference/users/messages/batchModify
  Gmail.Users.Messages.batchModify(resource, "me");
}

结果:

function foo() {
  const myLabel = /* get the Label somehow */;
  const ids = getMessageIdsWithLabel_(myLabel);
  ids.forEach(function (messageId) {
    var msg = GmailApp.getMessageById(messageId);
    /* do stuff with the message */
  });
  removeLabelFromMessages_(ids, myLabel);
}

推荐读物:

跟踪处理

您还可以将每个消息ID存储在某个地方,并使用存储的ID检查您是否已经处理了给定消息。消息ID是唯一的。

此示例使用本机JavaScript对象进行超快速查找(相对于将ID仅存储在数组中并需要使用Array#indexOf)。为了维护脚本执行之间的已处理ID,它在活动工作簿或您选择的工作簿上使用工作表:

var MSG_HIST_NAME = "___processedMessages";
function getProcessedMessages(wb) {
  // Read from a sheet on the given spreadsheet.
  if (!wb) wb = SpreadsheetApp.getActive();
  const sheet = wb.getSheetByName(MSG_HIST_NAME)
  if (!sheet) {
    try { wb.insertSheet(MSG_HIST_NAME).hideSheet(); }
    catch (e) { }
    // By definition, no processed messages.
    return {};
  }
  const vals = sheet.getSheetValues(1, 1, sheet.getLastRow(), 1);
  return vals.reduce(function (acc, row) {
    // acc is our "accumulator", and row is an array with a single message id.
    acc[ row[0] ] = true;
    return acc;
  }, {});
}
function setProcessedMessages(msgObject, wb) {
  if (!wb) wb = SpreadsheetApp.getActive();
  if (!msgObject) return;
  var sheet = wb.getSheetByName(MSG_HIST_NAME);
  if (!sheet) {
    sheet = wb.insertSheet(MSG_HIST_NAME);
    if (!sheet)
      throw new Error("Unable to make sheet for storing data");
    try { sheet.hideSheet(); }
    catch (e) { }
  }

  // Convert the object into a serializable 2D array. Assumes we only care
  // about the keys of the object, and not the values.
  const data = Object.keys(msgObject).map(function (msgId) { return [msgId]; });
  if (data.length) {
    sheet.getDataRange().clearContent();
    SpreadsheetApp.flush();
    sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
  }
}

用法类似于:

function foo() {
  const myLabel = /* get label somehow */;
  const processed = getProcessedMessages();
  myLabel.getThreads().forEach(function (thread) {
    thread.getMessages().forEach(function (msg) {
      var msgId = msg.getId();
      if (processed[msgId])
        return; // nothing to do for this message.
      processed[msgId] = true;
      // do stuff with this message
    });
    // do more stuff with the thread
  });
  setProcessedMessages(processed);
  // do other stuff
}

推荐读物: