使用撰寫動作擴充 Compose UI

除了在使用者閱讀 Gmail 郵件時提供卡片式介面,擴充 Gmail 的 Google Workspace 外掛程式還能在使用者撰寫新郵件或回覆現有郵件時,提供其他介面。外掛程式可藉此自動為使用者撰寫電子郵件。

存取 Google Workspace 外掛程式撰寫 UI

你可以透過兩種方式查看外掛程式的撰寫 UI。第一種方式是先開啟外掛程式,然後開始撰寫新草稿或回覆郵件。第二種方式是在撰寫草稿時啟動外掛程式。

無論是哪一種情況,外掛程式都會執行對應的撰寫觸發函式,該函式定義於外掛程式資訊清單中。撰寫觸發函式會為該撰寫動作建構撰寫 UI,然後 Gmail 會向使用者顯示該 UI。

建立撰寫外掛程式

如要為外掛程式新增撰寫功能,請按照下列一般步驟操作:

  1. gmail.composeTrigger 欄位新增至外掛程式指令碼專案的資訊清單,並更新資訊清單範圍,加入撰寫動作所需的範圍。
  2. 實作 Compose 觸發函式,在觸發條件觸發時建構 Compose UI。Compose 觸發函式會傳回單一 Card 物件,或形成 Compose 動作 Compose UI 的 Card 物件陣列。
  3. 實作相關聯的回呼函式,以便對使用者的 Compose UI 互動做出反應。這些函式並非 Compose 動作本身 (只會導致 Compose UI 顯示),而是管理選取 Compose UI 不同元素時所發生情況的個別函式。舉例來說,含有按鈕的 UI 資訊卡通常會具備相關聯的回呼函式,使用者點選該按鈕時就會執行該函式。更新草稿訊息內容的小工具回呼函式應傳回 UpdateDraftActionResponse 物件。

撰寫觸發函式

外掛程式的 Compose UI 建構方式與外掛程式的訊息 UI 相同,都是使用 Apps Script Card 服務建構資訊卡,並在其中填入小工具

您必須實作在資訊清單中定義的 gmail.composeTrigger.selectActions[].runFunction。撰寫觸發函式必須傳回單一 Card 物件,或是構成該動作撰寫 UI 的 Card 物件陣列。這些函式與情境觸發函式非常相似,應以相同方式建構資訊卡。

編寫觸發事件物件

選取撰寫動作時,系統會執行對應的撰寫觸發函式,並將事件物件做為參數傳遞至函式。事件物件可將外掛程式環境和正在撰寫的草稿資訊,傳送至觸發函式。

如要瞭解事件物件中的資訊排列方式,請參閱「事件物件結構」。事件物件中包含的資訊部分由 gmail.composeTrigger.draftAccess 資訊清單欄位的值控制:

  • 如果 gmail.composeTrigger.draftAccess 資訊清單欄位為 NONE 或未納入,事件物件就只會包含最少的資訊。

  • 如果 gmail.composeTrigger.draftAccess 設為 METADATA,傳遞至撰寫觸發函式的事件物件會填入要撰寫的電子郵件收件者清單。如要使用草稿存取權,外掛程式資訊清單必須包含 https://www.googleapis.com/auth/gmail.addons.current.message.metadata Gmail 範圍METADATA

將內容插入現有草稿

外掛程式通常會提供撰寫訊息時可用的選項和控制項。在這些使用案例中,使用者在 UI 中做出選取後,外掛程式會解讀這些選取項目,並據此更新目前的工作電子郵件草稿。

為方便更新目前的草稿電子郵件,我們已使用下列類別擴充 資訊卡服務

一般來說,外掛程式的 Compose UI 會包含「儲存」或「插入」小工具,使用者可以點選這些小工具,表示已在 UI 中完成選取,並希望將所選內容新增至正在撰寫的電子郵件。如要新增這項互動功能,小工具應具備相關聯的 Action 物件,指示外掛程式在點選小工具時執行特定回呼函式。您必須實作這些回呼函式。每個回呼函式都應傳回建構的 UpdateDraftActionResponse 物件,詳細說明要對目前草稿電子郵件進行的變更。

範例 1

下列程式碼片段說明如何建構 Compose UI,以更新目前電子郵件草稿的主旨,以及「收件者」、「副本」和「密件副本」收件者。

/**
 * 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 UI,將圖片插入目前的草稿電子郵件。

/**
 * 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;
}