Gmail のメッセージを読んでいるときにカードベースのインターフェースを提供できるだけでなく、Gmail を拡張する Google Workspace アドオンでは、ユーザーが新しいメッセージを作成したり、既存のメッセージに返信したりするときに別のインターフェースを提供できます。これにより、Google Workspace アドオンでユーザーのメール作成タスクを自動化できます。
アドオンの compose UI にアクセスする
アドオンの Compose UI を表示する方法は 2 つあります。1 つ目の方法は、アドオンがすでに開いている状態で、新しい下書きまたは返信の作成を開始することです。2 つ目の方法は、下書きの作成中にアドオンを起動する方法です。
どちらの場合でも、アドオンは、アドオンのマニフェストで定義されている対応するコンポーズ トリガー関数を実行します。Compose トリガー関数は、その Compose アクションの Compose UI をビルドし、Gmail がユーザーに表示します。
Compose アドオンの作成
アドオンにコンポーズ機能を追加する一般的な手順は次のとおりです。
- アドオン スクリプト プロジェクトのマニフェストに 
gmail.composeTriggerフィールドを追加し、マニフェストのスコープを更新して、コンポーズ アクションに必要なスコープを含めます。 - トリガーがトリガーされたときに Compose UI を作成する Compose トリガー関数を実装します。Compose トリガー関数は、単一の 
Cardオブジェクトまたは、Compose アクションの Compose UI を構成するCardオブジェクトの配列を返します。 - ユーザーの UI の作成操作に応答するために必要な関連するコールバック関数を実装します。これらの関数は、Compose UI が表示されるだけの Compose アクション自体ではなく、Compose UI のさまざまな要素が選択されたときに何が起こるかを制御する個別の関数です。たとえば、ボタンを含む UI カードには通常、ユーザーがそのボタンをクリックしたときに実行されるコールバック関数が関連付けられています。下書きメッセージのコンテンツを更新するウィジェットのコールバック関数は、
UpdateDraftActionResponseオブジェクトを返す必要があります。 
トリガー関数をコンポーズする
アドオンの作成 UI は、アドオンのメッセージ UI と同じ方法で作成されます。つまり、Apps Script のカード サービスを使用してカードを作成し、ウィジェットで埋めます。
マニフェストで定義した gmail.composeTrigger.selectActions[].runFunction を実装する必要があります。コンポーズ トリガー関数は、単一の Card オブジェクト、またはそのアクションのコンポーズ UI を構成する Card オブジェクトの配列を返す必要があります。これらの関数はコンテキスト トリガー関数と非常によく似ており、カードの作成方法も同じです。
トリガー イベント オブジェクトをコンポーズする
コンポーズ アクションが選択されると、対応するコンポーズ トリガー関数が実行され、関数にイベント オブジェクトがパラメータとして渡されます。イベント オブジェクトには、アドオンのコンテキストと、トリガー関数に作成される下書きに関する情報を含めることができます。
イベント オブジェクトに情報がどのように配置されているかについて詳しくは、イベント オブジェクトの構造をご覧ください。イベント オブジェクトに含まれる情報は、gmail.composeTrigger.draftAccess マニフェスト フィールドの値によって部分的に制御されます。
gmail.composeTrigger.draftAccessマニフェスト フィールドがNONEの場合、または含まれていない場合、イベント オブジェクトには最小限の情報のみが含まれます。gmail.composeTrigger.draftAccessがMETADATAに設定されている場合、作成トリガー関数に渡されるイベント オブジェクトには、作成中のメールの受信者のリストが入力されます。
アクティブな下書きにコンテンツを挿入する
通常、Google Workspace アドオンの作成 UI には、メッセージの作成に役立つユーザー オプションとコントロールが用意されています。このようなユースケースでは、ユーザーが UI で選択すると、アドオンはその選択を解釈し、それに応じて現在の作業中のメールの下書きを更新します。
現在の下書きメールを簡単に更新できるように、カード サービスが次のクラスで拡張されました。
ContentType- 変更可能な HTML、変更不可の HTML(Gmail ユーザーが編集できない)、または書式なしテキスト コンテンツのいずれを追加するかを定義する列挙型。UpdateDraftActionResponse- 現在のメールの下書きを更新するアクションに対するレスポンスを表します。UpdateDraftActionResponseBuilder-UpdateDraftActionResponseオブジェクトのビルダー。UpdateDraftBodyAction- 現在の下書きメールの本文を更新するアクションを表します。UpdateDraftBodyType- 本文の変更方法を定義する列挙型。UpdateDraftSubjectAction- 現在の下書きメールの件名フィールドを更新するアクションを表します。UpdateDraftToRecipientsAction- 現在の下書きメールの宛先受信者を更新するアクションを表します。UpdateDraftCcRecipientsAction- 現在の下書きメールの Cc 受信者を更新するアクションを表します。UpdateDraftBccRecipientsAction- 現在の下書きメールの Bcc 受信者を更新するアクションを表します。
通常、アドオンの作成 UI には、ユーザーがクリックして UI での選択が完了したことを示し、選択内容を作成中のメールに追加することを示す [保存] ウィジェットまたは [挿入] ウィジェットが含まれています。このインタラクティビティを追加するには、ウィジェットに Action オブジェクトを関連付け、ウィジェットがクリックされたときに特定のコールバック関数を実行するようアドオンに指示する必要があります。これらのコールバック関数を実装する必要があります。各コールバック関数は、現在の下書きメールに加える変更を詳細に示す、作成された UpdateDraftActionResponse オブジェクトを返す必要があります。
例 1
次のコード スニペットは、現在のメールの下書きの件名、To、Cc、Bcc の受信者を更新する作成 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
次のコード スニペットは、現在の下書きメールに画像を挿入する作成 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;
    }