상세 컨텐츠

본문 제목

구글 시트 재고 부족 알림 자동화, 소규모 사업자도 무료로 만들기 (2026 최신판)

AI 활용 사례 & 응용 🚀

by AI JB 2026. 7. 30. 06:00

본문

한 줄 요약

구글 시트의 현재재고가 안전재고 이하로 떨어지면 담당자 이메일로 부족 상품을 알리고, Gemini가 공급처에 보낼 발주 문의 초안까지 작성하는 자동화입니다.

안녕하세요.
IT세상입니다. 😊

상품이나 사무용품을 관리하다 보면 꼭 필요한 물건이 모두 떨어진 뒤에야 재고 부족을 발견하는 경우가 있습니다.

이번 글에서는 구글 시트에 입력한 현재재고가 안전재고 이하로 떨어지면 담당자에게 이메일을 보내는 자동화를 만들어 보겠습니다.

부족한 상품이 발견되면 Gemini가 공급처에 보낼 발주 문의 초안도 작성합니다. 다만 잘못된 수량으로 주문되는 일을 막기 위해 공급처에는 자동으로 보내지 않습니다. 담당자가 수량과 조건을 확인할 수 있도록 검토용 초안만 전달합니다.

왜 재고 부족 알림 자동화가 필요할까?

복사용지, 포장 테이프, 택배 상자, 프린터 토너처럼 자주 사용하는 물품은 하루만 늦게 주문해도 업무가 멈출 수 있습니다.

그렇다고 매일 재고관리 시트를 열고 모든 상품 수량을 하나씩 확인하는 것도 번거롭습니다.

구글 시트 재고 부족 알림 자동화를 만들어 두면 현재재고가 기준 이하로 내려간 상품만 자동으로 찾을 수 있습니다.

재고가 완전히 소진된 상품은 긴급으로 표시하고, 아직 조금 남아 있지만 안전재고의 절반 이하인 상품은 높은 우선순위로 구분할 수 있습니다.

이번 자동화에서 AI는 재고 부족 여부를 판단하지 않습니다. 현재재고와 안전재고의 숫자를 비교하는 일은 코드가 담당합니다. AI는 이미 부족하다고 확인된 상품을 바탕으로 발주 문의 문장을 작성하는 역할만 합니다.

이 글에서 알 수 있는 내용

  • 구글 시트에 재고관리 표를 자동으로 만드는 방법
  • 현재재고와 안전재고를 비교하는 원리
  • 한 시간마다 재고를 확인하는 트리거 설정
  • Gemini API로 발주 문의 초안을 만드는 방법
  • 담당자 이메일로 부족 상품 목록을 보내는 방법
  • 같은 상품의 중복 알림을 막는 방법
  • 재고가 보충됐을 때 상태를 자동 초기화하는 방법
  • API 오류가 나도 기본 초안으로 알림을 보내는 방법

완성되는 자동화 결과

현재재고 입력 안전재고와 비교 부족 상품 추출 AI 발주 초안 담당자 이메일

자동화가 완성되면 다음 순서로 작동합니다.

  1. 구글 시트에 상품별 현재재고와 안전재고를 입력합니다.
  2. Apps Script가 한 시간마다 재고관리 시트를 확인합니다.
  3. 현재재고가 안전재고 이하인 상품만 찾습니다.
  4. 현재재고가 0개면 긴급으로 표시합니다.
  5. 안전재고의 절반 이하로 내려가면 높음으로 표시합니다.
  6. Gemini가 공급처에 보낼 발주 문의 초안을 작성합니다.
  7. 부족한 상품을 최대 30개까지 한 통의 이메일로 묶어 담당자에게 보냅니다.
  8. 전송이 끝난 상품은 알림완료 상태로 변경합니다.
  9. 현재재고가 다시 안전재고보다 많아지면 정상 상태로 초기화합니다.
자동 발주는 하지 않습니다.

상품 가격, 납기일, 최소주문수량과 실제 공급 가능 여부는 AI가 확인할 수 없습니다. 이번 자동화는 담당자에게 검토용 문장만 전달합니다.

자동화 준비물

  • 개인 구글 계정
  • Google Sheets
  • Google Apps Script
  • Google AI Studio에서 생성한 Gemini API 키
  • 재고 부족 알림을 받을 이메일 주소
  • 관리할 상품명과 현재재고 정보

Gemini API 키를 입력하지 않아도 재고 부족 이메일은 받을 수 있습니다.

API 키가 없거나 Gemini 요청에 실패하면 코드에 미리 작성된 기본 발주 문의 초안이 사용됩니다. 따라서 AI 서비스에 일시적인 문제가 생겨도 재고 부족 사실은 확인할 수 있습니다.

재고관리 표는 어떻게 구성될까?

항목 입력하거나 표시되는 내용
상품코드 같은 이름의 상품을 구분할 고유 코드
상품명 관리할 상품이나 소모품 이름
현재재고 현재 실제로 남아 있는 수량
안전재고 발주 검토를 시작할 기준 수량
권장발주수량 담당자가 미리 정한 주문 검토 수량
공급처 상품을 구매하는 업체 이름
알림상태 정상, 알림완료 또는 확인필요
우선순위 긴급, 높음 또는 보통
AI발주초안 공급처에 보내기 전에 검토할 문의 문장
마지막알림 담당자에게 이메일을 보낸 시간

Apps Script로 재고 부족 알림 만들기

1단계. 새 구글 스프레드시트 만들기

  1. 구글 드라이브에 접속합니다.
  2. 왼쪽 위의 새로 만들기를 클릭합니다.
  3. Google 스프레드시트를 선택합니다.
  4. 파일 이름을 AI 재고 부족 알림으로 변경합니다.
여기까지 완료했다면

스프레드시트 왼쪽 위에 ‘AI 재고 부족 알림’이라는 파일 이름이 표시됩니다.

2단계. Apps Script 편집기 열기

  1. 스프레드시트 상단의 확장 프로그램을 클릭합니다.
  2. Apps Script를 선택합니다.
  3. 기본으로 들어 있는 코드를 모두 지웁니다.
  4. 프로젝트 이름을 AI 재고 알림 자동화로 변경합니다.
여기까지 완료했다면

Apps Script 편집기에 비어 있는 코드 입력 화면이 표시됩니다.

3단계. 전체 자동화 코드 붙여 넣기

아래 코드를 처음부터 끝까지 복사해 Apps Script 편집기에 붙여 넣습니다.

재고 부족 알림 전체 코드
const CONFIG = Object.freeze({
  MODEL: 'gemini-3.5-flash-lite',
  TIMEZONE: 'Asia/Seoul',
  SHEET_NAME: '재고관리',
  SPREADSHEET_ID_KEY: 'INVENTORY_SPREADSHEET_ID',
  API_KEY: 'GEMINI_API_KEY',
  NOTIFY_EMAIL: 'NOTIFY_EMAIL',
  MAX_ITEMS_PER_EMAIL: 30,
  COLUMNS: Object.freeze({
    code: 1,
    name: 2,
    current: 3,
    safety: 4,
    orderQty: 5,
    supplier: 6,
    status: 7,
    priority: 8,
    aiDraft: 9,
    lastAlert: 10
  })
});

function setupInventoryAutomation() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const properties = PropertiesService.getScriptProperties();

properties.setProperty(
CONFIG.SPREADSHEET_ID_KEY,
spreadsheet.getId()
);

let sheet = spreadsheet.getSheetByName(CONFIG.SHEET_NAME);

if (!sheet) {
sheet = spreadsheet.insertSheet(CONFIG.SHEET_NAME);
}

const headers = [
'상품코드',
'상품명',
'현재재고',
'안전재고',
'권장발주수량',
'공급처',
'알림상태',
'우선순위',
'AI발주초안',
'마지막알림'
];

sheet
.getRange(1, 1, 1, headers.length)
.setValues([headers])
.setFontWeight('bold')
.setBackground('#dbeafe');

sheet.setFrozenRows(1);
sheet.getRange('C:E').setNumberFormat('0');
sheet.getRange('J:J').setNumberFormat('yyyy-mm-dd hh:mm');

const widths = [
110,
220,
100,
100,
120,
180,
110,
100,
420,
150
];

widths.forEach(function(width, index) {
sheet.setColumnWidth(index + 1, width);
});

const statusValidation = SpreadsheetApp
.newDataValidation()
.requireValueInList(
['정상', '알림완료', '확인필요'],
true
)
.setAllowInvalid(false)
.build();

sheet
.getRange(
2,
CONFIG.COLUMNS.status,
Math.max(sheet.getMaxRows() - 1, 1),
1
)
.setDataValidation(statusValidation);

if (sheet.getLastRow() === 1) {
sheet
.getRange(2, 1, 3, headers.length)
.setValues([
[
'A-001',
'A4 복사용지',
2,
5,
10,
'사무용품 공급처',
'정상',
'',
'',
''
],
[
'B-002',
'검정 볼펜',
18,
10,
20,
'문구 공급처',
'정상',
'',
'',
''
],
[
'C-003',
'포장 테이프',
0,
4,
12,
'포장재 공급처',
'정상',
'',
'',
''
]
]);
}

sheet
.getRange(1, 1, sheet.getMaxRows(), headers.length)
.setVerticalAlignment('top')
.setWrap(true);

deleteExistingTrigger_();

ScriptApp
.newTrigger('checkLowStock')
.timeBased()
.everyHours(1)
.create();

spreadsheet.toast(
'재고관리 시트와 1시간 자동 실행 설정을 만들었습니다.',
'설정 완료',
6
);
}

function checkLowStock() {
const lock = LockService.getScriptLock();

if (!lock.tryLock(10000)) {
return;
}

try {
const sheet = getInventorySheet_();
const lastRow = sheet.getLastRow();

```
if (lastRow < 2) {
  return;
}

const rowCount = lastRow - 1;
const data = sheet
  .getRange(2, 1, rowCount, 10)
  .getValues();

const lowStockItems = [];

data.forEach(function(row, index) {
  const rowNumber = index + 2;
  const code = String(row[0] || '').trim();
  const name = String(row[1] || '').trim();

  if (!code && !name) {
    return;
  }

  const currentRaw = row[2];
  const safetyRaw = row[3];
  const orderQtyRaw = row[4];
  const current = Number(currentRaw);
  const safety = Number(safetyRaw);
  const orderQty = Number(orderQtyRaw);
  const status = String(row[6] || '').trim();

  if (
    currentRaw === '' ||
    safetyRaw === '' ||
    !Number.isFinite(current) ||
    !Number.isFinite(safety)
  ) {
    row[6] = '확인필요';
    row[7] = '';
    row[8] = '현재재고와 안전재고를 숫자로 입력하세요.';
    row[9] = '';
    return;
  }

  if (current > safety) {
    row[6] = '정상';
    row[7] = '';
    row[8] = '';
    row[9] = '';
    return;
  }

  if (status === '알림완료') {
    return;
  }

  lowStockItems.push({
    rowNumber: rowNumber,
    code: code || '코드 없음',
    name: name || '상품명 없음',
    current: current,
    safety: safety,
    orderQty:
      Number.isFinite(orderQty) && orderQty > 0
        ? orderQty
        : '확인 필요',
    supplier: String(row[5] || '확인 필요').trim(),
    priority: getPriority_(current, safety)
  });
});

sheet
  .getRange(2, 1, rowCount, 10)
  .setValues(data);

if (lowStockItems.length === 0) {
  return;
}

const itemsToSend = lowStockItems.slice(
  0,
  CONFIG.MAX_ITEMS_PER_EMAIL
);

const draft = createOrderDraft_(itemsToSend);

sendAlertEmail_(
  itemsToSend,
  draft,
  sheet.getParent().getUrl()
);

const now = new Date();

itemsToSend.forEach(function(item) {
  sheet
    .getRange(item.rowNumber, 7, 1, 4)
    .setValues([
      [
        '알림완료',
        item.priority,
        draft,
        now
      ]
    ]);
});
```

} finally {
lock.releaseLock();
}
}

function createOrderDraft_(items) {
const fallback = buildFallbackDraft_(items);

const apiKey = PropertiesService
.getScriptProperties()
.getProperty(CONFIG.API_KEY);

if (!apiKey) {
return '[기본 초안]\n' + fallback;
}

const safeItems = items.map(function(item) {
return {
code: item.code,
name: item.name,
current: item.current,
safety: item.safety,
orderQty: item.orderQty,
supplier: item.supplier,
priority: item.priority
};
});

const prompt = [
'너는 재고 부족 상품의 발주 문의 이메일 초안을 작성한다.',
'',
'아래 데이터에 있는 사실만 사용한다.',
'가격, 납기일, 할인, 최소주문수량을 만들지 않는다.',
'공급처에 바로 전송되는 문장이 아니라 담당자가 검토할 초안이다.',
'정중한 한국어 이메일 본문만 작성한다.',
'',
'[반드시 포함할 내용]',
'- 부족한 품목의 상품명과 상품코드',
'- 권장발주수량',
'- 공급 가능 여부 문의',
'- 예상 납기와 가격 조건 확인 요청',
'- 내부 확인 후 최종 수량을 확정한다는 안내',
'',
'[재고 부족 상품]',
JSON.stringify(safeItems)
].join('\n');

const url =
'https://generativelanguage.googleapis.com/' +
'v1beta/models/' +
CONFIG.MODEL +
':generateContent';

const payload = {
contents: [
{
role: 'user',
parts: [
{
text: prompt
}
]
}
],
generationConfig: {
maxOutputTokens: 700
}
};

try {
const response = UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
headers: {
'x-goog-api-key': apiKey
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
});

```
if (response.getResponseCode() !== 200) {
  return '[기본 초안]\n' + fallback;
}

const result = JSON.parse(response.getContentText());
const parts =
  result.candidates &&
  result.candidates[0] &&
  result.candidates[0].content &&
  result.candidates[0].content.parts;

if (!parts || parts.length === 0) {
  return '[기본 초안]\n' + fallback;
}

const text = parts
  .map(function(part) {
    return part.text || '';
  })
  .join('')
  .trim();

return text
  ? '[AI 생성]\n' + text
  : '[기본 초안]\n' + fallback;
```

} catch (error) {
return '[기본 초안]\n' + fallback;
}
}

function sendAlertEmail_(items, draft, spreadsheetUrl) {
const email = PropertiesService
.getScriptProperties()
.getProperty(CONFIG.NOTIFY_EMAIL);

if (!email) {
throw new Error(
'NOTIFY_EMAIL이 없습니다. 스크립트 속성을 확인하세요.'
);
}

if (MailApp.getRemainingDailyQuota() < 1) {
throw new Error(
'오늘 사용할 수 있는 이메일 발송 한도가 없습니다.'
);
}

const itemList = items
.map(function(item, index) {
return [
index + 1 + '. ' + item.name + ' (' + item.code + ')',
'현재재고: ' + item.current,
'안전재고: ' + item.safety,
'권장발주수량: ' + item.orderQty,
'우선순위: ' + item.priority,
'공급처: ' + item.supplier
].join(' / ');
})
.join('\n');

const body = [
'재고 부족 상품이 확인되었습니다.',
'',
itemList,
'',
'[발주 문의 초안]',
draft,
'',
'재고관리 시트:',
spreadsheetUrl,
'',
'주의: 수량, 가격과 납기를 확인한 뒤 사용하세요.'
].join('\n');

MailApp.sendEmail({
to: email,
subject:
'[재고 부족] ' +
items.length +
'개 상품 확인 필요',
body: body,
name: 'AI 재고 알림'
});
}

function getPriority_(current, safety) {
if (current <= 0) {
return '긴급';
}

if (safety > 0 && current <= safety / 2) {
return '높음';
}

return '보통';
}

function buildFallbackDraft_(items) {
const lines = items.map(function(item) {
return (
'- ' +
item.name +
' (' +
item.code +
'), 권장발주수량: ' +
item.orderQty
);
});

return [
'안녕하세요.',
'',
'아래 품목의 재고가 안전재고 이하로 확인되어',
'공급 가능 여부를 문의드립니다.',
'',
lines.join('\n'),
'',
'예상 납기와 가격 조건을 회신 부탁드립니다.',
'수량과 조건은 내부 검토 후 최종 확정하겠습니다.',
'',
'감사합니다.'
].join('\n');
}

function getInventorySheet_() {
const spreadsheetId = PropertiesService
.getScriptProperties()
.getProperty(CONFIG.SPREADSHEET_ID_KEY);

if (!spreadsheetId) {
throw new Error(
'setupInventoryAutomation을 먼저 실행하세요.'
);
}

const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
const sheet = spreadsheet.getSheetByName(CONFIG.SHEET_NAME);

if (!sheet) {
throw new Error('재고관리 시트를 찾지 못했습니다.');
}

return sheet;
}

function deleteExistingTrigger_() {
ScriptApp
.getProjectTriggers()
.forEach(function(trigger) {
if (
trigger.getHandlerFunction() ===
'checkLowStock'
) {
ScriptApp.deleteTrigger(trigger);
}
});
}

function testInventoryAlert() {
checkLowStock();
}

코드를 붙여 넣은 뒤 위쪽의 디스크 모양 저장 버튼을 클릭합니다.

여기까지 완료했다면

코드가 저장되고 편집기 왼쪽에 빨간 오류 표시가 나타나지 않습니다.

4단계. Gemini API 키 만들기

  1. Google AI Studio를 엽니다.
  2. 자동화에 사용할 구글 계정으로 로그인합니다.
  3. API Keys 또는 Get API key 메뉴를 엽니다.
  4. 새 API 키가 필요하면 Create API key를 클릭합니다.
  5. 생성된 API 키를 복사합니다.
API 키는 비밀번호처럼 관리하세요.

API 키를 블로그 본문, 공개 문서 또는 캡처 이미지에 노출하면 안 됩니다.

5단계. API 키와 알림 이메일 저장하기

  1. Apps Script 화면으로 돌아갑니다.
  2. 왼쪽의 톱니바퀴 모양 프로젝트 설정을 클릭합니다.
  3. 화면 아래쪽의 스크립트 속성을 찾습니다.
  4. 스크립트 속성 추가를 클릭합니다.
  5. 첫 번째 속성 이름에 GEMINI_API_KEY를 입력합니다.
  6. 값에는 Google AI Studio에서 복사한 API 키를 붙여 넣습니다.
  7. 속성을 하나 더 추가합니다.
  8. 두 번째 속성 이름에 NOTIFY_EMAIL을 입력합니다.
  9. 값에는 재고 부족 알림을 받을 이메일 주소를 입력합니다.
  10. 스크립트 속성 저장을 클릭합니다.
속성 이름 입력할 값
GEMINI_API_KEY Google AI Studio에서 복사한 API 키
NOTIFY_EMAIL 재고 부족 알림을 받을 담당자 이메일
여기까지 완료했다면

스크립트 속성 목록에 GEMINI_API_KEY와 NOTIFY_EMAIL이 표시됩니다.

6단계. 초기 설정 실행하기

  1. Apps Script의 함수 선택 메뉴에서 setupInventoryAutomation을 선택합니다.
  2. 실행 버튼을 클릭합니다.
  3. 권한 요청 화면에서 권한 검토를 클릭합니다.
  4. 사용할 구글 계정을 선택합니다.
  5. 스프레드시트 수정, 외부 서비스 연결과 이메일 발송 권한을 확인합니다.
  6. 허용을 클릭합니다.
여기까지 완료했다면

스프레드시트 아래쪽에 ‘재고관리’ 시트가 생성되고 예시 상품 3개가 표시됩니다.

Apps Script 트리거에는 checkLowStock 함수가 한 시간 간격으로 등록됩니다.

자동화가 정상 작동하는지 확인하기

1. 시험용 재고 확인하기

상품명 현재재고 안전재고 예상 결과
A4 복사용지 2개 5개 높음
검정 볼펜 18개 10개 정상
포장 테이프 0개 4개 긴급

2. 수동으로 시험 실행하기

  1. Apps Script 함수 목록에서 testInventoryAlert를 선택합니다.
  2. 실행을 클릭합니다.
  3. NOTIFY_EMAIL에 입력한 받은편지함을 엽니다.
정상 작동 결과

복사용지와 포장 테이프가 한 통의 이메일에 표시됩니다.

검정 볼펜은 현재재고가 안전재고보다 많기 때문에 이메일에 포함되지 않습니다.

3. AI 생성 여부 확인하기

Gemini API가 정상적으로 작동하면 시트의 AI발주초안 앞에 AI 생성이 표시됩니다.

API 키가 없거나 요청에 실패하면 기본 초안이 표시됩니다. 기본 초안이 표시돼도 재고 부족 이메일은 정상적으로 전송됩니다.

4. 중복 알림 확인하기

  1. 재고 수량을 바꾸지 않은 상태에서 testInventoryAlert를 다시 실행합니다.
  2. 받은편지함을 확인합니다.

이미 알림완료 상태로 변경된 상품에는 같은 이메일이 다시 전송되지 않습니다.

5. 재고 보충 후 상태 초기화하기

  1. A4 복사용지의 현재재고를 10개로 변경합니다.
  2. testInventoryAlert를 다시 실행합니다.
  3. 알림상태를 확인합니다.

현재재고가 안전재고보다 많아졌기 때문에 알림상태가 정상으로 돌아갑니다.

이후 현재재고가 다시 안전재고 이하로 내려가면 새로운 알림을 받을 수 있습니다.

TIP. 처음에는 한 시간 간격으로 운영하세요.

재고 수량이 자주 바뀌지 않는 소규모 사업장이라면 1분이나 5분마다 확인할 필요가 없습니다. 한 시간 간격으로 시작한 뒤 실제 업무 속도에 맞춰 조정하는 것이 좋습니다.

자주 발생하는 오류와 해결법

오류 1. 재고관리 시트가 만들어지지 않습니다

원인: setupInventoryAutomation 함수를 실행하지 않았거나 스프레드시트 권한을 허용하지 않았습니다.

해결 방법:

  1. Apps Script에서 setupInventoryAutomation을 선택합니다.
  2. 실행 버튼을 클릭합니다.
  3. 권한 검토를 누릅니다.
  4. 스프레드시트 수정 권한을 확인하고 허용합니다.

오류 2. NOTIFY_EMAIL이 없다고 표시됩니다

원인: 알림 이메일 주소를 스크립트 속성에 저장하지 않았습니다.

해결 방법:

  1. Apps Script 프로젝트 설정을 엽니다.
  2. 스크립트 속성에 NOTIFY_EMAIL을 추가합니다.
  3. 값에 실제 이메일 주소를 입력합니다.
  4. 저장한 뒤 다시 시험합니다.

오류 3. 이메일은 왔지만 기본 초안이라고 표시됩니다

원인: Gemini API 키가 없거나 API 요청이 실패했습니다.

해결 방법:

  1. 스크립트 속성의 GEMINI_API_KEY를 확인합니다.
  2. Google AI Studio에서 API 키 상태를 확인합니다.
  3. 필요하면 새 API 키를 생성해 교체합니다.
  4. 시험할 상품의 알림상태를 정상으로 변경합니다.
  5. testInventoryAlert를 다시 실행합니다.

오류 4. 숫자를 입력했는데 확인필요로 표시됩니다

현재재고나 안전재고에 ‘5개’처럼 문자가 함께 입력됐을 수 있습니다.

수량 셀에는 5, 10, 20처럼 숫자만 입력해야 합니다.

오류 5. 알림 이메일이 오지 않습니다

  1. 이메일의 스팸함을 확인합니다.
  2. NOTIFY_EMAIL 철자를 확인합니다.
  3. 현재재고가 안전재고 이하인지 확인합니다.
  4. 알림상태가 이미 알림완료인지 확인합니다.
  5. Apps Script 왼쪽의 실행 기록에서 오류 메시지를 확인합니다.

오류 6. 같은 상품의 알림을 다시 받고 싶습니다

해당 상품의 알림상태를 정상으로 변경한 뒤 testInventoryAlert를 다시 실행하세요.

오류 7. 재고를 보충했는데 상태가 바뀌지 않습니다

현재재고를 안전재고보다 큰 숫자로 변경한 뒤 testInventoryAlert를 실행하거나 다음 자동 실행까지 기다리세요.

오류 8. Gemini API 400 오류가 발생합니다

코드가 일부 빠졌거나 API 요청 형식이 변경됐을 수 있습니다.

본문의 전체 코드를 다시 복사하고 Apps Script 실행 기록에서 실제 오류 메시지를 확인하세요.

오류 9. Gemini API 401 또는 403 오류가 발생합니다

API 키가 잘못됐거나 사용할 수 없는 상태일 수 있습니다.

Google AI Studio에서 새 API 키를 생성하고 GEMINI_API_KEY 값을 교체하세요.

오류 10. 하루 이메일 한도를 초과했다고 나옵니다

Apps Script 이메일 발송량은 구글 계정 종류에 따라 제한됩니다.

이번 자동화는 부족한 상품을 한 통으로 묶어 전송하지만, 다른 Apps Script에서도 이메일을 많이 보냈다면 남은 할당량이 부족할 수 있습니다.

재고관리 방법 비교

비교 항목 수동 확인 Apps Script 자동화 Make 자동화
기본 비용 무료 무료 범위에서 시작 가능 무료 플랜 제공, 사용량에 따라 유료
코드 필요 없음 코드 붙여 넣기 필요 대부분 화면에서 설정
자동 확인 불가능 가능 가능
이메일 알림 직접 작성 자동 전송 자동 전송
AI 초안 직접 작성 Gemini 연결 OpenAI 등 외부 AI 연결 가능
오류 확인 별도 기록 없음 Apps Script 실행 기록 모듈별 실행 기록
유지관리 매일 직접 확인 코드와 트리거 확인 시나리오와 크레딧 확인
추천 대상 상품 수가 매우 적은 개인 무료 자동화를 시작할 사용자 여러 서비스를 연결할 팀

실제 활용 사례

직장인과 사무실

복사용지, 프린터 토너, 볼펜, 물티슈처럼 자주 사용하는 사무용품을 관리할 수 있습니다.

특정 수량 이하가 되면 총무 담당자에게 자동으로 이메일을 보내도록 설정하면 됩니다.

온라인 쇼핑몰

택배 상자, 포장 테이프, 완충재, 사은품처럼 출고에 필요한 소모품을 관리하기 좋습니다.

판매 상품의 재고가 남아 있어도 포장재가 떨어지면 배송이 지연될 수 있습니다. 포장재를 별도 품목으로 등록하면 이런 상황을 줄일 수 있습니다.

카페와 음식점

컵, 빨대, 포장 용기, 냅킨 같은 비식품 소모품 관리에 활용할 수 있습니다.

식재료는 유통기한, 입고일과 보관 온도까지 확인해야 하므로 별도의 관리 항목이 필요합니다.

개발자와 소규모 기업

처음에는 구글 시트로 시작한 뒤 판매 시스템이나 사내 데이터베이스와 연결할 수 있습니다.

재고가 부족할 때 Gmail뿐 아니라 Slack이나 Microsoft Teams로 알림을 보내는 방식으로도 확장할 수 있습니다.

장점과 단점

장점
  • 구글 계정만 있으면 무료 범위에서 시작할 수 있습니다.
  • 상품이 많아져도 부족한 항목만 빠르게 확인할 수 있습니다.
  • 같은 상품의 중복 알림을 줄일 수 있습니다.
  • Gemini가 작동하지 않아도 기본 초안으로 알림을 보냅니다.
  • 공급처에 자동 발송하지 않아 잘못된 발주 위험을 줄였습니다.
  • 재고가 보충되면 알림상태가 자동으로 초기화됩니다.
단점
  • 현재재고는 직접 수정하거나 다른 시스템과 연결해야 합니다.
  • 안전재고와 권장발주수량을 담당자가 직접 정해야 합니다.
  • AI는 실제 가격과 납기 여부를 확인하지 못합니다.
  • 구글 계정에는 이메일과 실행 할당량이 있습니다.
  • 회사 기밀이나 공급 가격을 외부 AI에 보낼 때는 보안 검토가 필요합니다.
  • 복잡한 판매 예측이나 자동 발주 기능은 포함하지 않습니다.

자주 묻는 질문

Q1. 재고가 몇 개일 때 알림이 오나요?

현재재고가 안전재고와 같거나 더 적어지면 알림 대상이 됩니다.

예를 들어 안전재고가 5개라면 현재재고가 5개 이하일 때 이메일이 발송됩니다.

Q2. Gemini API 키가 없어도 사용할 수 있나요?

가능합니다. API 키가 없거나 Gemini 요청이 실패하면 코드에 미리 작성된 기본 발주 문의 초안이 사용됩니다.

Q3. 공급처에 자동으로 이메일이 발송되나요?

아닙니다. 이번 자동화는 재고 담당자에게만 검토용 이메일을 보냅니다.

담당자가 수량, 가격과 납기를 확인한 뒤 공급처에 보내야 합니다.

Q4. 컴퓨터를 계속 켜 놓아야 하나요?

아닙니다. Apps Script는 구글 서버에서 실행되므로 컴퓨터가 꺼져 있어도 설정한 간격에 따라 작동합니다.

Q5. 같은 상품의 알림이 계속 반복되지 않나요?

이메일을 보낸 상품은 알림완료 상태로 변경됩니다.

재고가 보충되어 정상 상태로 돌아가기 전까지 같은 알림은 반복되지 않습니다.

Q6. AI가 발주할 수량을 자동으로 계산하나요?

아닙니다. 권장발주수량은 담당자가 직접 입력해야 합니다.

판매량, 납기, 최소주문수량과 보관 공간을 모르는 상태에서 AI가 발주량을 결정하면 과잉 재고가 생길 수 있습니다.

Q7. 하루에 상품을 몇 개까지 확인할 수 있나요?

시트에 많은 상품을 입력할 수 있지만 Apps Script의 실행 시간과 이메일 할당량이 적용됩니다.

이번 코드는 이메일 한 통에 부족 상품을 최대 30개까지 넣도록 설정했습니다.

마무리

구글 시트 재고 부족 알림 자동화는 복잡한 재고관리 프로그램을 도입하기 전에 가볍게 시작하기 좋은 방법입니다.

상품별 현재재고와 안전재고만 정확하게 관리하면 부족한 상품을 자동으로 찾고 담당자에게 이메일을 보낼 수 있습니다.

Gemini는 반복적인 이메일 작성을 줄여주는 초안을 만들지만 실제 발주를 결정하는 담당자는 아닙니다.

AI가 작성한 문장은 검토용으로만 사용하고 실제 수량, 가격, 납기와 공급 가능 여부는 사람이 반드시 확인해야 합니다.

처음에는 실제 발주가 필요 없는 시험 상품으로 이메일 전송, 중복 알림 차단과 상태 초기화가 정상적으로 작동하는지 확인한 뒤 업무에 적용해 보세요.

핵심 한 줄 정리

구글 시트와 AI를 연결하면 안전재고 이하 상품을 자동으로 찾고, 담당자가 검토할 발주 문의 초안까지 준비할 수 있습니다.

관련글 더보기