使用 Compose 操作扩展 Compose 界面

除了在用户阅读 Gmail 邮件时提供基于卡片的界面之外,扩展 Gmail 的 Google Workspace 插件还可以在用户撰写新邮件或回复现有邮件时提供另一个界面。这样,插件就可以自动执行为用户撰写电子邮件的任务。

访问 Google Workspace 插件撰写界面

您可以通过两种方式查看插件的撰写界面。第一种方式是在插件已打开的情况下开始撰写新草稿或回复。第二种方式是在撰写草稿时启动插件。

无论哪种情况,都会导致插件执行相应的 撰写触发器函数,该函数在插件 清单中定义。撰写触发器函数会为该撰写操作构建撰写界面,然后 Gmail 会向用户显示该界面。

构建撰写插件

您可以按照以下一般步骤为插件添加撰写功能:

  1. gmail.composeTrigger 字段添加到插件脚本项目 清单 ,并更新清单 范围以包含 撰写操作所需的范围。
  2. 实现一个撰写触发器函数,该函数会在触发器触发时构建撰写界面。撰写触发器函数会返回单个 Card对象或 Card对象数组,这些对象会构成撰写操作的撰写界面。
  3. 实现与用户撰写界面互动所需的关联回调函数。这些函数不是撰写操作本身(仅导致撰写界面显示),而是控制在选择撰写界面的不同元素时发生的情况的各个函数。例如,包含按钮的界面卡片通常具有关联的回调函数,该函数会在用户点击该按钮时执行。用于更新草稿邮件 内容的微件的回调函数应返回 UpdateDraftActionResponse 对象。

撰写触发器函数

插件的撰写界面的构建方式与 插件的消息界面相同,都是使用 Apps 脚本 卡片服务来构建 卡片并 使用 微件填充卡片。

您必须实现您在清单中定义的 gmail.composeTrigger.selectActions[].runFunction 。撰写触发器函数必须返回 单个 Card 对象或 Card 对象数组 ,这些对象会构成该操作的撰写界面。这些函数与上下文触发器函数非常相似,应以相同的方式构建卡片。

撰写触发器事件对象

选择撰写操作后,系统会执行相应的撰写触发器 函数,并将事件对象 作为参数传递给该函数。事件对象可以将有关插件上下文和正在撰写的草稿的信息传递给触发器函数。

如需详细了解如何在事件对象中排列信息,请参阅事件对象结构 。事件对象中包含的信息 部分由 gmail.composeTrigger.draftAccess 清单字段的值控制:

  • 如果 gmail.composeTrigger.draftAccess 清单字段为 NONE 或未包含,则事件对象仅包含 最少的信息。

  • 如果 gmail.composeTrigger.draftAccess 设置为 METADATA,则传递给撰写触发器函数的事件对象 会填充正在撰写的电子邮件的收件人列表。使用 METADATA草稿访问权限要求 插件清单包含 https://www.googleapis.com/auth/gmail.addons.current.message.metadata Gmail 范围

将内容插入到活动草稿中

通常,插件撰写界面会为用户提供有助于撰写邮件的选项和控件。对于这些用例,用户在界面中做出选择后,插件会解读这些选择并相应地更新当前正在处理的电子邮件草稿。

为了更轻松地更新当前草稿电子邮件,卡片服务 已使用以下类进行了扩展:

通常,插件撰写界面会包含“保存”或“插入”微件,用户可以点击这些微件来表明他们已在界面中完成选择,并希望将所选内容添加到正在撰写的电子邮件中。如需添加此 互动功能, 微件应具有关联的 Action 对象,该对象会指示 插件在点击 微件时运行特定的回调函数。您必须实现这些回调函数。每个回调函数都应返回一个已构建的 UpdateDraftActionResponse 对象,该对象详细说明了要对当前草稿电子邮件进行的更改。

示例 1

以下代码段展示了如何构建一个撰写界面,该界面会更新当前电子邮件草稿的主题以及“收件人”“抄送”和“密送”收件人。

/**
 * Compose trigger function that fires when the compose UI is
 * requested. Builds and returns a compose UI for inserting images.
 *
 * @param {event} e The compose trigger event object. Not used in
 *         this example.
 * @return {Card[]}
 */
function getComposeUI(e) {
  return [buildComposeCard()];
}

/**
 * Build a card to display interactive buttons to allow the user to
 * update the subject, and To, Cc, Bcc recipients.
 *
 * @return {Card}
 */
function buildComposeCard() {

  var card = CardService.newCardBuilder();
  var cardSection = CardService.newCardSection().setHeader('Update email');
  cardSection.addWidget(
      CardService.newTextButton()
          .setText('Update subject')
          .setOnClickAction(CardService.newAction()
              .setFunctionName('applyUpdateSubjectAction')));
  cardSection.addWidget(
      CardService.newTextButton()
          .setText('Update To recipients')
          .setOnClickAction(CardService.newAction()
              .setFunctionName('updateToRecipients')));
  cardSection.addWidget(
      CardService.newTextButton()
          .setText('Update Cc recipients')
          .setOnClickAction(CardService.newAction()
              .setFunctionName('updateCcRecipients')));
  cardSection.addWidget(
      CardService.newTextButton()
          .setText('Update Bcc recipients')
          .setOnClickAction(CardService.newAction()
              .setFunctionName('updateBccRecipients')));
  return card.addSection(cardSection).build();
}

/**
 * Updates the subject field of the current email when the user clicks
 * on "Update subject" in the compose UI.
 *
 * Note: This is not the compose action that builds a compose UI, but
 * rather an action taken when the user interacts with the compose UI.
 *
 * @return {UpdateDraftActionResponse}
 */
function applyUpdateSubjectAction() {
  // Get the new subject field of the email.
  // This function is not shown in this example.
  var subject = getSubject();
  var response = CardService.newUpdateDraftActionResponseBuilder()
      .setUpdateDraftSubjectAction(CardService.newUpdateDraftSubjectAction()
          .addUpdateSubject(subject))
      .build();
  return response;
}

/**
 * Updates the To recipients of the current email when the user clicks
 * on "Update To recipients" in the compose UI.
 *
 * Note: This is not the compose action that builds a compose UI, but
 * rather an action taken when the user interacts with the compose UI.
 *
 * @return {UpdateDraftActionResponse}
 */
function applyUpdateToRecipientsAction() {
  // Get the new To recipients of the email.
  // This function is not shown in this example.
  var toRecipients = getToRecipients();
  var response = CardService.newUpdateDraftActionResponseBuilder()
      .setUpdateDraftToRecipientsAction(CardService.newUpdateDraftToRecipientsAction()
          .addUpdateToRecipients(toRecipients))
      .build();
  return response;
}

/**
 * Updates the Cc recipients  of the current email when the user clicks
 * on "Update Cc recipients" in the compose UI.
 *
 * Note: This is not the compose action that builds a compose UI, but
 * rather an action taken when the user interacts with the compose UI.
 *
 * @return {UpdateDraftActionResponse}
 */
function applyUpdateCcRecipientsAction() {
  // Get the new Cc recipients of the email.
  // This function is not shown in this example.
  var ccRecipients = getCcRecipients();
  var response = CardService.newUpdateDraftActionResponseBuilder()
      .setUpdateDraftCcRecipientsAction(CardService.newUpdateDraftCcRecipientsAction()
          .addUpdateToRecipients(ccRecipients))
      .build();
  return response;
}

/**
 * Updates the Bcc recipients  of the current email when the user clicks
 * on "Update Bcc recipients" in the compose UI.
 *
 * Note: This is not the compose action that builds a compose UI, but
 * rather an action taken when the user interacts with the compose UI.
 *
 * @return {UpdateDraftActionResponse}
 */
function applyUpdateBccRecipientsAction() {
  // Get the new Bcc recipients of the email.
  // This function is not shown in this example.
  var bccRecipients = getBccRecipients();
  var response = CardService.newUpdateDraftActionResponseBuilder()
      .setUpdateDraftBccRecipientsAction(CardService.newUpdateDraftBccRecipientsAction()
          .addUpdateToRecipients(bccRecipients))
      .build();
  return response;
}

示例 2

以下代码段展示了如何构建一个撰写界面,该界面会将图片插入到当前草稿电子邮件中。

/**
 * Compose trigger function that fires when the compose UI is
 * requested. Builds and returns a compose UI for inserting images.
 *
 * @param {event} e The compose trigger event object. Not used in
 *         this example.
 * @return {Card[]}
 */
function getInsertImageComposeUI(e) {
  return [buildImageComposeCard()];
}

/**
 * Build a card to display images from a third-party source.
 *
 * @return {Card}
 */
function buildImageComposeCard() {
  // Get a short list of image URLs to display in the UI.
  // This function is not shown in this example.
  var imageUrls = getImageUrls();

  var card = CardService.newCardBuilder();
  var cardSection = CardService.newCardSection().setHeader('My Images');
  for (var i = 0; i < imageUrls.length; i++) {
    var imageUrl = imageUrls[i];
    cardSection.addWidget(
        CardService.newImage()
            .setImageUrl(imageUrl)
            .setOnClickAction(CardService.newAction()
                  .setFunctionName('applyInsertImageAction')
                  .setParameters({'url' : imageUrl})));
  }
  return card.addSection(cardSection).build();
}

/**
 * Adds an image to the current draft email when the image is clicked
 * in the compose UI. The image is inserted at the current cursor
 * location. If any content of the email draft is currently selected,
 * it is deleted and replaced with the image.
 *
 * Note: This is not the compose action that builds a compose UI, but
 * rather an action taken when the user interacts with the compose UI.
 *
 * @param {event} e The incoming event object.
 * @return {UpdateDraftActionResponse}
 */
function applyInsertImageAction(e) {
  var imageUrl = e.parameters.url;
  var imageHtmlContent = '<img style=\"display: block\" src=\"'
        + imageUrl + '\"/>';
  var response = CardService.newUpdateDraftActionResponseBuilder()
      .setUpdateDraftBodyAction(CardService.newUpdateDraftBodyAction()
          .addUpdateContent(
              imageHtmlContent,
              CardService.ContentType.MUTABLE_HTML)
          .setUpdateType(
              CardService.UpdateDraftBodyType.IN_PLACE_INSERT))
      .build();
  return response;
}