GmailApp - 为特定邮件添加标签,而不是线程

时间:2015-06-12 08:22:01

标签: javascript google-apps-script gmail gmail-api

我正在构建一个脚本,以便每天自动将我的电子邮件从一个标签移动到下一个标签(以便标记为“5天”的邮件将自动标记为“4天”,然后“ 3天“之后的第二天,等等。”

问题在于它将标签应用于整个线程,而不仅仅是消息 - 如果您关闭了“对话视图”并且各种电子邮件在不同的标签下分开,则会出现问题。

这是我的脚本(每日触发):

function moveUp(previousLabel, newLabel) {
  var threads = GmailApp.getUserLabelByName(previousLabel).getThreads()
  var numThreads = threads.length
  if (numThreads>0) {
    for(var i = 0; i < numThreads; i++) {

      if(GmailApp.getUserLabelByName(previousLabel).getThreads().length>0) {
        var lastThread = GmailApp.getUserLabelByName(previousLabel).getThreads()[0]
        GmailApp.getUserLabelByName(newLabel).addToThread(lastThread.markUnread());
        GmailApp.getUserLabelByName(previousLabel).removeFromThread(lastThread)
        Utilities.sleep(200)
      } else {
        {break;}
      }
    }
  }
}

function myFunction() {
  var threads = GmailApp.getUserLabelByName("-To Do/1 Day").getThreads()
  var numThreads = threads.length
  if (numThreads>0) {
    for(var i = 0; i < numThreads; i++) {

      if(GmailApp.getUserLabelByName("-To Do/1 Day").getThreads().length>0) {
        var lastThread = GmailApp.getUserLabelByName("-To Do/1 Day").getThreads()[0]
        lastThread.moveToInbox().markUnread();
        GmailApp.getUserLabelByName("-To Do/1 Day").removeFromThread(lastThread)
        Utilities.sleep(200)
      } else {
        {break;}
      }
    }
  }
    moveUp("-To Do/2 Days", "-To Do/1 Day")
    moveUp("-To Do/3 Days", "-To Do/2 Days")
    moveUp("-To Do/4 Days", "-To Do/3 Days")
    moveUp("-To Do/5 Days", "-To Do/4 Days")
}

所以有人知道如何仅将标签应用于特定消息吗?或者解决方法来实现相同的结果?

由于

2 个答案:

答案 0 :(得分:7)

您可以使用GMail API代替此操作。您需要为项目启用API。在编辑器中,选择Resources > Advanced Google services,然后点击“还必须在 Google Developers Console 中启用这些服务”。在那里,启用GMail API。

modifyMessage

使用示例:

modifyMessage('me', messageId, ['stack','overflow']);       // add two labels
modifyMessage('me', messageId, null, ['stack','overflow']); // remove two labels

TL; DR 完整代码可用in this gist,下方隐藏在代码段中。

/**
 * Modify the Labels a Message is associated with.
 * Throws if unsuccessful.
 * see https://developers.google.com/gmail/api/v1/reference/users/messages/modify
 *
 * @param  {String} userId           User's email address. The special value 'me'
 *                                   can be used to indicate the authenticated user.
 * @param  {String} messageId        ID of Message to modify.
 * @param  {String[]} labelsToAdd    Array of Label names to add.
 * @param  {String[]} labelsToRemove Array of Label names to remove.
 *
 * @returns {Object}                 Users.messages resource, see reference. 
 */
function modifyMessage(userId, messageId, labelsToAdd, labelsToRemove) {
  labelsToAdd = labelsToAdd || [];
  labelsToRemove = labelsToRemove || [];
  // see https://developers.google.com/gmail/api/v1/reference/users/messages/modify
  var url = 'https://www.googleapis.com/gmail/v1/users/${userId}/messages/${id}/modify'
            .replace("${userId}","me")
            .replace("${id}", messageId );
  var headers = {
    Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
  };
  var addLabelIds = [];
  for (var i=0; i<labelsToAdd.length; i++) {
    addLabelIds[i] = getLabelId( labelsToAdd[i] );
  }
  var removeLabelIds = [];
  for (var i=0; i<labelsToRemove.length; i++) {
    removeLabelIds[i] = getLabelId( labelsToRemove[i], false );
  }
  var request = {
    'addLabelIds': addLabelIds,
    'removeLabelIds': removeLabelIds
  };
  var params = {
    method: "post",
    contentType: "application/json",
    headers: headers,
    payload: JSON.stringify(request),
    muteHttpExceptions: true
  };
  //var check = UrlFetchApp.getRequest(url, params); // for debugging
  var response = UrlFetchApp.fetch(url, params);

  var result = response.getResponseCode();
  if (result == '200') {  // OK
    return JSON.parse(response.getContentText());
  }
  else {
    // This is only needed when muteHttpExceptions == true
    var err = JSON.parse(response.getContentText());
    throw new Error( 'Error (' + result + ") " + err.error.message );
  }
}

/**
 * Get the Label ID for the given LabelName. If Label isn't found, it will be created
 * depending on the state of ok2Create.
 * Throws if unsuccessful.
 * See https://developers.google.com/gmail/api/v1/reference/users/messages/modify.
 *
 * @param {String}   labelName        Name of label to retrieve ID for.
 * @param {Boolean}  ok2Create        (optional) Set true if a label should be created when not found.
 *                                    Default is true.
 *
 * @returns {String}                  ID of Label, or null if not found or created.
 */
function getLabelId( labelName, ok2Create ) {
  if (typeof ok2Create == 'undefined') ok2Create = true;
  
  var id = null;
  // see https://developers.google.com/gmail/api/v1/reference/users/labels/list
  var url = 'https://www.googleapis.com/gmail/v1/users/${userId}/labels'
            .replace("${userId}","me")  // The user's email address. The special value me can be used to indicate the authenticated user.
  var headers = {
    Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
  };
  var params = {
    method: "get",
    contentType: "application/json",
    headers: headers,
    muteHttpExceptions: true
  };
  
  //var check = UrlFetchApp.getRequest(url, params); // for debugging
  var response = UrlFetchApp.fetch(url, params);

  var result = response.getResponseCode();
  if (result == '200') {  // OK
    var labels = JSON.parse(response.getContentText()).labels;
    var found = false;
    for (var i=0; i<labels.length & !found; i++) {
      if (labels[i].name == labelName) {
        found = true;
        id = labels[i].id;
      }
    }
    if (!found && ok2Create) {
      id = createLabel( labelName );
    }
    return id;
  }
  else {
    // This is only needed when muteHttpExceptions == true
    var err = JSON.parse(response.getContentText());
    throw new Error( 'Error (' + result + ") " + err.error.message );
  }
}

/**
 * Create Label for given `labelName`.
 * Throws if unsuccessful.
 * See https://developers.google.com/gmail/api/v1/reference/users/messages/modify.
 *
 * @param {String}   labelName        Name of label to create
 *
 * @returns {String}                  ID of Label.
 */
function createLabel( labelName ) {
  var id = null;
  // see https://developers.google.com/gmail/api/v1/reference/users/labels/create
  var url = 'https://www.googleapis.com/gmail/v1/users/${userId}/labels'
            .replace("${userId}","me")  // The user's email address. The special value me can be used to indicate the authenticated user.
  var headers = {
    Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
  };
  var request = {
    'name': labelName
  };
  var params = {
    method: "post",
    contentType: "application/json",
    headers: headers,
    payload: JSON.stringify(request),
    muteHttpExceptions: true
  };
  
  //var check = UrlFetchApp.getRequest(url, params); // for debugging
  var response = UrlFetchApp.fetch(url, params);

  var result = response.getResponseCode();
  if (result == '200') {  // OK
    var label = JSON.parse(response.getContentText());
    id = label.id;
    return id;
  }
  else {
    // This is only needed when muteHttpExceptions == true
    var err = JSON.parse(response.getContentText());
    throw new Error( 'Error (' + result + ") " + err.error.message );
  }
}

/**
 * Modify the Labels a Message is associated with.
 * Throws if unsuccessful.
 * see https://developers.google.com/gmail/api/v1/reference/users/messages/modify
 *
 * @param  {String} userId           User's email address. The special value 'me'
 *                                   can be used to indicate the authenticated user.
 * @param  {String} messageId        ID of Message to modify.
 * @param  {String[]} labelsToAdd    Array of Label names to add.
 * @param  {String[]} labelsToRemove Array of Label names to remove.
 *
 * @returns {Object}                 Users.messages resource, see reference. 
 */
function modifyMessage(userId, messageId, labelsToAdd, labelsToRemove) {
  labelsToAdd = labelsToAdd || [];
  labelsToRemove = labelsToRemove || [];
  // see https://developers.google.com/gmail/api/v1/reference/users/messages/modify
  var url = 'https://www.googleapis.com/gmail/v1/users/${userId}/messages/${id}/modify'
            .replace("${userId}","me")
            .replace("${id}", messageId );

GMail API是一个RESTful API,与使用内置GMailApp服务提供的内容相比,可以更灵活,更详细地访问线程,消息,标签,草稿和历史记录。在我们的脚本中,我们通过URL访问API - 在这里,我们首先在modify消息方法的基本URL中填写详细信息。

  var headers = {
    Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
  };

除了为我们的项目启用API之外,每个请求都需要用户身份验证,这可以通过在命令头中嵌入Bearer Token来完成。

接下来,我们将构建其余的命令参数。

  var addLabelIds = [];
  for (var i=0; i<labelsToAdd.length; i++) {
    addLabelIds[i] = getLabelId( labelsToAdd[i] );
  }
  var removeLabelIds = [];
  for (i=0; i<labelsToRemove.length; i++) {
    removeLabelIds[i] = getLabelId( labelsToRemove[i], false );
  }
  var request = {
    'addLabelIds': addLabelIds,
    'removeLabelIds': removeLabelIds
  };

modify的规范调用POST操作,其中有效负载包含标签ID列表。这些ID不能通过内置的GMail服务获得,因此我们也将使用GMail API - getLabelId()是另一个类似于此的功能,专门用于按名称检索标签的ID,并创建根据需要新标签。请参阅该代码的要点或摘要。

  var params = {
    method: "post",
    contentType: "application/json",
    headers: headers,
    payload: JSON.stringify(request),
    muteHttpExceptions: true
  };
  //var check = UrlFetchApp.getRequest(url, params); // for debugging
  var response = UrlFetchApp.fetch(url, params);

最后,我们为命令组装了params对象,其中包含带有我们身份验证令牌的headers的属性,以及带有命令参数payload的{​​{1}} - d用于运输。设置stringify会在发生故障时压制系统生成的异常,以便我们自己处理它们。

我已经注释了对muteHttpExceptions: true的调用 - 在发送命令之前验证命令的内容非常方便。

UrlFetchApp.getRequest()的调用将我们的命令发送到我们在顶层建立的URL上运行的服务。

UrlFetchApp.fetch()

收到回复后,我们首先检查命令的 var result = response.getResponseCode(); if (result == '200') { // OK return JSON.parse(response.getContentText()); } ,其形式为HTTP Status Coderesult告诉我们我们成功了,所以我们继续将结果从响应中拉出来。 200 OK将邮件中的JSON string转换为JavaScript对象,然后返回给调用者。

JSON.parse()

但是,如果我们遇到错误,我们会抛出自己的异常。根据命令的详细信息,我们可能希望以不同方式处理特定错误。例如,在此 else { // This is only needed when muteHttpExceptions == true var err = JSON.parse(response.getContentText()); throw new Error( 'Error (' + result + ") " + err.error.message ); } } 命令中,如果我们提供不存在的标签ID,我们将收到错误:

  

错误:错误(400)标签无效:“无效标签”

答案 1 :(得分:0)

这是一个旧主题,但是对于像我这样阅读的任何人,也许这将为您节省一些时间。我喜欢@Mogsdad的答案,并从中学到了很多。但是,此版本使用高级Gmail服务(Google脚本中的完整GMail API),因此轻巧一些。

function getLabelMap() {
  var allLabels = Gmail.Users.Labels.list('me');
  var labelMap = [];

  for (var label of allLabels.labels) {
    labelMap[label.name] = label.id;
  }
  
  return labelMap;
}

var labelMap = getLabelMap();

function getLabel(labelName) {
  return labelMap[labelName];
}

function labelMessage(messageID, labelName) {
  var labelID = getLabel(labelName);
  var labelRequest = {addLabelIds: [labelID]};
  var subject = GmailApp.getMessageById(messageID).getSubject();

  if (labelID != null) {
    Logger.log("Labelling as %s: %s", labelName, subject);
    Gmail.Users.Messages.modify(labelRequest, 'me', messageID);
  } else {
    Logger.log("Label not found: %s", labelName);
  }
}

function unlabelMessage(messageID, labelName) {
  var labelID = getLabel(labelName);
  var labelRequest = {removeLabelIds: [labelID]};
  var subject = GmailApp.getMessageById(messageID).getSubject();

  if (labelID != null) {
    Logger.log("Removing label %s: %s", labelName, subject);
    Gmail.Users.Messages.modify(labelRequest, 'me', messageID);
  } else {
    Logger.log("Label not found: %s", labelName);
  }
}

function reLabel () {

  var messagesToRelabel = Gmail.Users.Messages.list('me', {'q':'label:Old-label'}).messages || []; // feel free to add date criteria using regular GMail keywords

  // Loop through each message (not by thread), using the Advanced Gmail Service (full GMail API in a Google Script).
  messagesToRelabel.forEach(function (messageToRelabel){
    unlabelMessage(messageToRelabel.id, "Old label");
    labelMessage(messageToRelabel.id, "New label");
  });

}

OP并没有要求,但可能对其他尝试使用GMail API进行“高级过滤/标记”的人有所帮助:

function getMessageHeader(messageID, headerField) {
  var messageInfo = Gmail.Users.Messages.get('me', messageID, {'format':'METADATA', 'metadataHeaders':[headerField]});

  if (messageInfo.payload.headers) {
    return messageInfo.payload.headers[0].value;
  } else {
    return null;
  }
}

以上内容可让您过滤标题信息,例如我用它来检查X-Uniform-Type-Identifier是否等于com.apple.mail-note以自动将旧的Apple Notes标记为删除。