본문으로 바로가기

Google Apps Script와 Gemini API 튜토리얼: 스마트 데이터 추출

Google Apps Script와 Gemini API를 사용해 이메일과 PDF에서 데이터 추출을 자동화하는 방법을 배워 보세요. 오늘 바로 Google 스프레드시트로 가는 서버리스 파이프라인을 구축하세요.
업데이트됨 2026년 7월 17일  · 11분 읽다

수작업 데이터 입력은 생산성의 적입니다. 송장, 예약 확인, 고객 피드백 양식처럼 운영 이메일에서 데이터를 추출해 업무를 진행한다면, 전통적인 파싱 방식이 얼마나 악몽 같은지 익숙하실 겁니다. 

과거에는 개발자들이 정규식(Regex)에 의존해 송장 번호나 청구 금액 같은 세부 정보를 추출했습니다. 하지만 Regex는 지나치게 취약합니다. 공급업체가 이메일 템플릿을 조금만 바꾸거나 임의의 줄바꿈을 추가해도 파서는 조용히 전부 망가집니다.

이 튜토리얼에서는 생성형 AI를 사용해 이 문제를 해결하는 완전 자동, 헤드리스 파이프라인을 구축하는 방법을 보여 드립니다. 읽지 않은 Gmail 메시지를 읽고, 비정형 텍스트를 Gemini API에 전달해 지능적으로 추출한 다음, 완벽하게 구조화된 JSON 데이터를 Google 스프레드시트에 바로 기록하는 경량 스크립트를 작성하겠습니다.

사전 준비 사항:

  • Google 계정
  • JavaScript(Google Apps Script)에 대한 기본 이해
  • Gemini API 키

Google Apps Script란?

Google Apps Script는 JavaScript 기반의 클라우드형 신속 애플리케이션 개발 플랫폼으로, Google Docs, Sheets, Slides 등 Google Workspace 애플리케이션을 자동화하고 사용자 정의하며 확장할 수 있게 해 줍니다. 

플랫폼이 Google의 서버에서 직접 실행되므로 소프트웨어 설치, 로컬 환경 구성, 인프라 관리가 필요 없습니다. 

Apps Script는 개발자/로우코드 개발자가 Docs, Sheets, Slides, Drive 등 Google Workspace 도구와 프로그램적으로 상호작용할 수 있게 합니다. 사용자 지정 메뉴, 버튼 클릭, 시간 기반 스케줄을 통해 자동화를 구축하고 실행할 수 있으며, Google Workspace 마켓플레이스용 애드온을 제작·배포하는 데에도 활용할 수 있습니다.

Google Apps Script의 작동 방식

Google Apps Script는 백엔드 구성과 API 인증의 무거운 작업을 추상화하여, 로직과 데이터에 집중할 수 있도록 해 줍니다. 이를 위해 다음과 같은 기능을 제공합니다.

  • 클라우드 네이티브 에디터: 브라우저에 내장된 웹 기반 IDE에서 JavaScript 코드를 작성, 디버그, 배포합니다.
  • 내장 서비스: OAuth나 복잡한 API 호출로 씨름하는 대신, SpreadsheetApp, MailApp, DriveApp 같은 기본 제공 전역 객체로 Google 서비스와 네이티브하게 상호작용합니다.
  • 이벤트 기반 트리거: 스크립트는 사용자 지정 메뉴 버튼으로 수동 실행하거나, 시간 기반 트리거(예: 매일 자정) 및 이벤트 기반 트리거(예: 사용자가 Google Form을 제출할 때)를 사용해 자동 실행되도록 예약할 수 있습니다.

Google Apps Script 아키텍처: Gmail에서 Sheets로 가는 파이프라인

스크립트를 작성하기 전에, 데이터가 이 파이프라인을 통해 어떻게 흐르는지 살펴보겠습니다. 이 아키텍처는 네 가지 구성 요소가 함께 작동하는 것에 의존합니다.

  • Gmail(소스): 표준 검색 연산자(예: is:unread label:invoices)로 받은편지함을 조회하는 것으로 시작합니다. 스크립트는 올바른 이메일 스레드를 선별하고, 일반 텍스트 본문과 첨부된 PDF 파일을 추출합니다.
  • Apps Script(연산): 오케스트레이션 레이어 역할을 합니다. 읽지 않은 스레드를 순회하고, 첨부 파일을 base64 데이터로 포맷하며, 오류 보고 및 배치 처리 로직을 담당합니다.
  • Gemini API(변환 엔진): Apps Script는 멀티모달 페이로드(이메일 텍스트 + PDF)를 Gemini 2.5 Flash 모델에 전송합니다. API 호출에 엄격한 JSON 응답 스키마를 전달함으로써, 모델이 대화형 텍스트를 생성하는 대신 공급업체, 총액, 통화 같은 정확한 값을 추출하도록 강제합니다.
  • Google 스프레드시트(도착지): Gemini가 구조화된 JSON을 반환하면, Apps Script는 결과를 파싱해 단일 배열로 묶고 setValues()를 사용해 활성 스프레드시트의 다음 빈 행에 데이터를 일괄 삽입합니다.

workflow-diagram

왜 이번 빌드의 연산 레이어로 Google Apps Script를 사용하나요? 

가장 큰 이점은 인프라 오버헤드를 완전히 제거한다는 점입니다. 서버 프로비저닝이 전혀 필요 없고, 이메일을 읽거나 스프레드시트에 쓰기 위해 Docker 컨테이너를 구성하거나 복잡한 OAuth 플로를 설정할 필요도 없습니다. 

Apps Script는 GmailAppSpreadsheetApp 같은 서비스와 네이티브하게 통합되기 때문에, 인증은 Google이 내부적으로 처리합니다. 코드를 작성하고 엔드포인트만 연결하면 됩니다.

Step 1: Google Apps Script 환경 준비

코드를 작성하기 전에 외부 종속성을 준비해야 합니다. 여기에는 Gemini API 접근 권한 확보, 대상 스프레드시트 생성, Gmail 받은편지함에서 들어오는 송장 이메일에 올바른 라벨을 지정하도록 구성하는 작업이 포함됩니다.

Gemini API 키 생성

지능형 데이터 추출을 구동하려면 Gemini API 접근이 필요합니다.

  1. 다음으로 이동하세요 Google AI Studio에 접속해 Google 계정으로 로그인합니다.
  2. 왼쪽 탐색 메뉴에서 Get API key를 클릭합니다.
  3. Create API key 버튼을 클릭합니다. 기존 Google Cloud 프로젝트에서 키를 생성하거나 AI Studio가 새 프로젝트를 만들어 주도록 선택할 수 있습니다.
  4. 생성된 문자열을 복사하세요. 

보안 모범 사례: 이 키를 잃어버리지 마세요. 더 중요한 것은 코드에 일반 텍스트로 하드코딩하지 않는 것입니다. 일단 클립보드나 안전한 메모장에 복사해 두세요. 다음 단계에서 Apps Script 환경에 안전하게 보관하겠습니다.

AIStudio-Dashboard

Google 스프레드시트 준비 및 키 보관

추출한 데이터를 저장할 공간이 필요합니다. 이 시트는 자동화 스크립트를 실행하는 출발점 역할도 합니다.

1. 데이터베이스 헤더 설정 새 빈 Google 스프레드시트를 만드세요. 첫 번째 행에, 스크립트에서 정의할 JSON 스키마와 일치하도록 다음 열 헤더를 만듭니다.

  • Date
  • Vendor
  • Invoice Number
  • Total Amount
  • Currency
  • Items Summary
  • Email Link

데이터가 늘어나도 헤더가 보이도록 맨 윗행을 고정하세요.

GoogleSheet

2. Apps Script에 접속하여 API 키 저장 시트가 준비됐으니 그곳에서 바로 Apps Script 편집기를 열 수 있습니다. 이렇게 하면 코드가 자동으로 이 스프레드시트에 연결됩니다.

  1. Google 스프레드시트에서 상단 메뉴의 확장 프로그램 > Apps Script를 클릭하세요.launch-script-editor
  2. 에디터가 열리면 왼쪽 사이드바의 기어 아이콘을 눌러 프로젝트 설정을 엽니다.

appsscript-editor

  1. 하단으로 스크롤해 스크립트 속성 섹션을 찾습니다.
  2. 스크립트 속성 추가를 클릭합니다.
  3. Property에 정확히 GEMINI_API_KEY를 입력합니다.
  4. Value에는 앞서 AI Studio에서 복사한 API 키를 붙여넣습니다.
  5. 스크립트 속성 저장을 클릭합니다.

store-the-gemini-api-key

이후 작성할 코드는 런타임에 이 값을 안전하게 가져와 자격 증명이 노출되지 않도록 합니다.

Step 2: Google Apps Script 코드 작성

Apps Script 편집기에서 기본 코드를 모두 삭제하세요. 이제 자동화 엔진을 블록 단위로 만들어 보겠습니다.

1. 구성 및 UI 설정

먼저 전역 구성 객체를 정의합니다. 이는 모든 하드코딩 변수를 한곳에 모아두는 클린 코드 모범 사례로, 이 상단 블록만 수정하면 됩니다.

또한 onOpen() 함수를 추가합니다. 이 내장 Apps Script 트리거는 Google 스프레드시트에 사용자 지정 메뉴를 자동으로 생성하므로, 비전문가도 코드 편집기를 열지 않고 스크립트를 수동 실행할 수 있습니다.

const CONFIG = {
 searchQuery: "is:unread label:invoices",
 model: "gemini-2.5-flash",
 adminEmail: Session.getActiveUser().getEmail() // Automatically emails the script owner if it crashes
};

/**
* Creates a custom menu in Google Sheets so non-technical users can run the script manually.
*/
function onOpen() {
 const ui = SpreadsheetApp.getUi();
 ui.createMenu('🤖 AI Automations')
   .addItem('Fetch New Invoices', 'processInvoices')
   .addToUi();
}

2. 오케스트레이션 설정

processInvoices() 함수는 주 오케스트레이터 역할을 합니다. 먼저 앞서 설정한 스크립트 속성에서 API 키를 안전하게 가져옵니다. 

그다음 내장 GmailApp 서비스를 사용해 받은편지함을 조회합니다.

GmailApp.search(CONFIG.searchQuery)를 호출하면, is:unread label:invoices 규칙과 일치하는 이메일 스레드 배열을 가져옵니다. 

매치되는 항목이 있으면 각 스레드를 순회하며 최신 메시지를 가져오고, 일반 텍스트 본문을 추출하고, 첨부된 PDF 파일을 분리합니다.

function processInvoices() {
  const apiKey = PropertiesService.getScriptProperties().getProperty("GEMINI_API_KEY");
  if (!apiKey) {
    throw new Error("GEMINI_API_KEY is missing! Please set it in Script Properties.");
  }

  const threads = GmailApp.search(CONFIG.searchQuery);
  if (threads.length === 0) return;

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const batchData = [];
  const processedThreads = [];

3. 이메일과 멀티모달 PDF 처리

이메일 스레드를 순회하면서 최신 메시지를 가져옵니다. 하지만 송장은 일반 텍스트로 오는 경우가 드뭅니다. 거의 항상 PDF로 첨부됩니다. 

Gemini 2.5 Flash는 네이티브 멀티모달이므로, 스크립트가 latestMessage.getAttachments()를 순회하면서 PDF를 찾아 Base64 문자열로 변환하고, inlineData로 API 페이로드에 직접 전달합니다. 

Gemini는 PDF를 시각적으로 "읽어" 텍스트를 읽는 것만큼 쉽게 데이터를 추출합니다.

for (let i = 0; i < threads.length; i++) {
   const thread = threads[i];
   const latestMessage = thread.getMessages().pop();
  
   const emailBody = latestMessage.getPlainBody();
   const emailDate = latestMessage.getDate();
   const emailLink = https://mail.google.com/mail/u/0/#inbox/${thread.getId()};
   const attachments = latestMessage.getAttachments();
   try {
     const geminiParts = [];
     geminiParts.push({ text: "Extract invoice details from this email and any attached documents:\n\n" + emailBody });
    
     // Add PDF attachments as base64 to the prompt
     for (const attachment of attachments) {
       if (attachment.getContentType() === "application/pdf") {
         geminiParts.push({
           inlineData: {
             mimeType: "application/pdf",
             data: Utilities.base64Encode(attachment.getBytes())
           }
         });
       }
     }
     // Invoke Gemini API
     const extractedData = callGeminiAPI(apiKey, geminiParts);

4. 배치 삽입과 오류 처리

성능 최적화를 위해 스프레드시트에 한 행씩 쓰지 않습니다. 

대신 추출된 JSON 데이터를 배열(batchData)에 모아, 마지막에 setValues()로 한 번에 기록합니다.

try...catch 블록에 주목하세요. 

Gemini가 특정 이메일에서 오류를 내거나 환각을 일으키더라도 스크립트 전체가 중단되지 않습니다. 대신 오류를 우아하게 포착하고 MailApp.sendEmail()로 관리자를 즉시 알리므로 가시성이 높습니다.

 // Push to batch array instead of writing one-by-one
     batchData.push([
       emailDate,
       extractedData.vendor || "Unknown Vendor",
       extractedData.invoiceNumber || "N/A",
       extractedData.totalAmount || 0.00,
       extractedData.currency || "USD",
       extractedData.itemsSummary || "N/A",
       emailLink
     ]);
     processedThreads.push(thread);
   } catch (error) {
     MailApp.sendEmail(CONFIG.adminEmail, "🚨 Invoice Pipeline Error", error.toString());
   }
 }
 // Batch Write to Sheets
 if (batchData.length > 0) {
   const lastRow = Math.max(sheet.getLastRow(), 1);
   sheet.getRange(lastRow + 1, 1, batchData.length, batchData[0].length).setValues(batchData);
 }
 // Mark all processed threads as read so they aren't parsed again
 processedThreads.forEach(t => t.markRead());
}

마지막으로 스크립트는 처리된 모든 이메일에 대해 thread.markRead()를 호출합니다. 이렇게 하면 다음 실행 때 이 이메일들을 완전히 건너뛰고 새 항목만 찾습니다.

5. Gemini API 헬퍼 함수(JSON 모드)

LLM을 호출할 때 개발자들은 종종 "JSON 블록으로 반환하라" 같은 프롬프트 엔지니어링을 사용합니다. 하지만 모델이 자주 대화형 패딩(예: "물론입니다. 요청하신 데이터입니다: [JSON]")을 덧붙여 응답하고, 이로 인해 후속 코드 파서가 크래시 나곤 합니다.

responseMimeType: "application/json"을 설정하고 엄격한 responseSchema를 제공하면, Gemini REST API가 우리 스프레드시트 열 헤더에 정확히 대응하는 보장된 JSON 객체만 반환하도록 강제할 수 있습니다.

function callGeminiAPI(apiKey, partsArray) {
 const url = https://generativelanguage.googleapis.com/v1beta/models/${CONFIG.model}:generateContent?key=${apiKey};
  const responseSchema = {
   type: "OBJECT",
   properties: {
     vendor: { type: "STRING" },
     invoiceNumber: { type: "STRING" },
     totalAmount: { type: "NUMBER" },
     currency: { type: "STRING" },
     itemsSummary: { type: "STRING" }
   },
   required: ["vendor", "totalAmount"]
 };
  const payload = {
   contents: [{ parts: partsArray }],
   generationConfig: {
     responseMimeType: "application/json",
     responseSchema: responseSchema
   }
 };
  const options = {
   method: "POST",
   contentType: "application/json",
   payload: JSON.stringify(payload),
   muteHttpExceptions: true
 };
  const response = UrlFetchApp.fetch(url, options);
 const jsonResponse = JSON.parse(response.getContentText());
  return JSON.parse(jsonResponse.candidates[0].content.parts[0].text);
}

Step 3: Google Apps Script 파이프라인 자동화

코드는 삶을 더 편하게 해 줄 때 비로소 가치가 있습니다. 

Google Apps Script는 인터랙티브한 사용자 버튼부터 완전 헤드리스 백그라운드 크론 작업까지 강력한 실행 환경을 제공합니다.

방법 1: 스프레드시트 UI에서 트리거

비기술적인 회계팀을 위해 이 도구를 만든다면, 오늘의 송장을 처리하려고 Apps Script 코드 편집기를 열고 싶어 하지는 않을 것입니다. 

코드에 onOpen() 함수를 포함했기 때문에, 스프레드시트가 열릴 때마다 Apps Script가 Google 스프레드시트 인터페이스에 자동으로 사용자 지정 메뉴를 바인딩합니다.

  1. Google 스프레드시트로 돌아가 페이지를 새로고침하세요.
  2. 몇 초 기다린 뒤 상단 메뉴를 보면 새 드롭다운 🤖 AI Automations가 보일 것입니다.
  3. 클릭하여 Fetch New Invoices를 선택하세요.

running-the-automation

  1. 처음 실행할 때 Google이 스크립트 권한(사용자 Gmail 읽기 및 사용자를 대신해 이메일 전송)을 요청합니다. 승인하면 스크립트가 실시간으로 실행됩니다. 추출된 JSON 데이터가 행에 채워지는 것을 바로 확인할 수 있습니다!

방법 2: 시간 기반 트리거를 통한 헤드리스 자동화

진정한 세팅 후 방치 자동화를 원한다면, 기본 제공 시간 기반 트리거를 사용해 백그라운드에서 자율적으로 파이프라인을 실행할 수 있습니다.

  1. Apps Script 편집기에서 왼쪽 사이드바의 트리거(시계 아이콘)를 클릭합니다.

Trigger-button

  1. 오른쪽 하단의 트리거 추가를 클릭합니다.

configuring-the-trigger

  1. 함수를 processInvoices로 설정합니다.
  2. 이벤트 소스를 시간 기반으로 변경하고, 시간 타이머(예: 6시간마다)로 실행되도록 설정합니다.
  3. 저장을 클릭합니다.

Trigger-Settings

이제 헤드리스 AI 파이프라인이 완전히 자율적으로 동작합니다.

컴퓨터 전원이 완전히 꺼져 있어도, Google의 서버가 6시간마다 깨어나 받은편지함을 스캔하고, Gemini로 송장을 파싱데이터를 시트에 기록하고 다시 잠자리에 듭니다. 

Apps Script 편집기의 실행 탭에서 로그를 확인해 이러한 백그라운드 실행의 성공 또는 실패를 모니터링할 수 있습니다.

Step 4: AI 데이터 추출 테스트

코드를 배치했으니, 추출 파이프라인이 예상대로 작동하는지 테스트해야 합니다.

두 가지 실전 시나리오를 통해 Gemini API가 서로 다른 데이터 형식을 어떻게 처리하는지, 실제 응답이 어떻게 나오는지 살펴보겠습니다.

테스트 1: 일반 텍스트 이메일 추출

먼저 이메일 본문에 송장이 직접 포함된 경우를 테스트합니다.

  1. 제목을 "Invoice INV-2023-88493"로 하여 본인에게 이메일을 보냅니다.
  2. 본문에는 다음처럼 비정형 텍스트를 작성합니다: "안녕하세요 팀, Q3 소프트웨어 라이선스 비용으로 Acme Corp에 $450.00 USD를 지불해 주세요."
  3. 해당 이메일에 invoices 라벨을 적용하고 읽지 않음 상태로 둡니다.

final-email-output

  1. 사용자 지정 메뉴에서 스크립트를 실행합니다.

백그라운드에서 Gemini는 이 비정형 텍스트를 받고, 우리가 정의한 JSON 스키마를 엄격히 준수합니다. 

대화형 패딩 없이 원시 페이로드를 반환합니다. 

응답이 완벽히 구조화된 JSON이기 때문에, 우리의 batchData.push() 배열은 extractedData.totalAmount를 매끄럽게 읽어들여 6550을 복잡한 Regex 없이 그대로 스프레드시트에 기록합니다.

final-response

테스트 2: PDF 첨부 파일에서 추출

다음으로, PDF 문서를 전달해 Gemini 2.5 Flash의 진가를 시험해 봅시다.

  1. 샘플 PDF 송장을 생성하거나 다운로드하세요(예: ProTech Cloud Services 발 $20,700.00).
  2. 해당 PDF 문서를 자신에게 이메일로 전송합니다. 이메일 본문은 완전히 비워도 됩니다!
  3. invoices 라벨을 적용하고 읽지 않음으로 표시합니다.

email-attachment

  1. 스크립트를 실행합니다. 파이프라인이 첨부 파일을 감지하고 Base64로 변환하며, Gemini가 문서를 시각적으로 읽어 공급업체와 총액을 추출합니다.

final-response

바로 여기서 이 아키텍처의 가치가 입증됩니다. 

사용자 정의 OCR(광학 문자 인식) 로직을 작성하거나, 별도의 PDF 파싱 라이브러리를 관리하거나, 총액을 찾기 위한 정규식을 만들 필요가 전혀 없습니다. 

LLM이 비정형 시각 데이터 처리를 네이티브로 담당합니다.

마무리

비즈니스 워크플로 자동화에 무거운 인프라를 관리하거나 복잡한 인증 루프와 싸울 필요는 없습니다. 

Google Apps Script와 Gemini API를 결합해, 매일 사용하는 클라우드 생태계 안에서 완전히 실행되는 지능형 서버리스 데이터 파이프라인을 구축했습니다.

이 아키텍처의 강점은 단순함에 있습니다. 서버 프로비저닝, 웹후크 구성, 외부 서버의 보안 자격 증명 파일 관리 대신, Apps Script가 컨텍스트, 인증, 실행을 네이티브로 처리합니다. 

한편, Gemini는 취약한 정규식이나 값비싼 OCR 소프트웨어의 필요성을 없애고, 지저분한 이메일 본문과 비정형 PDF를 단 한 번의 API 호출로 예측 가능한 데이터베이스 행으로 변환합니다.

LLM에 프로그래밍 방식으로 접근해 더 많은 것을 구축하고 싶다면, DataCamp의 Introduction to APIs in Python을 살펴보거나, AI Agent Fundamentals 과정에서 지능형 워크플로 설계를 심층적으로 학습해 보세요.

주제

Top DataCamp Courses

courses

Google ADK로 AI 에이전트 만들기

1
6.8K
Google의 Agent Development Kit (ADK)로 고객 지원 어시스턴트를 단계별로 구축하세요.
자세히 보기Right Arrow
강좌 시작
더 보기Right Arrow