Gmail 검색 조건으로 문의 메일을 찾고, 필요한 정보를 구글시트에 기록한 뒤 처리 완료 표시까지 자동화하는 흐름입니다.
Gmail로 들어오는 문의 메일을 매번 열어 보고, 보낸 사람과 제목을 복사해서 구글시트에 붙여넣는 일은 생각보다 시간이 많이 듭니다. 하루에 몇 건이면 괜찮지만, 문의가 꾸준히 쌓이면 누락, 중복 기록, 처리 상태 혼선이 생기기 쉽습니다.
Google Apps Script를 사용하면 Gmail에서 특정 조건에 맞는 메일을 검색하고, 날짜·보낸 사람·이메일·제목·본문 일부를 Google Sheets에 자동 저장할 수 있습니다. 여기에 처리 완료 라벨까지 붙이면 이미 기록한 메일을 다시 저장하지 않도록 관리할 수 있습니다.
Gmail 자동화로 줄일 수 있는 반복 업무
이번 자동화는 고객 문의, 제휴 문의, 견적 요청, 신청 메일처럼 일정한 형식으로 들어오는 메일을 구글시트에 정리하는 데 적합합니다. 메일함에서 하나씩 확인하던 일을 줄이고, 시트에서 접수 현황을 한눈에 볼 수 있게 만드는 것이 핵심입니다.
| 수동 작업 | 자동화 후 | 효과 |
|---|---|---|
| 문의 메일 검색 | Gmail 검색 조건으로 자동 조회 | 확인 시간 단축 |
| 보낸 사람·제목 복사 | Apps Script가 메일 정보 추출 | 입력 실수 감소 |
| 구글시트에 붙여넣기 | 행 단위로 자동 저장 | 누락 방지 |
| 처리 여부 기억 | 처리 완료 라벨 적용 | 중복 저장 방지 |
오늘 만들 자동화 흐름
Gmail 검색, 메일 정보 추출, 구글시트 저장, 처리 완료 라벨 적용 순서로 이어지는 자동화 흐름입니다.
전체 흐름은 단순합니다. Gmail에서 문의 메일을 검색하고, 각 메일의 기본 정보를 가져온 뒤, Google Sheets에 저장합니다. 저장이 끝난 메일에는 Gmail 라벨을 붙여 다음 실행 때 다시 처리되지 않게 합니다.
자동화 흐름
Gmail 검색 → 메일 정보 추출 → 구글시트 기록 → 처리 완료 라벨 적용 순서로 움직입니다. 처음에는 수동 실행으로 결과를 확인하고, 문제가 없을 때 시간 기반 트리거를 연결하는 방식이 안전합니다.
이 방식이 잘 맞는 경우
메일 제목에 “문의”, “제휴”, “견적”, “신청” 같은 단어가 자주 들어가거나, 특정 발신자·라벨·기간을 기준으로 메일을 구분할 수 있다면 적용하기 좋습니다. 반대로 문의 메일 형식이 너무 다양하면 처음부터 넓은 조건으로 자동화하기보다 Gmail 라벨을 먼저 정리한 뒤 시작하는 편이 좋습니다.
Google Apps Script를 처음 다룬다면 기본 개념을 먼저 확인한 뒤 실습하면 이해가 더 쉽습니다. 구글시트 중심의 기초 흐름은 Google Apps Script 자동화 입문: 구글시트 반복 작업 줄이는 법에서 이어서 볼 수 있습니다.
준비물
별도 서버나 유료 자동화 도구 없이 Google 계정 안에서 시작할 수 있습니다. 다만 Gmail과 구글시트의 개인 데이터에 접근하므로 처음 실행할 때 권한 승인이 필요합니다.
| 준비물 | 용도 | 확인할 점 |
|---|---|---|
| Gmail | 문의 메일 검색 | 검색 조건을 좁게 설정 |
| Google Sheets | 메일 정보 저장 | 시트 ID 확인 |
| Google Apps Script | Gmail과 Sheets 연결 | 권한 승인 필요 |
구글시트 컬럼 만들기
먼저 Google Sheets에서 새 스프레드시트를 만들고, 첫 번째 행에 컬럼명을 넣습니다. 자동화는 이 컬럼 순서에 맞춰 데이터를 저장하므로 처음부터 단순하게 시작하는 것이 좋습니다.
수집일시 | 메일날짜 | 보낸사람 | 이메일 | 제목 | 본문요약 | 메일ID | 처리상태여기서 메일ID는 중복 저장을 막는 기준으로 사용합니다. 같은 제목의 문의가 여러 번 들어올 수 있으므로 제목만으로 중복 여부를 판단하면 안 됩니다. Gmail 메시지의 고유 ID를 함께 저장해야 나중에 같은 메일이 반복 기록되는 문제를 줄일 수 있습니다.
Apps Script 코드 작성
구글시트 상단 메뉴에서 확장 프로그램 → Apps Script를 열고 아래 코드를 붙여넣습니다. 코드에서 SPREADSHEET_ID와 GMAIL_SEARCH_QUERY만 자신의 환경에 맞게 바꾸면 됩니다.
const SPREADSHEET_ID = '여기에_구글시트_ID를_입력하세요';
const SHEET_NAME = '문의메일';
const DONE_LABEL_NAME = '자동정리완료';
const GMAIL_SEARCH_QUERY = 'subject:문의 newer_than:7d -label:자동정리완료';
function saveInquiryEmailsToSheet() {
const sheet = getOrCreateSheet_();
prepareHeader_(sheet);
const existingIds = getExistingMessageIds_(sheet);
const doneLabel = getOrCreateGmailLabel_(DONE_LABEL_NAME);
const threads = GmailApp.search(GMAIL_SEARCH_QUERY, 0, 30);
const rows = [];
threads.forEach(thread => {
const messages = thread.getMessages();
messages.forEach(message => {
const messageId = message.getId();
if (existingIds.has(messageId)) {
return;
}
const from = message.getFrom();
const email = extractEmail_(from);
const subject = message.getSubject();
const mailDate = message.getDate();
const plainBody = message.getPlainBody();
const summary = plainBody.replace(/\s+/g, ' ').trim().slice(0, 200);
rows.push([
new Date(),
mailDate,
from,
email,
subject,
summary,
messageId,
'시트 저장 완료'
]);
existingIds.add(messageId);
});
thread.addLabel(doneLabel);
});
if (rows.length > 0) {
sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows);
}
}
function getOrCreateSheet_() {
const spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
let sheet = spreadsheet.getSheetByName(SHEET_NAME);
if (!sheet) {
sheet = spreadsheet.insertSheet(SHEET_NAME);
}
return sheet;
}
function prepareHeader_(sheet) {
const headers = ['수집일시', '메일날짜', '보낸사람', '이메일', '제목', '본문요약', '메일ID', '처리상태'];
const firstRow = sheet.getRange(1, 1, 1, headers.length).getValues()[0];
const hasHeader = firstRow.some(value => value !== '');
if (!hasHeader) {
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
sheet.setFrozenRows(1);
}
}
function getExistingMessageIds_(sheet) {
const lastRow = sheet.getLastRow();
if (lastRow < 2) {
return new Set();
}
const messageIdColumn = 7;
const values = sheet.getRange(2, messageIdColumn, lastRow - 1, 1).getValues();
return new Set(values.flat().filter(String));
}
function getOrCreateGmailLabel_(labelName) {
const existingLabel = GmailApp.getUserLabelByName(labelName);
if (existingLabel) {
return existingLabel;
}
return GmailApp.createLabel(labelName);
}
function extractEmail_(fromText) {
const match = fromText.match(/<(.+?)>/);
if (match && match[1]) {
return match[1];
}
return fromText;
}구글시트 ID 찾는 방법
구글시트를 열면 주소창에 긴 URL이 보입니다. 그중 /d/와 /edit 사이에 있는 값이 스프레드시트 ID입니다.
https://docs.google.com/spreadsheets/d/여기가_스프레드시트_ID입니다/editGmail 검색 조건 설정하기
자동화의 정확도는 Gmail 검색 조건에서 결정됩니다. 조건이 너무 넓으면 필요 없는 메일까지 저장되고, 너무 좁으면 실제 문의 메일을 놓칠 수 있습니다. 처음에는 최근 7일 또는 30일처럼 기간을 제한한 뒤 테스트하는 것이 좋습니다.
| 검색 조건 | 예시 | 사용 상황 |
|---|---|---|
| 제목 기준 | subject:문의 |
문의 제목이 일정할 때 |
| 발신자 기준 | from:example.com |
특정 서비스 알림 메일 정리 |
| 라벨 기준 | label:문의 |
Gmail 필터로 미리 분류할 때 |
| 기간 기준 | newer_than:7d |
최근 메일만 처리할 때 |
| 제외 조건 | -label:자동정리완료 |
이미 처리한 메일 제외 |
예를 들어 제휴 문의만 저장하고 싶다면 아래처럼 바꿀 수 있습니다.
const GMAIL_SEARCH_QUERY = 'subject:제휴 newer_than:30d -label:자동정리완료';문의 라벨이 붙은 메일만 정리하고 싶다면 Gmail 필터를 먼저 만든 뒤 아래처럼 사용할 수 있습니다.
const GMAIL_SEARCH_QUERY = 'label:문의 newer_than:30d -label:자동정리완료';중복 저장을 방지하는 방법
Gmail 자동화에서 가장 흔한 문제는 같은 메일이 여러 번 시트에 저장되는 것입니다. 이를 막으려면 최소 두 가지 장치를 함께 쓰는 것이 좋습니다.
1. 메일ID를 시트에 저장하기
코드에서는 message.getId()로 Gmail 메시지 ID를 가져와 시트의 메일ID 컬럼에 저장합니다. 다음 실행 때 이미 저장된 ID인지 확인하므로 같은 메시지가 다시 기록될 가능성을 줄일 수 있습니다.
2. 처리 완료 라벨 붙이기
저장이 끝난 스레드에는 자동정리완료 라벨을 붙입니다. Gmail 검색 조건에 -label:자동정리완료를 넣어 두면 이미 처리된 스레드를 다시 검색하지 않습니다.
주의할 점
라벨은 스레드 단위로 붙고, 메일ID는 메시지 단위로 저장됩니다. 문의가 같은 스레드 안에서 계속 오가는 업무라면 최신 답장까지 모두 저장할지, 첫 문의만 저장할지 기준을 정한 뒤 코드를 조정하는 것이 좋습니다.
자동 실행 트리거 설정하기
코드가 정상 작동하는지 먼저 수동으로 실행해 본 뒤 자동 실행 트리거를 설정합니다. Apps Script 화면 왼쪽의 시계 모양 트리거 메뉴에서 새 트리거를 추가하면 됩니다.
- 실행할 함수 선택:
saveInquiryEmailsToSheet - 이벤트 소스 선택: 시간 기반
- 시간 기반 트리거 유형 선택: 분 단위, 시간 단위, 일 단위 중 선택
- 실행 간격 선택: 처음에는 1시간마다 또는 하루 1회 권장
- 저장 후 권한 승인: Google 계정으로 접근 권한 확인
문의가 많지 않은 블로그, 소규모 서비스, 개인 업무라면 5분마다 실행할 필요는 없습니다. 너무 잦은 실행은 할당량 문제를 만들 수 있으므로 업무량에 맞춰 간격을 조정하는 것이 좋습니다.
자주 나는 오류와 해결 방법
처음 실행할 때 오류가 나더라도 대부분은 권한, 시트 ID, 검색 조건, 실행량 문제입니다. 아래 순서대로 확인하면 원인을 좁히기 쉽습니다.
| 오류 상황 | 주요 원인 | 해결 방법 |
|---|---|---|
| 권한 승인 화면이 뜸 | Gmail·Sheets 접근 권한 필요 | 계정 확인 후 권한 승인 |
| 시트를 찾을 수 없음 | 스프레드시트 ID 오류 | /d/와 /edit 사이 값 재확인 |
| 메일이 저장되지 않음 | 검색 조건이 너무 좁음 | Gmail 검색창에서 조건 먼저 테스트 |
| 같은 메일이 반복 저장됨 | 메일ID 컬럼 누락 또는 라벨 미적용 | 메일ID 저장 여부와 라벨명 확인 |
| 실행 시간이 길어짐 | 검색 결과가 너무 많음 | 기간 제한과 검색 개수 축소 |
권한·개인정보 주의점
Gmail 자동화는 개인 메일함의 내용을 읽어오는 작업입니다. 따라서 업무용 계정과 개인 계정을 구분하고, 시트 공유 범위를 최소화하는 것이 좋습니다. 특히 고객 이메일, 문의 내용, 전화번호, 계약 관련 문구가 포함될 수 있다면 공유 권한을 더 신중하게 설정해야 합니다.
- 개인 Gmail보다 업무용 Gmail 또는 전용 문의 계정에서 먼저 테스트합니다.
- 구글시트 공유 대상은 실제로 처리해야 하는 사람으로 제한합니다.
- 본문 전체를 저장하기보다 필요한 일부 요약만 저장합니다.
- 퇴사자, 외부 협력자, 임시 계정의 접근 권한을 정기적으로 확인합니다.
- 민감한 정보가 포함되는 업종이라면 내부 보관 기준에 맞춰 컬럼을 줄입니다.
처음 적용할 때의 기준
자동화는 넓게 시작하는 것보다 작게 시작하는 편이 안전합니다. 최근 7일, 제목에 문의가 포함된 메일, 최대 30개 처리처럼 범위를 제한한 뒤 결과가 맞는지 확인하고 확장하는 흐름이 좋습니다.
Make나 n8n과 비교하면 언제 Apps Script가 좋을까
Apps Script는 Gmail과 Google Sheets 안에서 끝나는 자동화에 잘 맞습니다. 별도 도구에 계정을 연결하지 않아도 되고, 간단한 JavaScript 코드만으로 구글 서비스끼리 연결할 수 있기 때문입니다.
반면 여러 외부 서비스와 연결하거나, 화면에서 노드를 조립하며 흐름을 관리하고 싶다면 Make나 n8n이 더 편할 수 있습니다. RSS, API, 웹훅, 데이터 변환이 섞이는 자동화라면 Make 자동화 예시: RSS 글을 구글시트에 자동 저장하는 법처럼 노코드 도구를 함께 비교해 보는 것도 좋습니다.
공식 자료로 더 확인하기
Gmail과 Google Sheets 자동화는 계정 권한, 실행 트리거, 서비스별 메서드의 영향을 받습니다. 실제 업무에 적용하기 전에는 공식 문서에서 Gmail 검색, 시트 저장, 자동 실행 기준을 확인하는 것이 좋습니다.
Apps Script에서 Gmail 메일을 검색하고, 스레드·메시지·라벨을 다루는 기본 메서드를 확인할 수 있습니다.
GmailApp 검색과 라벨 처리 메서드 확인하기Apps Script에서 Google Sheets 파일을 열고, 시트와 범위에 데이터를 쓰는 방식의 기준을 확인할 수 있습니다.
Google Sheets 접근과 저장 방식 확인하기시간 기반 트리거로 함수를 자동 실행하는 방법과 설치형 트리거의 제한 사항을 확인할 수 있습니다.
시간 기반 자동 실행 트리거 기준 확인하기함께 보면 좋은 글
자주 묻는 질문
Gmail 자동화는 검색 조건을 좁게 잡고, 메일ID와 처리 완료 라벨로 중복을 막는 것부터 시작하면 안정적으로 운영할 수 있습니다.
댓글