작성 작업으로 Compose UI 확장

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

부가기능 작성 UI에 액세스

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

어느 경우든 부가기능은 부가기능 매니페스트에 정의된 상응하는 트리거 함수 작성을 실행합니다. Compose 트리거 함수는 해당 Compose 작업의 Compose UI를 빌드하며 Gmail은 이를 사용자에게 표시합니다.

Compose 부가기능 빌드

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

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

트리거 함수 작성

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

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

트리거 이벤트 객체 작성

Compose 작업이 선택되면 상응하는 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;
    }