使用已更改收件人的AppScript在Gmail中回复电子邮件后,会在一个新主题中结束

时间:2018-08-10 12:30:04

标签: javascript google-apps-script gmail

我的邮箱中有一封电子邮件,我希望AppScript程序仅由我和一个特殊的Google网上论坛作为收件人进行回复。这样做的目的是使程序与我通信,因为一旦程序处理了消息,并在答复正文中提供了有关处理的必要详细信息,便会对其进行答复。原始邮件中可能还会有其他收件人,但我不希望该程序将答复发送给他们。

所以我需要使用一组更改的收件人进行回复。当我在Gmail GUI中执行此操作时,它工作正常,我点击了回复,更改了收件人,发送了邮件,然后回复最终显示在原始线程中。但是,当我在脚本中执行此操作时,回复始终以新线程结尾。最初,我认为Gmail是根据电子邮件的主题决定的,但似乎还有很多(也许它最近有所更改,因为我认为它曾经以这种方式工作)。

我尝试了许多略有不同的方法,其中之一是:

var messageBody = "foo";
var newRecipients = "me@gmail.com, my-group@gmail.com";
var messageToReplyTo = ...;
var advancedParams = {from : "my-alias@gmail.com"};

var replyDraft = messageToReplyTo.createDraftReply(messageBody);
var replySubject = replyDraft.getMessage().getSubject();
var replyBody = replyDraft.getMessage().getBody();

replyDraft.update(newRecipients, replySubject, replyBody, advancedParams);

replyDraft.send();

1 个答案:

答案 0 :(得分:2)

要实现这一目标,您需要做一些有趣的事情,但是您可以轻松完成。您绝对应该阅读Drafts的指南。

Per the API spec:

  

要成为主题的一部分,消息或草稿必须满足以下条件:

     
      
  1. 所请求的threadId必须在您随请求提供的MessageDraft.Message上指定。
  2.   
  3. 参考 In-Reply-To 标头必须符合RFC 2822标准设置。
  4.   
  5. 主题标题必须匹配。
  6.   

要开始,您需要获得要更新的草稿的参考。使用GmailApp可能最简单:

const thread = /** get the thread somehow */;
const newBody = /** your plaintext here */;
const reply = thread.createDraftReply(newBody);

Gmail和草稿的主要问题是Draft是服务器资源的不变消息。如果您更改了其中的任何一个,则全部更改。因此,要更改标头值(例如收件人地址),您需要完全重建邮件。这就是使用GmailApp methods to update a draft无法维护现有线程信息的原因-您不能将其指定为构建新消息的高级选项之一。因此,您必须使用Gmail REST API来完成此任务:

const rawMsg = Gmail.Users.Drafts.get("me", reply.getId(), {format: "raw"}).message;

要更新草稿,您需要提供以base64编码的RFC 2822格式的消息。如果您愿意将格式丰富的消息部分转换为这样的有效字符串,则可以使用非原始格式,因为您可以直接访问message.payload中的标头。

要处理原始消息,请知道Apps脚本在上述调用中将描述的base64编码的字符串强制转换为字节数组。然后,将字节数组视为字符串字节,尤其是charCode s:

const msg_string = rawMsg.raw.reduce(function (acc, b) { return acc + String.fromCharCode(b); }, "");
console.log({message: "Converted byte[] to str", bytes: rawMsg.raw, str: msg_string});

将消息作为字符串发送后,可以使用正则表达式更新所需的标题:

const pattern = /^To: .+$/m;
var new_msg_string = msg_string.replace(pattern, "To: <....>");
// new_msg_string += ....

由于update a Draft的Gmail API端点要求使用base64网络安全编码的字符串,因此您可以计算得出:

const encoded_msg = Utilities.base64EncodeWebSafe(new_msg_string);

唯一剩下的就是执行呼叫(和/或send更新的草稿)。

const resource = {
  id: <draft id>, // e.g. reply.getId()
  message: {
    threadId: <thread id>, // e.g. thread.getId()
    raw: encoded_msg
  }
}
const resp = Gmail.Users.Drafts.update(resource, "me", reply.getId());
const sent_msg = Gmail.Users.Drafts.send({id: resp.id}, "me");
console.log({message: "Sent the draft", msg: sent_msg});

我并不是说从Byte属性返回的Message.raw数组的处理是100%正确的,只是它看起来是正确的,并且不会在测试消息中导致任何错误我发了。还有一种更简单的方法,因为Apps Script服务具有一个Drafts.update端点,该端点接受一个Blob输入,而我尚未研究如何使用它。