코멘토 로고

관심 기업의 새 채용 공고 알림을 받고 지원 현황을 구글 시트로 관리하려면 어떻게 자동화하나요?

꿈
꿈꾸는 AI

채용 사이트의 공식 알림 메일을 Gmail 라벨로 모으면 됩니다. 그다음 구글 시트에 붙인 Apps Script가 1시간마다 그 메일을 읽어, 조건에 맞는 공고만 시트에 적고 내게 메일로 알리게 합니다. AI 한 줄 요약은 같은 스크립트가 OpenAI API를 불러 시트 칸에 채웁니다. 처음이라면 사이트를 긁어 오는 스크래핑은 건너뛰고 "공식 알림 메일 → Gmail 라벨 → Apps Script" 순서로 시작하기를 권합니다.

이 글은 포텐스닷 라운지에서 Google, OpenAI, LinkedIn 공식 문서를 바탕으로 정리한 절차이며, 기준 시점은 2026년 11월 02일입니다.

새 공고는 어디서 어떻게 가져오나요?

채용 사이트의 공식 알림 기능을 먼저 쓰는 편이 안전합니다. 공식 API나 RSS가 있으면 그쪽을 우선하고, 웹페이지를 허락 없이 반복해서 긁어 오지 않습니다.

  1. 사이트 알림 켜기: LinkedIn은 검색 결과 화면에서 Set alert를 켜면 조건에 맞는 공고를 메일로 받을 수 있습니다(LinkedIn 안내). LinkedIn 도움말에 따르면 알림은 계정당 최대 20개입니다. 국내 채용 사이트도 알림 조건과 개수를 각 사이트 설정 화면에서 확인합니다.
  2. Gmail 라벨 만들기: Gmail 검색창에 from:(알림 발신 주소) (채용 OR 공고)처럼 검색 연산자를 넣습니다. 그다음 검색 옵션에서 필터 만들기 → 라벨 적용을 고릅니다(Gmail 검색 연산자). 라벨은 채용알림/미처리와 채용알림/처리완료 두 개를 만들어 둡니다.
  3. 스크래핑 전 확인: 이용약관에서 "자동화된 수단", "크롤링", "무단 수집"을 금지하는 조항이 있는지 찾아봅니다. 일반적인 확인 절차로는 사이트 주소 뒤에 /robots.txt를 붙여 수집을 막아 둔 경로가 있는지도 볼 수 있습니다.

지원 현황 시트는 어떤 열로 만드나요?

최소 구성인 다섯 열로 시작하고, 필요하면 기업명, 근무지, 지원일 같은 열을 늘립니다. A~C열은 스크립트가 채우고, D열과 E열은 직접 관리합니다.

열 내용 채우는 방식
A 공고 URL 중복을 막는 기준 값 스크립트 자동
B 제목 알림 메일 제목 스크립트 자동
C 한 줄 요약 회사, 직무, 핵심 자격요건 AI 자동
D 마감일 2026-11-30 형식 날짜 원문을 보고 직접 입력
E 단계 관심, 서류 제출, 서류 합격, 면접, 최종 합격, 불합격 드롭다운 선택

E열은 데이터 → 데이터 확인에서 "드롭다운"을 고르고 단계 이름을 넣습니다. 마감 임박 표시도 걸 수 있습니다. D열을 선택하고 서식 → 조건부 서식 → 맞춤 수식에 =AND($D2<>"",$D2>=TODAY(),$D2-TODAY()<=3)을 넣은 뒤 빨간 배경을 지정하면, 마감 3일 이내 공고가 빨갛게 표시됩니다.

Apps Script 코드는 어떻게 붙여 넣고 실행하나요?

시트에서 확장 프로그램 → Apps Script를 열고 아래 코드를 붙여 넣은 다음, 시간 기반 트리거를 걸어 주기적으로 실행되게 합니다. Gmail 읽기와 발송에는 GmailApp, 외부 API 호출에는 UrlFetchApp을 씁니다.

const CFG = { todo: '채용알림/미처리', done: '채용알림/처리완료',
  keywords: ['기획', '데이터'], regions: ['서울', '판교'], sheet: '공고' };

function checkJobs() {
  const sh = SpreadsheetApp.getActive().getSheetByName(CFG.sheet);
  const seen = sh.getRange('A:A').getValues().flat();
  const todo = GmailApp.getUserLabelByName(CFG.todo);
  const done = GmailApp.getUserLabelByName(CFG.done);
  const hits = [];
  todo.getThreads().forEach(t => {
    const m = t.getMessages()[0];
    const text = m.getPlainBody();
    const url = (text.match(/https?:\/\/\S+/) || [''])[0];
    const ok = CFG.keywords.some(k => text.includes(k)) &&
               CFG.regions.some(r => text.includes(r));
    if (ok && url && !seen.includes(url)) {
      sh.appendRow([url, m.getSubject(), summarize(text), '', '관심']);
      seen.push(url);
      hits.push(m.getSubject() + '\n' + url);
    }
    t.removeLabel(todo).addLabel(done);
  });
  if (hits.length) GmailApp.sendEmail(Session.getActiveUser().getEmail(),
    '새 채용 공고 ' + hits.length + '건', hits.join('\n\n'));
}

function summarize(text) {
  const key = PropertiesService.getScriptProperties().getProperty('OPENAI_API_KEY');
  const res = UrlFetchApp.fetch('https://api.openai.com/v1/chat/completions', {
    method: 'post', contentType: 'application/json',
    headers: { Authorization: 'Bearer ' + key },
    payload: JSON.stringify({ model: 'MODEL_NAME', messages: [{ role: 'user',
      content: '채용 공고를 회사, 직무, 핵심 자격요건이 들어간 한국어 한 줄로 요약:\n' + text.slice(0, 4000) }] })
  });
  return JSON.parse(res.getContentText()).choices[0].message.content;
}

이 코드는 조건에 맞지 않는 메일도 채용알림/처리완료로 옮겨서 다음 실행 때 다시 읽지 않습니다. 같은 URL이 여러 번 와도 seen에 추가해 두기 때문에 시트에는 한 번만 들어갑니다. 실행 전에 바꿀 곳은 네 군데입니다.

  1. 조건: keywords(직무 단어)와 regions(지역)를 내 조건으로 고치고, 시트 탭 이름을 공고로 맞춥니다.
  2. API 키: 편집기 왼쪽 프로젝트 설정 → 스크립트 속성에 OPENAI_API_KEY를 추가합니다. 키를 코드에 직접 적는 것보다는 안전합니다. 다만 시트를 편집자로 공유하면 연결된 스크립트와 속성도 열어 볼 수 있으니 편집 권한은 나만 갖습니다.
  3. API 호출 방식: 코드의 호출 주소, 요청 형식, MODEL_NAME은 예시입니다. OpenAI API 문서에서 현재 주소와 모델 이름을 확인한 뒤 고칩니다. 회사, 직무, 자격요건을 칸별로 나눠 받고 싶다면 Structured Outputs(정해 둔 JSON 틀대로만 답하게 하는 기능)를 쓸 수 있습니다.
  4. 트리거: 편집기 왼쪽 시계 아이콘 트리거 → 트리거 추가에서 checkJobs, "시간 기반", "1시간마다"를 고릅니다. 시간 기반 트리거는 실행 시각이 조금씩 무작위로 밀릴 수 있어서 정각 실행은 보장되지 않습니다(설치형 트리거 안내).

처음 실행하면 Google 권한 승인 창이 뜹니다. 먼저 테스트용 메일 한두 통에만 라벨을 붙여 결과를 확인하고, 그다음에 트리거를 켜세요.