【问题标题】:Google Apps Script - Label Email Based On Email Body [Optimize Code]Google Apps 脚本 - 基于电子邮件正文的标签电子邮件 [优化代码]
【发布时间】:2018-10-21 08:41:59
【问题描述】:

我的目标是:

  • 收到一封符合放置在标签 A 文件夹中的条件的电子邮件。
  • 收到一封新电子邮件。
  • 这封新电子邮件的正文与收到的第一封电子邮件相同。
  • 这封新电子邮件会跳过收件箱并转到标签 B 文件夹。

这是我的实现方式:

  • 所有新电子邮件都标记为“原始”
  • 脚本运行时,会将电子邮件正文与之前的所有正文进行比较。
  • 如果正文是重复的,则将其标记为“重复”,移至“存档”,并删除“原始”标签。

代码如下:

function emailLabeling() {


var DUPLICATE = _getLabel();
  var labels = GmailApp.getUserLabelByName("Original");
  if(labels != null){
    var threads = labels.getThreads();
    for (var i = 0; i < threads.length; i++){
      var messages = threads[i].getMessages();
      for (var j = 0; j < messages.length; j++){
        var message = messages[j];
        for (var k = i; k < threads.length; k++){
        var messages_check = threads[k].getMessages();
          for (var l = j; l < messages_check.length; l++){
            var message_check = messages_check[l];
            if(message_check.getPlainBody() == message.getPlainBody()){
              if(i !=  k || j != l){
                Logger.log(i +""+ j +""+ k +""+ l);
                DUPLICATE.addToThread(threads[i]);
                labels.removeFromThread(threads[i]);
                GmailApp.moveThreadToArchive(threads[i]);
              }
            }
          }
        }
      }
    }
  }
  else{
    Logger.log("Label Not Found!");
  }
}

function _getLabel() {
  var label_text = "Duplicates";
  var label = GmailApp.getUserLabelByName(label_text);
  if (label == null) {
    var label = GmailApp.createLabel(label_text);
  }
  return label;
}

代码运行良好。问题在于 4 个嵌套循环,随着“原始”电子邮件数量的增加,运行时间呈指数增长。

有没有办法优化这段代码? 是否有更聪明的逻辑来实现这个想法?

任何帮助将不胜感激。

【问题讨论】:

  • 请注意,即使在您开始查看新线程后,您仍会在该线程中的 jth 消息之后继续启动 message_checks,而不是 0。这意味着您正在跳过电子邮件检查。此外,当你发现一个重复的身体时,你会做什么并不很清楚 - 我会保留早期的线程 - i - 在标签中并将后面的线程 - k - 移动到 "duplicate" 标签(您必须以某种方式检查标签是否仍然存在于非零i)。
  • 你是对的,它应该从 0 开始。目的是移动最新的线程。我猜这段代码有问题。 :|

标签: for-loop google-apps-script gmail-api


【解决方案1】:

在嵌套循环情况下(尤其是重复识别)提高性能的一种方法是存储遍历内容的记录,而不是重复比较。例如,您可以hash 消息正文(给定正确的散列函数)并将散列存储为对象属性。请注意,没有formal limit on the length of an object property,因此您可以自己跳过散列(以获得固定长度的属性),让 Google Apps 脚本为您完成。自然,在生产中使用这样的假设之前测试消息的大小可能是明智的。

function updateEmailLabels() {
  // Use an Object to associate a message's plaintext body with the
  // associated thread/message IDs (or other data as desired).
  var seenBodies = {}, // When a message is read, its plaintext body is stored.
      DUPLICATE = _getLabel("SO_Duplicates"),
      ORIGINAL = _getLabel("SO_Original");

  // getThreads() returns newest first. Start with the oldest by reversing it.
  ORIGINAL.getThreads().reverse().forEach(function (thread) {
    thread.getMessages().forEach(function (message, messageIndex) {
      // Use this message's body for fast lookups.
      // Assumption: Apps Script has no reachable limit on Object property length.
      var body = message.getPlainBody();

      // Compare this message to all previously seen messages:
      if (!seenBodies[body]) {
        seenBodies[body] = {
          count: 1,
          msgIndices: [ messageIndex ],
          threads: [ thread ],
          threadIds: [ thread.getId() ]
        };
      } else {
        // This exact message body has been observed previously.
        // Update information about where the body has been seen (or perform
        // more intricate checks, i.e. compare threadIds and message indices,
        // before treating this thread and message as a duplicate).
        seenBodies[body].count += 1;
        seenBodies[body].msgIndices.push(messageIndex);
        seenBodies[body].threads.push(thread);
        seenBodies[body].threadIds.push(thread.getId());
      }
    }); // End for-each-message. 
  }); // End for-each-thread.

  // All messages in all threads have now been read and checked against each other.
  // Determine the unique threads to be modified.
  var threadsToChange = {};
  for (var body in seenBodies) {
    if (seenBodies[body].count === 1)
      continue;
    var data = seenBodies[body];
    for (var threadIndex = 1; threadIndex < data.threads.length; ++threadIndex)
      threadsToChange[data.threadIds[threadIndex]] = data.threads[threadIndex];
  }
  // Update their labels and archive status.
  for (var id in threadsToChange) {
    var thread = threadsToChange[id];
    DUPLICATE.addToThread(thread);
    ORIGINAL.removeFromThread(thread);
    GmailApp.moveThreadToArchive(thread);
  }
}

function _getLabel(labelText) {
  var label = GmailApp.getUserLabelByName(labelText);
  return label ? label : GmailApp.createLabel(labelText);
}

您肯定会想要调整重复检测位,因为我没有完全符合条件的电子邮件只是放在周围;)我怀疑如果至少有 2 条消息相同,我所写的内容会将线程分类为重复,即使该线程是具有该特定消息正文的唯一线程。

【讨论】:

    猜你喜欢
    • 2017-02-04
    • 2014-08-05
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2020-12-15
    • 2021-06-08
    相关资源
    最近更新 更多