Google Apps Script 입문 – 구글 시트·Gmail 자동화 실전 가이드
매일 반복하는 구글 작업, 자동으로 돌릴 수 있다면?
구글 스프레드시트에서 매주 같은 보고서를 복사하고, Gmail에서 같은 형식의 안내 메일을 보내고, 캘린더에 일정을 하나하나 손으로 등록하는 일. 누구나 한 번쯤은 ‘이걸 자동으로 할 수 없을까?’ 하고 생각해 본 적이 있을 겁니다.
그 답이 바로 Google Apps Script입니다. 구글이 무료로 제공하는 자동화 도구인데, 별도 설치 없이 웹 브라우저만 있으면 바로 사용할 수 있습니다. 프로그래밍 경험이 없어도 괜찮습니다. 이 글에서는 복사·붙여넣기만으로 따라 할 수 있는 실전 예제 5가지를 준비했습니다.
Python 자동화나 n8n 같은 도구와 비교하면, Google Apps Script는 구글 서비스와의 연동이 압도적으로 쉽고 서버가 필요 없다는 게 가장 큰 장점입니다. 구글 계정 하나면 바로 시작할 수 있으니까요.

Google Apps Script란 무엇인가
구글이 만든 무료 자동화 플랫폼
Google Apps Script(이하 GAS)는 구글이 제공하는 클라우드 기반 스크립팅 플랫폼입니다. 자바스크립트(JavaScript)를 기반으로 하며, 구글 스프레드시트, Gmail, 캘린더, 드라이브, 폼 등 구글 워크스페이스의 거의 모든 서비스를 프로그래밍 방식으로 제어할 수 있습니다.
가장 중요한 특징은 완전히 무료라는 점입니다. 구글 계정만 있으면 누구나 사용할 수 있고, 별도의 서버를 준비하거나 소프트웨어를 설치할 필요가 없습니다. 코드를 작성하고 실행하는 편집기도 웹 브라우저 안에 내장되어 있어서, 크롬이나 엣지만 열면 바로 시작할 수 있습니다.
다른 자동화 도구와의 차이점
자동화 도구는 이미 많습니다. Python 스크립트, n8n, Zapier, Make(구 Integromat) 등 선택지가 다양한데, GAS가 특별한 이유는 구글 생태계 안에서 가장 자연스럽게 동작한다는 점입니다.
- Python 스크립트: PC에 Python을 설치해야 하고, 구글 API 인증 설정이 별도로 필요합니다. 유연하지만 초기 세팅이 번거롭습니다.
- n8n, Zapier: 노코드로 다양한 서비스를 연결할 수 있지만, 무료 플랜에 실행 횟수 제한이 있고 세밀한 로직 구현이 어렵습니다.
- Google Apps Script: 구글 서비스라면 인증 한 번으로 모든 것에 접근 가능합니다. 무료 실행 한도도 넉넉하고(하루 약 6분 실행 시간, 트리거 20개), 간단한 자동화부터 복잡한 비즈니스 로직까지 커버합니다.
정리하면, 구글 서비스를 주로 사용하는 분이라면 GAS가 가장 효율적인 선택입니다. 특히 회사에서 구글 워크스페이스를 쓰고 있다면, 업무 자동화의 일등 공신이 될 수 있습니다.
GAS로 할 수 있는 것들
구체적으로 어떤 일을 자동화할 수 있는지 몇 가지 예를 들어보겠습니다.
- 스프레드시트 데이터를 기반으로 맞춤 이메일 자동 발송
- 매일 아침 특정 시트의 데이터를 요약해서 슬랙이나 이메일로 알림
- 구글 폼 응답이 들어올 때마다 자동으로 캘린더 일정 생성
- 드라이브 폴더의 파일 목록을 스프레드시트로 자동 정리
- 여러 시트의 데이터를 하나로 합쳐서 보고서 자동 생성
- 외부 API를 호출해서 환율, 날씨 등 실시간 데이터를 시트에 기록
이 정도면 사무직 직장인의 반복 업무 상당 부분을 커버할 수 있다는 게 느껴지시죠?
시작하기: 스크립트 편집기 여는 법
방법 1 – 스프레드시트에서 바로 열기
가장 간단한 방법은 구글 스프레드시트에서 직접 스크립트 편집기를 여는 것입니다.
- 구글 스프레드시트를 하나 엽니다 (새로 만들어도 됩니다).
- 상단 메뉴에서 확장 프로그램 → Apps Script를 클릭합니다.
- 새 탭에 스크립트 편집기가 열립니다.
이렇게 열면 해당 스프레드시트에 바인딩(bound)된 스크립트가 만들어집니다. 이 스크립트에서는 SpreadsheetApp.getActiveSpreadsheet()로 해당 시트에 바로 접근할 수 있어서 편리합니다.
방법 2 – 독립 스크립트로 만들기
특정 문서에 종속되지 않는 독립(standalone) 스크립트를 만들 수도 있습니다.
- 브라우저에서 script.google.com에 접속합니다.
- 왼쪽 상단의 새 프로젝트를 클릭합니다.
독립 스크립트는 여러 구글 서비스를 동시에 다루거나, 웹 앱으로 배포할 때 유용합니다.
편집기 화면 구성 이해하기
스크립트 편집기를 처음 열면 function myFunction() { }이라는 빈 함수가 하나 보입니다. 왼쪽 사이드바에는 파일 목록, 서비스 추가, 트리거 설정 등의 메뉴가 있습니다.
알아두면 좋은 핵심 메뉴들입니다.
- 편집기(코드): 코드를 작성하는 메인 화면입니다.
- 트리거(시계 아이콘): 자동 실행 스케줄을 설정하는 곳입니다. 예를 들어 ‘매일 오전 9시에 실행’ 같은 설정을 여기서 합니다.
- 실행 로그: 스크립트 실행 결과와 에러 메시지를 확인할 수 있습니다.
- 프로젝트 설정: 스크립트 ID 확인, 매니페스트 파일 편집 등 고급 설정을 할 수 있습니다.
처음에는 편집기와 트리거 두 가지만 알면 충분합니다. 나머지는 필요할 때 하나씩 익히면 됩니다.

실전 예제 1: 스프레드시트 데이터로 맞춤 이메일 보내기
어떤 상황에서 쓸까
동아리 회비 안내, 고객 개별 안내 메일, 팀원별 업무 리마인더 등 같은 내용이지만 받는 사람마다 이름이나 금액이 다른 메일을 보내야 할 때가 있습니다. 한두 명이면 직접 보내겠지만, 20명, 50명이 되면 이야기가 달라집니다.
GAS를 사용하면 스프레드시트에 이름, 이메일, 내용을 정리해 두고, 버튼 하나로 전체에게 맞춤 메일을 발송할 수 있습니다.
스프레드시트 준비
먼저 구글 스프레드시트에 아래와 같은 형태로 데이터를 준비합니다.
- A열: 이름 (예: 홍길동)
- B열: 이메일 (예: [email protected])
- C열: 안내 내용 (예: 5월 회비 30,000원)
첫 번째 행은 헤더(이름, 이메일, 내용)로 사용하고, 두 번째 행부터 실제 데이터를 입력합니다.
코드 작성
스프레드시트에서 확장 프로그램 → Apps Script를 열고, 아래 코드를 붙여넣습니다.
function sendCustomEmails() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const data = sheet.getDataRange().getValues();
for (let i = 1; i < data.length; i++) {
const name = data[i][0];
const email = data[i][1];
const content = data[i][2];
const subject = name + '님, 안내 말씀드립니다';
const body = name + '님 안녕하세요,\n\n' + content + '\n\n감사합니다.';
GmailApp.sendEmail(email, subject, body);
}
SpreadsheetApp.getUi().alert('메일 발송이 완료되었습니다!');
}
코드 동작 원리
코드를 한 줄씩 살펴보겠습니다.
- getActiveSpreadsheet().getActiveSheet(): 현재 열려 있는 시트를 가져옵니다.
- getDataRange().getValues(): 시트에 데이터가 있는 전체 범위를 2차원 배열로 읽어옵니다. 예를 들어 data[1][0]은 2행 A열의 값입니다.
- for 루프: i = 1부터 시작하는 이유는 0번째 행이 헤더이기 때문입니다. 1행부터 마지막 행까지 반복합니다.
- GmailApp.sendEmail(): 지정한 이메일 주소로 제목과 본문을 담아 메일을 보냅니다. 이 한 줄로 Gmail 발송이 끝납니다.
- SpreadsheetApp.getUi().alert(): 모든 메일 발송이 끝나면 완료 알림 팝업을 띄웁니다.
실행 방법
코드를 저장(Ctrl+S)한 후 상단의 실행 버튼(▶)을 누릅니다. 처음 실행할 때는 권한 승인 화면이 나옵니다. ‘권한 검토’를 클릭하고 자신의 구글 계정을 선택한 뒤 ‘허용’을 누르면 됩니다.
권한 승인 화면에서 ‘확인되지 않은 앱’이라는 경고가 나올 수 있는데, 이건 본인이 직접 만든 스크립트이기 때문에 걱정할 필요가 없습니다. ‘고급’을 클릭하고 ‘프로젝트로 이동’을 선택하면 됩니다.
응용: HTML 형식 메일 보내기
텍스트만으로는 밋밋하다면, HTML 형식의 메일도 보낼 수 있습니다. GmailApp.sendEmail()의 세 번째 인자 대신 옵션 객체를 사용하면 됩니다.
GmailApp.sendEmail(email, subject, '', {
htmlBody: '<h2>' + name + '님 안녕하세요</h2><p>' + content + '</p>'
});
이렇게 하면 굵은 글씨, 색상, 이미지 삽입 등 다양한 서식을 적용한 메일을 보낼 수 있습니다.
실전 예제 2: 매일 아침 자동 리포트 이메일
시나리오
판매 데이터, 운동 기록, 가계부 등을 스프레드시트로 관리하고 있다면, 매일 아침 전날의 요약을 이메일로 받아보면 편리합니다. GAS의 시간 기반 트리거를 사용하면 이것을 완전 자동으로 만들 수 있습니다.
코드 작성
function sendDailyReport() {
const sheet = SpreadsheetApp.openById('스프레드시트_ID').getSheetByName('매출');
const lastRow = sheet.getLastRow();
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy-MM-dd');
// 마지막 행의 데이터를 당일 요약으로 사용
const date = sheet.getRange(lastRow, 1).getValue();
const totalSales = sheet.getRange(lastRow, 2).getValue();
const orderCount = sheet.getRange(lastRow, 3).getValue();
const subject = '[일일 리포트] ' + today + ' 매출 요약';
const body = '안녕하세요,\n\n' +
'오늘의 매출 요약입니다.\n\n' +
'- 날짜: ' + date + '\n' +
'- 총 매출: ' + totalSales.toLocaleString() + '원\n' +
'- 주문 건수: ' + orderCount + '건\n\n' +
'좋은 하루 되세요!';
GmailApp.sendEmail('내이메일@gmail.com', subject, body);
}
코드 해설
- SpreadsheetApp.openById(): 독립 스크립트에서 특정 스프레드시트를 열 때 사용합니다. 스프레드시트 URL의
/d/와/edit사이에 있는 긴 문자열이 ID입니다. - getSheetByName(‘매출’): ‘매출’이라는 이름의 시트를 선택합니다.
- getLastRow(): 데이터가 입력된 마지막 행 번호를 가져옵니다. 이렇게 하면 데이터가 늘어나도 항상 최신 행을 읽습니다.
- Utilities.formatDate(): 날짜를 원하는 형식으로 변환합니다. 시간대를 ‘Asia/Seoul’로 지정해야 한국 시간 기준으로 표시됩니다.
트리거 설정으로 매일 자동 실행
이 코드를 매일 아침 자동으로 실행하려면 트리거를 설정해야 합니다.
- 스크립트 편집기 왼쪽 사이드바에서 시계 모양 아이콘(트리거)을 클릭합니다.
- 오른쪽 하단의 트리거 추가를 클릭합니다.
- 실행할 함수: sendDailyReport
- 이벤트 소스: 시간 기반
- 시간 기반 트리거 유형: 일 단위 타이머
- 시간대: 오전 7시~8시 (원하는 시간대 선택)
- 저장을 누릅니다.
이제부터 매일 아침 7~8시 사이에 자동으로 리포트 메일이 발송됩니다. 구글 서버에서 실행되기 때문에 내 컴퓨터를 켜놓지 않아도 됩니다. 이것이 GAS의 가장 큰 장점 중 하나입니다.
실전 예제 3: 구글 폼 응답을 캘린더 일정으로 자동 등록
활용 시나리오
팀 회의 일정 신청, 시설 예약, 상담 예약 등을 구글 폼으로 받고 있다면, 응답이 들어올 때마다 자동으로 구글 캘린더에 일정을 생성할 수 있습니다. 수작업으로 옮겨 적는 과정이 완전히 사라집니다.
구글 폼 준비
구글 폼에 아래 항목을 만듭니다.
- 예약자 이름 (단답형)
- 예약 날짜 (날짜 선택)
- 시작 시간 (시간 선택)
- 예약 내용 (단답형)
폼의 응답이 저장되는 스프레드시트에서 확장 프로그램 → Apps Script를 엽니다.
코드 작성
function onFormSubmit(e) {
const responses = e.values;
// responses[0]은 타임스탬프
const name = responses[1];
const dateStr = responses[2];
const timeStr = responses[3];
const description = responses[4];
const startTime = new Date(dateStr + ' ' + timeStr);
const endTime = new Date(startTime.getTime() + 60 * 60 * 1000); // 1시간 후
const calendar = CalendarApp.getDefaultCalendar();
calendar.createEvent(
name + ' - ' + description,
startTime,
endTime,
{ description: '예약자: ' + name + '\n내용: ' + description }
);
}
코드 해설
- onFormSubmit(e): 폼 제출 이벤트가 발생하면 호출되는 함수입니다.
e.values에 폼 응답 값이 배열로 들어옵니다. - CalendarApp.getDefaultCalendar(): 기본 구글 캘린더를 가져옵니다. 다른 캘린더에 등록하고 싶다면
CalendarApp.getCalendarById('캘린더ID')를 사용합니다. - createEvent(): 제목, 시작 시간, 종료 시간, 옵션(설명)을 지정해서 일정을 생성합니다.
트리거 설정
이 함수는 시간 기반이 아니라 이벤트 기반 트리거로 설정해야 합니다.
- 트리거 추가 화면에서 실행할 함수: onFormSubmit
- 이벤트 소스: 스프레드시트에서
- 이벤트 유형: 양식 제출 시
이렇게 설정하면 누군가 폼을 제출할 때마다 자동으로 캘린더에 일정이 등록됩니다. 예약 관리가 이보다 편할 수 있을까요?

실전 예제 4: 드라이브 파일 목록 자동 정리
언제 필요할까
구글 드라이브에 파일이 수백 개씩 쌓이면 어떤 파일이 있는지 파악하기 어렵습니다. 특히 팀 공유 드라이브라면 더욱 그렇습니다. GAS로 특정 폴더의 파일 목록을 스프레드시트에 자동으로 정리할 수 있습니다.
코드 작성
function listDriveFiles() {
const folderId = '폴더_ID_여기에_입력';
const folder = DriveApp.getFolderById(folderId);
const files = folder.getFiles();
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheet.clear();
sheet.appendRow(['파일명', '유형', '크기(KB)', '최종 수정일', '파일 URL']);
while (files.hasNext()) {
const file = files.next();
sheet.appendRow([
file.getName(),
file.getMimeType(),
Math.round(file.getSize() / 1024),
file.getLastUpdated(),
file.getUrl()
]);
}
SpreadsheetApp.getUi().alert(sheet.getLastRow() - 1 + '개 파일 정리 완료!');
}
코드 해설
- DriveApp.getFolderById(): 폴더 ID로 특정 폴더에 접근합니다. 폴더 ID는 드라이브에서 폴더를 열었을 때 URL의
/folders/뒤에 있는 문자열입니다. - folder.getFiles(): 해당 폴더의 모든 파일을 가져오는 이터레이터(반복자)를 반환합니다.
- while (files.hasNext()): 파일이 더 있는 동안 반복합니다.
files.next()로 다음 파일을 하나씩 가져옵니다. - sheet.clear(): 기존 데이터를 지우고 새로 작성합니다. 실행할 때마다 최신 상태로 갱신됩니다.
- appendRow(): 시트 마지막 행 아래에 새 행을 추가합니다.
하위 폴더까지 포함하는 확장 버전
하위 폴더의 파일까지 모두 정리하고 싶다면 재귀 함수를 사용합니다.
function listAllFiles(folder, sheet, depth) {
const files = folder.getFiles();
while (files.hasNext()) {
const file = files.next();
sheet.appendRow([
' '.repeat(depth) + file.getName(),
folder.getName(),
Math.round(file.getSize() / 1024),
file.getLastUpdated()
]);
}
const subFolders = folder.getFolders();
while (subFolders.hasNext()) {
listAllFiles(subFolders.next(), sheet, depth + 1);
}
}
이 함수를 메인 함수에서 listAllFiles(folder, sheet, 0)으로 호출하면 전체 폴더 트리를 시트에 정리할 수 있습니다. 파일 감사(audit)나 용량 정리할 때 특히 유용합니다.
실전 예제 5: 외부 API 연동으로 환율 자동 업데이트
GAS에서 외부 데이터 가져오기
GAS는 구글 서비스뿐 아니라 외부 웹 API에도 접근할 수 있습니다. UrlFetchApp을 사용하면 HTTP 요청을 보내고 응답을 받을 수 있어서, 공개 API에서 데이터를 가져와 스프레드시트에 기록하는 것이 가능합니다.
환율 정보 자동 업데이트 코드
function updateExchangeRate() {
const url = 'https://open.er-api.com/v6/latest/USD';
const response = UrlFetchApp.fetch(url);
const data = JSON.parse(response.getContentText());
const krwRate = data.rates.KRW;
const jpyRate = data.rates.JPY;
const eurRate = data.rates.EUR;
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('환율');
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy-MM-dd');
const lastRow = sheet.getLastRow() + 1;
sheet.getRange(lastRow, 1).setValue(today);
sheet.getRange(lastRow, 2).setValue(krwRate);
sheet.getRange(lastRow, 3).setValue(jpyRate);
sheet.getRange(lastRow, 4).setValue(eurRate);
}
코드 해설
- UrlFetchApp.fetch(url): 지정한 URL로 HTTP GET 요청을 보냅니다. 외부 API와 통신하는 GAS의 핵심 기능입니다.
- JSON.parse(): API 응답은 보통 JSON 형식이므로, 이를 자바스크립트 객체로 변환합니다.
- data.rates.KRW: 변환된 객체에서 원하는 환율 값을 꺼냅니다.
- getRange().setValue(): 특정 셀에 값을 입력합니다.
getRange(행, 열)형태로 셀 위치를 지정합니다.
이 스크립트에 일 단위 트리거를 설정하면, 매일 환율이 자동으로 기록되어 시간에 따른 환율 변동 추이를 한눈에 볼 수 있습니다. 해외 직구를 자주 하거나 해외 투자를 하는 분이라면 아주 유용한 기능입니다.
다른 API 활용 아이디어
같은 방식으로 다양한 공개 API를 연동할 수 있습니다.
- 날씨 API: 매일 아침 오늘의 날씨를 시트에 기록하거나 이메일로 알림
- 주식 API: 관심 종목의 시세를 실시간으로 시트에 업데이트
- 뉴스 API: 특정 키워드가 포함된 뉴스를 자동 수집
- GitHub API: 저장소의 이슈나 PR 상태를 시트로 관리
API 키가 필요한 경우에는 스크립트 속성(Project Settings → Script Properties)에 저장해두면 코드에 직접 노출하지 않아서 안전합니다.

알아두면 좋은 팁과 주의사항
실행 시간 제한
GAS에는 실행 시간 제한이 있습니다. 일반 구글 계정은 스크립트 하나당 최대 6분, 구글 워크스페이스 계정은 최대 30분입니다. 대량의 데이터를 처리할 때는 이 제한을 의식해야 합니다.
6분이 넘을 수 있는 작업은 데이터를 나눠서 처리하거나, 스크립트 속성에 진행 상태를 저장하고 트리거로 이어서 실행하는 방식을 사용합니다.
일일 할당량
무료 계정 기준으로 하루에 보낼 수 있는 이메일은 약 100통, 트리거 실행 총 시간은 약 90분입니다. 일상적인 자동화 용도로는 충분하지만, 대규모 메일 발송 같은 작업에는 제한될 수 있습니다.
디버깅 방법
코드가 예상대로 동작하지 않을 때는 Logger.log()를 사용해서 값을 확인합니다.
Logger.log('현재 값: ' + myVariable);
실행 후 실행 로그 메뉴(Ctrl+Enter)에서 로그 내용을 확인할 수 있습니다. 최신 버전에서는 console.log()도 사용할 수 있으며, 이 경우 Cloud Logging에서 더 자세한 로그를 볼 수 있습니다.
에러 알림 받기
트리거로 자동 실행되는 스크립트가 에러를 일으키면 구글이 자동으로 이메일 알림을 보내줍니다. 트리거 설정에서 ‘실패 알림 설정’을 ‘즉시’로 해두면 문제를 빠르게 파악할 수 있습니다.
보안 주의사항
GAS 코드에 비밀번호나 API 키를 직접 적지 마세요. 대신 스크립트 속성을 사용하세요.
// 속성에 저장 (한 번만 실행)
PropertiesService.getScriptProperties().setProperty('API_KEY', 'your-key-here');
// 코드에서 읽기
const apiKey = PropertiesService.getScriptProperties().getProperty('API_KEY');
스크립트를 다른 사람과 공유할 때 민감한 정보가 노출되는 것을 방지할 수 있습니다.
더 나아가기: GAS 학습 로드맵
1단계: 기본 자동화 (지금 단계)
이 글에서 다룬 예제들을 직접 따라 해보세요. 스프레드시트 읽기/쓰기, 이메일 발송, 트리거 설정만 익히면 일상 업무의 상당 부분을 자동화할 수 있습니다.
2단계: 커스텀 메뉴와 사이드바
스프레드시트에 나만의 메뉴를 추가하거나, 사이드바 UI를 만들어서 팀원들이 코드를 몰라도 버튼 하나로 기능을 실행할 수 있게 만들 수 있습니다.
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('자동화 도구')
.addItem('메일 발송', 'sendCustomEmails')
.addItem('파일 목록 정리', 'listDriveFiles')
.addToUi();
}
onOpen() 함수는 스프레드시트를 열 때 자동으로 실행되는 특수 함수입니다. 이렇게 하면 상단 메뉴에 ‘자동화 도구’라는 항목이 추가되어, 누구나 클릭 한 번으로 기능을 실행할 수 있습니다.
3단계: 웹 앱 배포
GAS로 간단한 웹 페이지를 만들고 URL로 공유할 수도 있습니다. doGet() 함수와 HTML 파일을 조합하면 별도의 웹 서버 없이 웹 앱을 배포할 수 있습니다. 사내 도구, 간단한 대시보드, 데이터 입력 폼 등을 만들 때 활용합니다.
4단계: 외부 서비스 연동
Slack, Notion, 텔레그램 등 외부 서비스의 API와 연동하면 자동화의 범위가 크게 넓어집니다. 예를 들어 스프레드시트 데이터가 업데이트되면 슬랙 채널에 알림을 보내거나, 텔레그램 봇으로 보고서를 전송하는 것이 가능합니다.
마무리: 자동화의 시작은 작은 불편함에서
Google Apps Script는 거창한 개발 프로젝트가 아니라, 일상 속 작은 불편함을 해결하는 도구입니다. 매주 수동으로 만들던 보고서, 하나하나 보내던 안내 메일, 손으로 옮겨 적던 예약 정보. 이런 반복 작업을 하나씩 자동화하다 보면, 어느 순간 시간이 많이 남는 자신을 발견하게 됩니다.
프로그래밍을 전혀 몰라도 괜찮습니다. 이 글의 코드를 그대로 복사해서 시트 구조만 맞추면 바로 동작합니다. 그리고 한 번 맛을 보면 ‘이것도 자동화할 수 있지 않을까?’ 하는 생각이 꼬리를 물게 됩니다.
오늘 당장 구글 스프레드시트를 하나 열고, 확장 프로그램 → Apps Script를 클릭해 보세요. 여러분의 첫 번째 자동화가 거기서 시작됩니다.
이미지는 Leonardo AI 로 생성되었습니다.
이미지는 Claude AI 로 생성되었습니다.


