【问题标题】:Getting draft body on Gmail Addon在 Gmail Addon 上获取草稿正文
【发布时间】:2020-10-05 22:28:52
【问题描述】:

我有一个与Question 类似的问题,并且该主题错误已解决,但我需要从用户正在编写的消息中获取“Body”以及“messageId”。

我有一个 contextualTrigger,但它没有登录 STACKDRIVER

function onGmailMessageOpen(e) {
  console.log(e);
  
  // Get the ID of the message the user has open.
  var messageId = e.gmail.messageId;
}
"gmail": {
      "contextualTriggers": [
        {
          "unconditional": {},
          "onTriggerFunction": "onGmailMessageOpen"
        }
      ],

有没有办法获取当前正在撰写的消息的“body”和“messageId”,无论是新草稿还是回复,或者这是插件的限制?

【问题讨论】:

    标签: google-apps-script triggers gmail add-on


    【解决方案1】:

    TL;DR

    1. 您将两个不同的触发器合二为一。
    2. 撰写 UI 事件对象没有 body 字段。
    3. 撰写 UI 事件对象不应有 subject 字段(但有)。

    这不是错误

    这种行为是在撰写 UI 的上下文中触发的触发器的事件对象应该如何工作。在文档中,没有提到 subjectbody 字段(尽管 subject 现在可用事实上,可能是由于您引用的问答中提到的功能请求)。

    事件对象结构

    目前gmail资源只能有the following properties

    | Property      | Type     | Always present?     |
    | ------------- | -------- | ------------------- |
    | accessToken   | string   | Yes                 |
    | bccRecipients | string[] | disabled by default |
    | ccRecipients  | string[] | disabled by default |
    | messageId     | string   | Yes                 |
    | threadId      | string   | Yes                 |
    | toRecipients  | string[] | disabled by default |
    

    但是,此事件对象结构特定于消息 UI,并未在撰写 UI 上下文中完整构造。

    编写 UI 事件对象

    composeTrigger 清单字段中指定的撰写 UI 触发器无权访问打开的消息元数据。鉴于存在 METADATA 范围,the event object 看起来像这样(如果 subject 为空,它将从资源中丢失):

    {
      commonEventObject: {
        platform: 'WEB',
        hostApp: 'GMAIL'
      },
      gmail: {
        subject: '12345'
      },
      clientPlatform: 'web',
      draftMetadata: {
        toRecipients: [],
        subject: '12345',
        bccRecipients: [],
        ccRecipients: []
      },
      hostApp: 'gmail'
    }
    

    现在,尝试构建一个 Card 并向其添加一个可操作的小部件(即 TextButton):

    const onComposeAction = (e) => {
        const builder = CardService.newCardBuilder();
    
        const section = CardService.newCardSection();
    
        const action = CardService.newAction();
        action.setFunctionName("handleButtonClick"); //<-- callback name to test event object;
        
        const widget = CardService.newTextButton();
        widget.setText("Test Event Object");
        widget.setOnClickAction(action);
    
        section.addWidget(widget);
    
        builder.addSection(section);
    
        return builder.build();
    };
    

    触发动作后,如果您记录事件对象,您会看到它看起来与前一个非常相似,并附加了动作事件对象属性:

    {
      hostApp: 'gmail',
      formInputs: {}, //<-- multi-value inputs
      formInput: {}, //<-- single-value inputs
      draftMetadata: {
        subject: '12345',
        ccRecipients: [],
        toRecipients: [],
        bccRecipients: []
      },
      gmail: {
        subject: '12345'
      },
      parameters: {}, //<-- parameters passed to builder
      clientPlatform: 'web',
      commonEventObject: {
        hostApp: 'GMAIL',
        platform: 'WEB'
      }
    }
    

    请注意缺少 accessTokenthreadIdmessageId 属性 - 触发器在当前打开的草稿而不是打开的电子邮件的上下文中触发。

    消息 UI 事件对象

    相反,消息 UI 事件对象(响应以阅读模式打开电子邮件并传递给onTriggerFunction manifest 属性中指定的函数的对象)确实包含必要的元数据:

    {
      messageMetadata: {
        accessToken: 'token here',
        threadId: 'thread id here',
        messageId: 'message id here'
      },
      clientPlatform: 'web',
      gmail: {
        messageId: 'message id here',
        threadId: 'thread id here',
        accessToken: 'token here'
      },
      commonEventObject: {
        platform: 'WEB',
        hostApp: 'GMAIL'
      },
      hostApp: 'gmail'
    }
    

    解决方法

    一个可行的解决方法是使用getDraftMessages 方法并提取第一个匹配的草稿(合理地假设同时没有创建草稿的完整副本)。这种实用程序的一个示例是:

    const listDraftGmailMessages = ({
        subject,
        toRecipients: to,
        ccRecipients: cc,
        bccRecipients: bcc
    } = {}) => {
    
        const drafts = GmailApp.getDraftMessages();
    
        return drafts.filter((draft) => {
            const s = draft.getSubject();
            const t = draft.getTo().split(",");
            const c = draft.getCc().split(",");
            const b = draft.getBcc().split(",");
    
            const sameSubj = subject ? s === subject : true;
            const sameTo = to ? t.every(r => to.includes(trimFrom(r))) : true;
            const sameCc = cc ? c.every(r => cc.includes(trimFrom(r))) : true;
            const sameBcc = bcc ? b.every(r => bcc.includes(trimFrom(r))) : true;
    
            return sameSubj && sameTo && sameCc && sameBcc;
        });
    };
    

    注意getTogetCcgetBcc都是name &lt;email&gt;形式的返回接收者,所以要修剪。一个“足够好”的实用程序 trimFrom 应该可以解决问题:

    const trimFrom = (input) => {
        try {
            const regex = /<([-\w.]+@\w+(?:\.\w+)+)>/i;
            const [, email] = input.match(regex) || [input];
            return email || input;
        } catch (error) {
            console.warn(error);
            return input;
        }
    };
    

    提取第一个匹配草稿后,您可以随意处理(在您的情况下,使用getBody 方法)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-26
      • 2016-02-01
      • 2014-08-19
      • 2019-02-28
      • 2018-02-20
      • 2012-09-07
      • 1970-01-01
      相关资源
      最近更新 更多