Google Workspace 부가기능으로 이메일의 활용도를 높여보세요

1. 개요

이 Codelab에서는 Google Apps Script를 사용하여 사용자가 이메일의 영수증 데이터를 Gmail 내에서 바로 스프레드시트에 추가할 수 있는 Gmail용 Google Workspace 부가기능을 작성합니다. 사용자가 이메일로 영수증을 받으면 이메일에서 관련 비용 정보를 자동으로 가져오는 부가기능을 열 수 있습니다. 사용자는 지출 정보를 편집한 다음 제출하여 비용을 Google Sheets 스프레드시트에 기록할 수 있습니다.

학습할 내용

  • Google Apps Script를 사용하여 Gmail용 Google Workspace 부가기능 만들기
  • Google Apps Script로 이메일 파싱
  • Google Apps Script를 통해 Google 스프레드시트와 상호작용
  • Google Apps Script의 속성 서비스를 사용하여 사용자 가치 저장

필요한 항목

  • 인터넷 및 웹브라우저 액세스
  • Google 계정
  • Gmail의 일부 메시지(이메일 영수증 권장)

2. 샘플 코드 가져오기

이 Codelab을 진행하면서 작성할 코드의 작동하는 버전을 참고하면 도움이 될 수 있습니다. GitHub 저장소에는 참조로 사용할 수 있는 샘플 코드가 포함되어 있습니다.

샘플 코드를 가져오려면 명령줄에서 다음을 실행합니다.

git clone https://github.com/googleworkspace/gmail-add-on-codelab.git

3. 기본 부가기능 만들기

먼저 이메일과 함께 비용 양식을 표시하는 간단한 부가기능 버전의 코드를 작성합니다.

먼저 새 Apps Script 프로젝트를 만들고 프로젝트의 매니페스트 파일을 엽니다.

  1. script.google.com으로 이동합니다. 여기에서 Apps Script 프로젝트를 생성, 관리, 모니터링할 수 있습니다.
  2. 새 프로젝트를 만들려면 왼쪽 상단에서 새 프로젝트를 클릭합니다. 새 프로젝트가 Code.gs이라는 기본 파일과 함께 열립니다. 지금은 Code.gs를 그대로 둡니다. 나중에 작업합니다.
  3. 제목 없는 프로젝트를 클릭하고 프로젝트의 이름을 Expense It!으로 지정한 후 이름 바꾸기를 클릭합니다.
  4. 왼쪽에서 프로젝트 설정 프로젝트 설정을 클릭합니다.
  5. 'appscript.json' 표시 매니페스트 파일 만들기' 체크박스를 선택합니다.
  6. 편집기 편집자를 클릭합니다.
  7. 매니페스트 파일을 열려면 왼쪽에서 appscript.json를 클릭합니다.

appscript.json에서 부가기능과 관련된 메타데이터(예: 이름, 필요한 권한)를 지정합니다. appsscript.json의 콘텐츠를 다음 구성 설정으로 바꿉니다.

{
  "timeZone": "GMT",
  "oauthScopes": [
    "https://www.googleapis.com/auth/gmail.addons.execute"
  ],
  "gmail": {
    "name": "Expense It!",
    "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/receipt_black_24dp.png",
    "contextualTriggers": [{
      "unconditional": {
      },
      "onTriggerFunction": "getContextualAddOn"
    }],
    "primaryColor": "#41f470",
    "secondaryColor": "#94f441"
  }
}

매니페스트의 contextualTriggers 부분에 특히 주의하세요. 매니페스트의 이 부분은 부가기능이 처음 활성화되었을 때 호출할 사용자 정의 함수를 식별합니다. 이 경우 열려 있는 이메일에 관한 세부정보를 가져오고 사용자에게 표시할 카드 세트를 반환하는 getContextualAddOn를 호출합니다.

getContextualAddOn 함수를 만들려면 다음 단계를 따르세요.

  1. 왼쪽에서 Code.gs 위로 포인터를 가져간 다음 메뉴 메뉴 더 보기 >를 클릭합니다. 이름 바꾸기.
  2. GetContextualAddOn를 입력하고 Enter 키를 누릅니다. Apps Script에서 자동으로 파일 이름에 .gs을 추가하므로 파일 확장자를 입력할 필요가 없습니다. GetContextualAddOn.gs를 입력하면 Apps Script에서 파일 이름을 GetContextualAddOn.gs.gs로 지정합니다.
  3. GetContextualAddOn.gs에서 기본 코드를 getContextualAddOn 함수로 바꿉니다.
/**
 * Returns the contextual add-on data that should be rendered for
 * the current e-mail thread. This function satisfies the requirements of
 * an 'onTriggerFunction' and is specified in the add-on's manifest.
 *
 * @param {Object} event Event containing the message ID and other context.
 * @returns {Card[]}
 */
function getContextualAddOn(event) {
  var card = CardService.newCardBuilder();
  card.setHeader(CardService.newCardHeader().setTitle('Log Your Expense'));

  var section = CardService.newCardSection();
  section.addWidget(CardService.newTextInput()
    .setFieldName('Date')
    .setTitle('Date'));
  section.addWidget(CardService.newTextInput()
    .setFieldName('Amount')
    .setTitle('Amount'));
  section.addWidget(CardService.newTextInput()
    .setFieldName('Description')
    .setTitle('Description'));
  section.addWidget(CardService.newTextInput()
    .setFieldName('Spreadsheet URL')
    .setTitle('Spreadsheet URL'));

  card.addSection(section);

  return [card.build()];
}

모든 Google Workspace 부가기능의 사용자 인터페이스는 카드가 하나 이상의 섹션으로 구성되어 있으며, 각 섹션에는 사용자에게 정보를 표시하고 가져올 수 있는 위젯이 포함되어 있습니다. getContextualAddOn 함수는 이메일에 있는 비용의 세부정보를 가져오는 단일 카드를 만듭니다. 카드에는 관련 데이터에 대한 텍스트 입력란이 포함된 섹션이 하나 있습니다. 이 함수는 부가기능 카드의 배열을 반환합니다. 이 경우 반환된 배열에는 하나의 카드만 포함됩니다.

Expense It!을 배포하기 전에 Apps Script 프로젝트에서 승인, 고급 서비스, 기타 세부정보를 관리하는 데 사용하는 Google Cloud Platform (GCP) 프로젝트가 필요합니다. 자세한 내용은 Google Cloud Platform 프로젝트를 참조하세요.

부가기능을 배포하고 실행하려면 다음 단계를 따르세요.

  1. GCP 프로젝트를 열고 프로젝트 번호를 복사합니다.
  2. Apps Script 프로젝트의 왼쪽에서 프로젝트 설정 프로젝트 설정을 클릭합니다.
  3. 'Google Cloud Platform (GCP) 프로젝트'에서 프로젝트 변경을 클릭합니다.
  4. GCP 프로젝트의 프로젝트 번호를 입력한 다음 프로젝트 설정을 클릭합니다.
  5. 배포 > 배포 테스트를 클릭합니다.
  6. 배포 유형이 Google Workspace 부가기능인지 확인합니다. 필요한 경우 대화상자 상단에서 배포 유형 사용 설정 배포 유형 사용 설정을 클릭하고 배포 유형으로 Google Workspace 부가기능을 선택합니다.
  7. 응용 프로그램: Gmail 옆의 설치를 클릭합니다.
  8. 완료를 클릭합니다.

이제 Gmail 받은편지함에서 부가기능을 볼 수 있습니다.

  1. 컴퓨터에서 Gmail을 엽니다.
  2. 오른쪽 패널에는 비용 지출이 있습니다. 비용을 지출하세요! 영수증 아이콘 부가기능이 표시됩니다. 부가기능 더보기 부가기능 더보기를 클릭하여 찾아야 할 수도 있습니다.
  3. 지출 내역이 나와 있는 영수증과 같은 이메일을 엽니다.
  4. 부가기능을 열려면 오른쪽 측면 패널에서 '비용 지출'을 클릭합니다. 비용을 지출하세요! 영수증 아이콘.
  5. 경비 지원 액세스 승인을 클릭하여 Google 계정에 액세스하고 표시되는 메시지를 따릅니다.

부가기능에는 열려 있는 Gmail 메일과 함께 간단한 양식이 표시됩니다. 아직 다른 작업을 하지 않지만 다음 섹션에서 기능을 빌드합니다.

이 실습을 진행하면서 부가기능의 업데이트를 확인하려면 코드를 저장하고 Gmail을 새로고침하기만 하면 됩니다. 추가 배포는 필요하지 않습니다.

4. 이메일 메시지 액세스

이메일 콘텐츠를 가져오는 코드를 추가하고 코드를 모듈화하여 좀 더 정리해 보세요.

Files 옆의 추가 파일 추가를 클릭합니다. 스크립트를 작성하고 Cards라는 파일을 만듭니다. Helpers라는 두 번째 스크립트 파일을 만듭니다. Cards.gs는 카드를 만들고 Helpers.gs의 함수를 사용하여 이메일 내용에 따라 양식의 필드를 채웁니다.

Cards.gs의 기본 코드를 다음 코드로 바꿉니다.

var FIELDNAMES = ['Date', 'Amount', 'Description', 'Spreadsheet URL'];

/**
 * Creates the main card users see with form inputs to log expenses.
 * Form can be prefilled with values.
 *
 * @param {String[]} opt_prefills Default values for each input field.
 * @param {String} opt_status Optional status displayed at top of card.
 * @returns {Card}
 */
function createExpensesCard(opt_prefills, opt_status) {
  var card = CardService.newCardBuilder();
  card.setHeader(CardService.newCardHeader().setTitle('Log Your Expense'));
  
  if (opt_status) {
    if (opt_status.indexOf('Error: ') == 0) {
      opt_status = '<font color=\'#FF0000\'>' + opt_status + '</font>';
    } else {
      opt_status = '<font color=\'#228B22\'>' + opt_status + '</font>';
    }
    var statusSection = CardService.newCardSection();
    statusSection.addWidget(CardService.newTextParagraph()
      .setText('<b>' + opt_status + '</b>'));
    card.addSection(statusSection);
  }
  
  var formSection = createFormSection(CardService.newCardSection(),
                                      FIELDNAMES, opt_prefills);
  card.addSection(formSection);
  
  return card;
}

/**
 * Creates form section to be displayed on card.
 *
 * @param {CardSection} section The card section to which form items are added.
 * @param {String[]} inputNames Names of titles for each input field.
 * @param {String[]} opt_prefills Default values for each input field.
 * @returns {CardSection}
 */
function createFormSection(section, inputNames, opt_prefills) {
  for (var i = 0; i < inputNames.length; i++) {
    var widget = CardService.newTextInput()
      .setFieldName(inputNames[i])
      .setTitle(inputNames[i]);
    if (opt_prefills && opt_prefills[i]) {
      widget.setValue(opt_prefills[i]);
    }
    section.addWidget(widget);
  }
  return section;
}

createExpensesCard 함수는 값의 배열을 사용하여 양식을 선택적 인수로 미리 채웁니다. 함수는 선택적 상태 메시지를 표시할 수 있습니다. 상태 메시지는 상태가 'Error:'로 시작하면 빨간색으로, 그렇지 않으면 녹색으로 표시됩니다. 각 필드를 양식에 수동으로 추가하는 대신 createFormSection라는 도우미 함수가 텍스트 입력 위젯을 만드는 프로세스를 반복하고 setValue로 각 기본값을 설정한 후 카드의 해당 섹션에 위젯을 추가합니다.

이제 Helpers.gs의 기본 코드를 다음 코드로 바꿉니다.

/**
 * Finds largest dollar amount from email body.
 * Returns null if no dollar amount is found.
 *
 * @param {Message} message An email message.
 * @returns {String}
 */
function getLargestAmount(message) {
  return 'TODO';
}

/**
 * Determines date the email was received.
 *
 * @param {Message} message An email message.
 * @returns {String}
 */
function getReceivedDate(message) {
  return 'TODO';
}

/**
 * Determines expense description by joining sender name and message subject.
 *
 * @param {Message} message An email message.
 * @returns {String}
 */
function getExpenseDescription(message) {
  return 'TODO';
}

/**
 * Determines most recent spreadsheet URL.
 * Returns null if no URL was previously submitted.
 *
 * @returns {String}
 */
function getSheetUrl() {
  return 'TODO';
}

Helpers.gs의 함수는 getContextualAddon에서 호출하여 양식에 미리 채워진 값을 확인합니다. 현재 이 함수는 'TODO' 문자열만 반환합니다. 자동 입력 로직을 이후 단계에서 구현하게 됩니다.

다음으로 Cards.gsHelpers.gs의 코드를 활용하도록 GetContextualAddon.gs의 코드를 업데이트합니다. GetContextualAddon.gs의 코드를 다음 코드로 바꿉니다.

/**
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Returns the contextual add-on data that should be rendered for
 * the current e-mail thread. This function satisfies the requirements of
 * an 'onTriggerFunction' and is specified in the add-on's manifest.
 *
 * @param {Object} event Event containing the message ID and other context.
 * @returns {Card[]}
 */
function getContextualAddOn(event) {
  var message = getCurrentMessage(event);
  var prefills = [getReceivedDate(message),
                  getLargestAmount(message),
                  getExpenseDescription(message),
                  getSheetUrl()];
  var card = createExpensesCard(prefills);

  return [card.build()];
}

/**
 * Retrieves the current message given an action event object.
 * @param {Event} event Action event object
 * @return {Message}
 */
function getCurrentMessage(event) {
  var accessToken = event.messageMetadata.accessToken;
  var messageId = event.messageMetadata.messageId;
  GmailApp.setCurrentMessageAccessToken(accessToken);
  return GmailApp.getMessageById(messageId);
}

getCurrentMessage 함수는 Gmail에서 제공하는 이벤트를 사용하여 사용자가 현재 열려 있는 메일을 읽습니다. 이 함수가 작동하려면 Gmail 메일에 대한 읽기 전용 액세스를 허용하는 스크립트 매니페스트에 범위를 추가합니다.

appscript.json에서 https://www.googleapis.com/auth/gmail.addons.current.message.readonly 범위도 요청하도록 oauthScopes를 업데이트합니다.

"oauthScopes": [
  "https://www.googleapis.com/auth/gmail.addons.execute",
   "https://www.googleapis.com/auth/gmail.addons.current.message.readonly"
],

Gmail에서 부가기능을 실행하고 Expense It!에 대한 액세스를 승인합니다. 이메일 메시지를 확인하세요. 양식 필드가 이제 'TODO'로 미리 채워집니다.

5. Google Sheets와 상호작용

비용 활용: 부가기능에는 사용자가 비용에 대한 세부정보를 입력할 수 있는 양식이 있지만 이러한 세부정보는 어디로도 이동할 수 없습니다. 양식 데이터를 Google 시트로 전송하는 버튼을 추가해 보겠습니다.

버튼을 추가하려면 ButtonSet 클래스를 사용합니다. Google Sheets와 상호작용하기 위해 Google Sheets 서비스를 사용합니다.

'Submit'이라는 라벨이 지정된 버튼을 반환하도록 createFormSection를 수정합니다. 카드의 양식 섹션에서 찾을 수 있습니다. 다음 단계를 따릅니다.

  1. CardService.newTextButton()를 사용하여 텍스트 버튼을 만들고 버튼에 'Submit' 라벨을 지정합니다. (CardService.TextButton.setText() 사용)
  2. 버튼을 클릭하면 다음 submitForm 작업이 CardService.TextButton.setOnClickAction()를 통해 호출되도록 버튼을 설계합니다.
/**
 * Logs form inputs into a spreadsheet given by URL from form.
 * Then displays edit card.
 *
 * @param {Event} e An event object containing form inputs and parameters.
 * @returns {Card}
 */
function submitForm(e) {
  var res = e['formInput'];
  try {
    FIELDNAMES.forEach(function(fieldName) {
      if (! res[fieldName]) {
        throw 'incomplete form';
      }
    });
    var sheet = SpreadsheetApp
      .openByUrl((res['Spreadsheet URL']))
      .getActiveSheet();
    sheet.appendRow(objToArray(res, FIELDNAMES.slice(0, FIELDNAMES.length - 1)));
    return createExpensesCard(null, 'Logged expense successfully!').build();
  }
  catch (err) {
    if (err == 'Exception: Invalid argument: url') {
      err = 'Invalid URL';
      res['Spreadsheet URL'] = null;
    }
    return createExpensesCard(objToArray(res, FIELDNAMES), 'Error: ' + err).build();
  }
}

/**
 * Returns an array corresponding to the given object and desired ordering of keys.
 *
 * @param {Object} obj Object whose values will be returned as an array.
 * @param {String[]} keys An array of key names in the desired order.
 * @returns {Object[]}
 */
function objToArray(obj, keys) {
  return keys.map(function(key) {
    return obj[key];
  });
}
  1. CardService.newButtonSet()를 사용하여 버튼 모음 위젯을 만들고 CardService.ButtonSet.addButton()로 설정된 버튼에 텍스트 버튼을 추가합니다.
  2. CardService.CardSection.addWidget()를 사용하여 카드의 양식 섹션에 버튼 세트 위젯을 추가합니다.

코드 몇 줄이면 URL로 스프레드시트를 연 다음 해당 시트에 데이터 행을 추가할 수 있습니다. 양식 입력은 e 이벤트의 일부로 함수에 전달되며 사용자가 모든 필드를 제공했는지 확인합니다. 오류가 발생하지 않는다고 가정하고 양호한 상태의 빈 지출 카드를 만듭니다. 오류가 포착되면 오류 메시지와 함께 원래 채워진 카드를 반환합니다. objToArray 도우미 함수를 사용하면 양식 응답을 배열로 쉽게 변환한 다음 스프레드시트에 추가할 수 있습니다.

마지막으로 appsscript.jsonoauthScopes 섹션을 업데이트하여 https://www.googleapis.com/auth/spreadsheets 범위를 다시 요청합니다. 이 범위가 승인되면 부가기능에서 사용자의 Google Sheets를 읽고 수정할 수 있습니다.

"oauthScopes": [
  "https://www.googleapis.com/auth/gmail.addons.execute",
  "https://www.googleapis.com/auth/gmail.addons.current.message.readonly",
  "https://www.googleapis.com/auth/spreadsheets"
],

아직 새 스프레드시트를 만들지 않은 경우 https://docs.google.com/spreadsheets/에서 만들어 보세요.

이제 부가기능을 다시 실행하고 양식을 제출해 보세요. 스프레드시트 URL 양식 입력란에 도착 URL의 전체 URL을 입력해야 합니다.

6. 속성 서비스로 값 저장

사용자가 동일한 스프레드시트에 많은 비용을 기록하는 경우가 많으므로 가장 최근의 스프레드시트 URL을 카드의 기본값으로 제공하는 것이 편리합니다. 가장 최근 스프레드시트의 URL을 알기 위해서는 부가기능을 사용할 때마다 해당 정보를 저장해야 합니다.

속성 서비스를 사용하면 키-값 쌍을 저장할 수 있습니다. 이 경우 적합한 키는 'SPREADSHEET_URL'입니다. 값은 URL 자체가 됩니다. 이러한 값을 저장하려면 시트에 새 행을 추가할 때 스프레드시트의 URL이 속성으로 저장되도록 Cards.gs에서 submitForm를 수정해야 합니다.

속성은 스크립트, 사용자 또는 문서의 세 가지 범위 중 하나를 가질 수 있습니다. document 범위는 Gmail 부가기능에는 적용되지 않지만, 특정 Google 문서 또는 시트와 관련된 정보를 저장할 때는 별도의 부가기능 유형과 관련이 있습니다. Google 부가기능에서 원하는 동작은 다른 사용자가 아닌 자신의 최신 스프레드시트를 양식의 기본 옵션으로 표시하는 것입니다. 따라서 script 범위 대신 user 범위를 선택합니다.

PropertiesService.getUserProperties().setProperty()를 사용하여 스프레드시트 URL을 저장합니다. Cards.gssubmitForm에 다음을 추가합니다.

PropertiesService.getUserProperties().setProperty('SPREADSHEET_URL', 
    res['Spreadsheet URL']);

그런 다음 사용자가 부가기능을 사용할 때마다 최신 URL이 표시되도록 Helpers.gsgetSheetUrl 함수를 수정하여 저장된 속성을 반환합니다. PropertiesService.getUserProperties().getProperty()를 사용하여 속성 값을 가져옵니다.

/**
 * Determines most recent spreadsheet URL.
 * Returns null if no URL was previously submitted.
 *
 * @returns {String}
 */
function getSheetUrl() {
  return PropertiesService.getUserProperties().getProperty('SPREADSHEET_URL');
}

마지막으로 속성 서비스에 액세스하려면 스크립트도 승인해야 합니다. 부가기능이 속성 정보를 읽고 쓸 수 있도록 이전과 같이 범위 https://www.googleapis.com/auth/script.storage를 매니페스트에 추가합니다.

7. Gmail 메일 파싱

사용자의 입장에서 이메일의 비용과 관련된 정보로 양식을 미리 작성해 보겠습니다. Helpers.gs에서 이 역할을 하는 함수를 이미 만들었지만 지금까지는 'TODO'만 반환했습니다. 날짜, 금액, 지출 설명

예를 들어 이메일을 수신한 날짜를 가져와 이를 비용이 발생한 날짜의 기본값으로 사용할 수 있습니다.

/**
 * Determines date the email was received.
 *
 * @param {Message} message - The message currently open.
 * @returns {String}
 */
function getReceivedDate(message) {
  return message.getDate().toLocaleDateString();
}

나머지 두 함수를 구현합니다.

  1. getExpenseDescription에는 발신자의 이름과 메일 제목을 모두 결합해야 할 수도 있지만 메일 본문을 파싱하고 더 정확한 설명을 전달하는 더 정교한 방법이 있습니다.
  2. getLargestAmount의 경우 돈과 관련된 특정 기호를 찾아보세요. 영수증에는 세금 및 기타 수수료 등 여러 값이 표시되는 경우가 많습니다. 정확한 금액을 파악할 수 있는 방법을 생각해 보세요. 정규 표현식을 사용하면 편리합니다.

추가적인 아이디어가 필요하면 GmailMessage 참조 문서를 살펴보거나 Codelab 시작 부분에서 다운로드한 솔루션 코드를 확인하세요. Helpers.gs의 모든 함수를 위한 자체 구현을 고안했다면 부가기능을 사용해 보세요. 영수증을 열어 스프레드시트에 기록하세요.

8. 카드 작업으로 양식 지우기

비용을 지출하면 어떻게 되나요? 열려 있는 이메일에서 비용을 오인하고 양식에 잘못된 정보를 미리 입력한 적이 있나요? 사용자가 양식을 지웁니다. CardAction 클래스를 사용하면 작업을 클릭할 때 호출되는 함수를 지정할 수 있습니다. 이 메서드를 사용하여 사용자에게 양식을 빠르게 지울 수 있는 방법을 제공해 보겠습니다.

반환되는 카드에 '양식 지우기'라는 카드 작업이 포함되도록 createExpensesCard를 수정합니다. 그리고 클릭하면 Cards.gs에 붙여넣을 수 있는 다음 clearForm 함수가 호출됩니다. opt_status를 'Status'라는 이름의 매개변수로 전달해야 합니다. 양식을 지워도 상태 메시지가 유지되도록 할 수 있습니다. 작업의 선택적 매개변수는 Object.<string, string> 유형이어야 하므로 opt_status를 사용할 수 없는 경우 {'Status' : ''}를 전달해야 합니다.

/**
 * Recreates the main card without prefilled data.
 *
 * @param {Event} e An event object containing form inputs and parameters.
 * @returns {Card}
 */
function clearForm(e) {
  return createExpensesCard(null, e['parameters']['Status']).build();
}

9. 스프레드시트 만들기

Google Apps Script를 사용하여 기존 스프레드시트를 수정하는 것 외에도 프로그래밍 방식으로 완전히 새로운 스프레드시트를 만들 수도 있습니다. 부가기능으로 사용자가 비용용 스프레드시트를 만들 수 있도록 허용해 보겠습니다. 시작하려면 createExpensesCard가 반환하는 카드에 다음 카드 섹션을 추가합니다.

var newSheetSection = CardService.newCardSection();
var sheetName = CardService.newTextInput()
  .setFieldName('Sheet Name')
  .setTitle('Sheet Name');
var createExpensesSheet = CardService.newAction()
  .setFunctionName('createExpensesSheet');
var newSheetButton = CardService.newTextButton()
  .setText('New Sheet')
  .setOnClickAction(createExpensesSheet);
newSheetSection.addWidget(sheetName);
newSheetSection.addWidget(CardService.newButtonSet().addButton(newSheetButton));
card.addSection(newSheetSection);

이제 사용자가 '새 시트'를 클릭하면 버튼을 누르면 부가기능이 항상 표시되도록 고정된 헤더 행으로 서식이 지정된 새 스프레드시트를 생성합니다. 사용자가 양식에서 새 스프레드시트의 제목을 지정합니다. 양식이 비어 있는 경우 기본값을 포함하는 것이 좋을 수도 있습니다. createExpensesSheet 구현에서 적절한 상태 메시지를 추가하고 URL 필드에 새 스프레드시트의 URL을 미리 채우고 거의 동일한 카드를 기존 카드에 반환합니다.

10. 축하합니다.

이메일에서 비용을 찾고 사용자가 단 몇 초 만에 비용을 스프레드시트에 기록할 수 있도록 도와주는 Gmail 부가기능을 성공적으로 설계 및 구현했습니다. Google Apps Script를 사용하여 여러 Google API와 인터페이스하고 부가기능을 여러 번 실행할 때 데이터를 유지했습니다.

가능한 개선사항

Expense It!을 향상하려면 상상력을 발휘해 보세요. 더 유용한 제품을 만들기 위한 몇 가지 아이디어를 소개합니다.

  • 사용자가 비용을 기록하면 스프레드시트로 연결
  • 비용 기록을 수정/실행취소하는 기능 추가
  • 사용자가 결제하고 금액을 요청할 수 있도록 외부 API를 통합합니다.

자세히 알아보기