Compose 작업으로 Compose UI 확장

사용자가 Gmail 메시지를 읽을 때 카드 기반 인터페이스를 제공하는 것 외에도 Gmail을 확장하는 Google Workspace 부가기능은 사용자가 새 메시지를 작성하거나 기존 메시지에 회신할 때 또 다른 인터페이스를 제공할 수 있습니다. 이를 통해 Google Workspace 부가기능에서 사용자의 이메일 작성 작업을 자동화할 수 있습니다.

부가기능 Compose UI에 액세스

부가기능의 Compose UI를 보는 방법에는 두 가지가 있습니다. 첫 번째 방법은 부가기능이 이미 열려 있는 상태에서 새 초안을 작성하거나 답장을 하는 것입니다. 두 번째 방법은 초안을 작성하는 동안 부가기능을 시작하는 것입니다.

두 경우 모두 부가기능이 부가기능 매니페스트에 정의된 상응하는 트리거 함수 작성을 실행하도록 합니다. 작성 트리거 함수는 해당 작성 작업의 작성 UI를 빌드하고 Gmail에서 사용자에게 표시합니다.

Compose 부가기능 빌드

다음 일반적인 단계에 따라 부가기능에 Compose 기능을 추가할 수 있습니다.

  1. gmail.composeTrigger 필드를 부가기능 스크립트 프로젝트 매니페스트에 추가하고 매니페스트 범위를 업데이트하여 작성 작업에 필요한 범위를 포함합니다.
  2. 트리거가 실행될 때 Compose UI를 빌드하는 Compose 트리거 함수를 구현합니다. Compose 트리거 함수는 단일 Card 객체 또는 작성 작업의 작성 UI를 구성하는 Card 객체의 배열을 반환합니다.
  3. 사용자의 작성 UI 상호작용에 반응하는 데 필요한 연결된 콜백 함수를 구현합니다. 이러한 함수는 Compose UI만 표시하는 작성 작업 자체가 아니며, Compose UI의 여러 요소가 선택될 때 발생하는 작업을 제어하는 개별 함수입니다. 예를 들어 버튼이 포함된 UI 카드에는 일반적으로 사용자가 버튼을 클릭할 때 실행되는 콜백 함수가 연결되어 있습니다. 초안 메시지 콘텐츠를 업데이트하는 위젯의 콜백 함수는 UpdateDraftActionResponse 객체를 반환해야 합니다.

Compose 트리거 함수

부가기능의 Compose UI는 부가기능의 메시지 UI와 동일한 방식으로 빌드됩니다. 즉, Apps Script 카드 서비스를 사용하여 카드를 구성하고 위젯으로 카드를 채웁니다.

매니페스트에서 정의한 gmail.composeTrigger.selectActions[].runFunction를 구현해야 합니다. Compose 트리거 함수는 단일 Card 객체 또는 해당 작업의 Compose UI를 구성하는 Card 객체의 배열을 반환해야 합니다. 이러한 함수는 상황별 트리거 함수와 매우 유사하며 동일한 방식으로 카드를 빌드해야 합니다.

Compose 트리거 이벤트 객체

작성 작업이 선택되면 해당 작성 트리거 함수를 실행하고 함수에 이벤트 객체를 매개변수로 전달합니다. 이벤트 객체는 부가기능 컨텍스트와 트리거 함수에 구성되는 초안에 대한 정보를 전달할 수 있습니다.

이벤트 객체에서 정보가 정렬되는 방식에 대한 자세한 내용은 이벤트 객체 구조를 참조하세요. 이벤트 객체에 포함된 정보는 gmail.composeTrigger.draftAccess 매니페스트 필드의 값에 의해 부분적으로 제어됩니다.

  • gmail.composeTrigger.draftAccess 매니페스트 필드가 NONE이거나 포함되지 않은 경우 이벤트 객체에는 최소한의 정보만 포함됩니다.

  • gmail.composeTrigger.draftAccessMETADATA로 설정되면 작성 트리거 함수로 전달되는 이벤트 객체가 작성 중인 이메일의 수신자 목록으로 채워집니다.

활성 초안에 콘텐츠 삽입

일반적으로 Google Workspace 부가기능 작성 UI는 메시지 작성에 도움이 되는 사용자 옵션과 컨트롤을 제공합니다. 이러한 사용 사례의 경우 사용자가 UI에서 항목을 선택하면 부가기능이 선택사항을 해석하고 그에 따라 현재 작업 중인 이메일 초안을 업데이트합니다.

현재 초안 이메일을 더 쉽게 업데이트할 수 있도록 카드 서비스가 다음 클래스로 확장되었습니다.

일반적으로 부가기능 작성 UI에는 '저장' 또는 '삽입' 위젯이 포함되어 있습니다. 이 위젯은 사용자가 UI에서 선택을 완료했으며 작성 중인 이메일에 선택 항목을 추가하고 싶다고 표시하기 위해 클릭할 수 있습니다. 이 상호작용을 추가하려면 위젯을 클릭할 때 특정 콜백 함수를 실행하도록 부가기능에 지시하는 연결된 Action 객체가 위젯에 있어야 합니다. 이러한 콜백 함수를 구현해야 합니다. 각 콜백 함수는 현재 임시 이메일의 변경사항을 자세히 설명하는 빌드된 UpdateDraftActionResponse 객체를 반환해야 합니다.

예 1

다음 코드 스니펫은 현재 이메일 초안의 제목과 받는사람, 참조, 숨은참조 수신자를 업데이트하는 편지쓰기 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;
    }