내용 검토: 2026년 10월 4일. Slack Incoming Webhooks와 Google Apps Script 공식 문서를 기준으로 설정·권한·실패 처리 절차를 다시 확인했습니다.
Google Forms 응답을 Slack 채널에 자동으로 알리려면 응답이 쌓이는 Google Sheets에 Apps Script를 연결하고, 스프레드시트의 설치형 양식 제출 트리거에서 Slack Incoming Webhook을 호출하면 됩니다. 아래 예제는 응답 내용이나 개인정보를 Slack으로 보내지 않고 새 응답이 등록됐다는 알림과 해당 행 링크만 전송합니다.
이 방법은 “응답이 도착했다”는 채널 알림이 필요한 소규모 업무 흐름에 적합합니다. 실제 고객 답변 전체를 Slack으로 옮기거나 높은 전달 보장·감사 로그가 필요한 업무라면 승인된 업무 자동화 플랫폼이나 서버 측 대기열을 검토하세요.
먼저 확인할 것
Google Forms의 응답 대상이 Google Sheets로 연결되어 있어야 합니다. 이 글은 폼 응답 → 연결된 스프레드시트 → Apps Script → Slack 채널 흐름만 다룹니다. Slack 메시지를 보내려면 권한 승인이 필요한 외부 요청을 실행해야 하므로, 단순 트리거보다 설치형 트리거를 사용합니다.
- 폼 응답을 기록하는 스프레드시트의 편집 권한
- 알림을 게시할 Slack 워크스페이스와 채널
- Apps Script 프로젝트 편집 권한. 웹훅을 볼 수 있는 사람도 프로젝트 편집자로 제한합니다.
- 테스트용 폼 응답과 공개 채널이 아닌 전용 테스트 채널
응답 내용에 이름·이메일·전화번호·상담 내용이 들어간다면 기본 예제처럼 Slack에는 고정 알림만 보내세요. 알림 채널 구성원 모두가 원본 시트에 접근할 수 있는지 별도로 확인하고, Slack 게시가 필요한 업무인지 조직의 개인정보·보존 정책도 먼저 검토합니다.
Slack 웹훅 만들고 보관하기
- Slack API에서 새 앱을 만들거나 기존 앱을 엽니다.
- Incoming Webhooks 기능을 켜고 워크스페이스에 앱을 설치합니다.
- 메시지를 받을 채널을 선택해 Incoming Webhook URL을 발급합니다. 웹훅은 선택한 채널에 연결됩니다.
- Apps Script의 프로젝트 설정 → 스크립트 속성에 속성 이름
SLACK_WEBHOOK_URL, 값은 발급받은 URL로 저장합니다.
웹훅 URL 자체가 비밀값입니다. 소스 코드, 셀, 공개 문서, 화면 캡처, 실행 로그에 넣지 마세요. 스크립트 속성은 코드에 직접 적는 실수를 줄이는 설정 저장소이지 비밀 금고가 아닙니다. 같은 Apps Script 프로젝트의 편집자는 속성에 접근할 수 있으므로 편집자를 제한하세요. URL이 노출되면 기존 URL을 폐기하고 새 웹훅을 발급합니다.
Incoming Webhook은 설정된 기본 채널·작성자 이름·아이콘을 요청 본문에서 바꾸는 용도가 아닙니다. 아래 코드는 text만 보냅니다. 예전 예제에서 흔히 보이는 channel, username, icon_emoji는 이 설정을 덮어쓰지 않습니다.
Apps Script 코드 넣기
응답 스프레드시트에서 확장 프로그램 → Apps Script를 열고 코드를 붙여넣으세요. 상수 SHEET_NAME은 실제 응답 탭 이름으로 바꾸고, 응답 시트 첫 행의 맨 오른쪽에 Slack 알림 상태 열을 추가합니다.
const SHEET_NAME = 'Form Responses 1'; // 실제 응답 탭 이름으로 변경
const STATUS_HEADER = 'Slack 알림 상태';
const WEBHOOK_PROPERTY = 'SLACK_WEBHOOK_URL';
function notifySlackOnFormSubmit(e) {
if (!e || !e.range || !e.namedValues) {
throw new Error('스프레드시트 양식 제출 트리거에서 실행해야 합니다.');
}
const sheet = e.range.getSheet();
if (sheet.getName() !== SHEET_NAME) return;
const row = e.range.getRow();
const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn())
.getDisplayValues()[0];
const statusColumn = headers.indexOf(STATUS_HEADER) + 1;
if (statusColumn === 0) {
throw new Error('첫 행에서 Slack 알림 상태 열을 찾을 수 없습니다.');
}
const lock = LockService.getScriptLock();
lock.waitLock(10000);
try {
const statusCell = sheet.getRange(row, statusColumn);
if (String(statusCell.getValue()).trim()) return;
const webhook = PropertiesService.getScriptProperties()
.getProperty(WEBHOOK_PROPERTY);
if (!webhook) throw new Error('스크립트 속성에 웹훅 설정이 없습니다.');
statusCell.setValue('전송 중');
SpreadsheetApp.flush();
const responseUrl = sheet.getParent().getUrl() +
'#gid=' + sheet.getSheetId() + '&range=A' + row;
let response;
try {
response = UrlFetchApp.fetch(webhook, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({
text: '새 Google Forms 응답이 등록되었습니다. (행 ' + row + ')\n' + responseUrl
}),
muteHttpExceptions: true
});
} catch (error) {
statusCell.setValue('확인 필요');
throw new Error('Slack 응답을 받지 못했습니다. 채널과 실행 기록을 확인하세요.');
}
const code = response.getResponseCode();
const body = response.getContentText().trim();
if (code === 200 && body === 'ok') {
statusCell.setValue('전송 완료');
return;
}
statusCell.setValue(code === 200 ? '확인 필요' : '오류');
throw new Error('Slack 전송 확인 실패: HTTP ' + code + '. 응답 본문은 기록하지 않았습니다.');
} finally {
lock.releaseLock();
}
}
상태 열이 비어 있는 행만 전송합니다. 스크립트 잠금은 두 실행이 같은 행을 동시에 처리하는 상황을 줄이고, 전송 결과가 확인되면 상태를 기록합니다. 메시지에는 응답 값을 넣지 않습니다. 데이터가 꼭 필요하다면 필요한 항목만 선택하고 민감정보를 제거한 뒤 Slack 채널의 접근 권한과 보존 기준을 먼저 확인하세요.
양식 제출 트리거 연결하기
- Apps Script 왼쪽의 트리거를 열고 트리거를 추가합니다.
- 실행 함수는
notifySlackOnFormSubmit, 이벤트 소스는 스프레드시트에서, 이벤트 유형은 양식 제출 시로 지정합니다. - 저장 후 이 트리거를 만든 Google 계정으로 권한을 승인합니다. 승인 화면에서 Sheets 접근과 외부 서비스 연결 권한을 확인합니다.
- 다른 함수의 단순
onEdit나 Google Forms 자체의 제출 트리거를 고르지 마세요. 이 예제는 연결된 응답 시트의 제출 이벤트 객체e.range와e.namedValues를 확인합니다.
설치형 트리거는 만든 계정 권한으로 실행됩니다. 다른 편집자가 별도로 같은 트리거를 만들면 알림이 중복될 수 있고, 트리거 목록은 만든 계정별로 관리됩니다. 운영 담당 계정과 트리거 소유자를 정하고, 트리거 화면에서 같은 함수가 중복 등록되지 않았는지 확인하세요.
안전하게 테스트하기
- 테스트용 Slack 채널을 고르고 그 채널 전용 웹훅을 발급합니다.
- 복제한 테스트 폼에서 이름·연락처 같은 실제 개인정보 없이 가짜 응답을 한 번 제출합니다.
- 연결 시트의 새 행에서
Slack 알림 상태가전송 완료인지, Slack 메시지에 행 링크가 맞는지 확인합니다. - Slack에는 메시지가 왔는데 상태가 바뀌지 않거나 실행 기록에 실패가 있으면 원인을 확인하기 전 다시 제출하지 않습니다.
- 테스트 성공 뒤 운영 폼·운영 채널로 바꾸고, 운영 웹훅과 테스트 웹훅이 혼동되지 않도록 속성값을 확인합니다.
Apps Script 트리거는 편집기에서 함수를 수동 실행하는 것과 다르게 이벤트 객체를 전달받습니다. e 없이 함수를 직접 실행하면 위 코드가 안내 오류를 내는 것이 정상입니다. 동작 확인은 테스트 폼을 실제로 제출해 진행하세요.
전송 실패와 중복 진단
| 증상 | 먼저 확인할 곳 | 다음 조치 |
|---|---|---|
| 실행 기록이 없고 메시지도 없음 | Apps Script 트리거 화면, 대상 함수·이벤트 유형, 트리거를 만든 계정 | 스프레드시트의 양식 제출 트리거인지 확인하고 권한을 다시 승인합니다. |
| HTTP 400·403·404 | 실행 기록의 HTTP 상태, Slack 앱의 웹훅 설정과 채널 상태 | 요청 형식·앱 승인·웹훅 유효성을 확인합니다. URL 전문이나 응답 본문을 공개하지 않습니다. |
HTTP 200이지만 전송 완료가 아님 | Slack 응답이 일반적인 성공 응답 ok인지 확인 | 채널 메시지와 실행 기록을 비교하고, 코드가 Slack 속성값을 출력하지 않는지 확인합니다. |
| 같은 응답 알림이 두 번 도착 | 같은 함수에 설치된 트리거 수, 중복 실행 계정, 응답 행의 상태 셀 | 중복 트리거를 정리합니다. 상태값을 무조건 지우면 같은 행을 다시 보낼 수 있습니다. |
전송 중 또는 확인 필요에서 멈춤 | Apps Script 실행 기록과 해당 Slack 채널의 실제 메시지 | 먼저 메시지 도착 여부를 확인합니다. 요청이 Slack에 도달한 뒤 응답만 유실된 경우 재실행하면 중복될 수 있습니다. |
웹훅 호출이 시간 초과되면 Slack이 메시지를 받았는지 코드만으로 확정할 수 없는 경우가 있습니다. 그래서 이 예제는 실패를 자동 재시도하지 않고 확인 필요로 남깁니다. 채널에서 같은 응답의 메시지가 없는 것을 확인한 뒤 원인을 해결하고, 해당 행 상태를 직접 비워 한 번 재처리하세요. Slack 메시지가 이미 있다면 상태를 전송 완료로 정리해 다시 보내지 않도록 합니다. 이를 완전한 1회 전송으로 보장한다고 볼 수는 없습니다.
트리거 실패 알림 메일과 Apps Script의 실행 기록에서 함수명·오류 시각·HTTP 상태를 확인할 수 있습니다. 웹훅 URL, 전체 응답 본문, 폼 응답 전문은 로그에 넣지 마세요.
자주 묻는 질문
Apps Script에서 Slack 채널을 코드로 바꿀 수 있나요?
Incoming Webhook은 생성·승인 때 연결한 채널에 게시합니다. 이 예제의 요청에서 채널 이름을 덮어쓸 수 없습니다. 채널이 다르면 해당 채널에 연결된 웹훅을 별도로 설정하고 속성값을 바꾸세요.
폼 답변이나 이메일 주소도 Slack에 보내도 되나요?
기술적으로 메시지 본문에 값을 넣을 수 있지만 기본 예제는 보내지 않습니다. 필요한 최소 항목인지 검토하고, Slack 채널 구성원의 원본 데이터 접근 권한과 조직의 개인정보 처리 기준을 확인한 뒤에만 범위를 좁혀 추가하세요.
오류 난 행을 자동으로 다시 보내면 안 되나요?
호출 시간이 초과된 경우 Slack이 이미 게시한 뒤 응답만 돌아오지 않았을 수 있습니다. 자동 재시도는 중복 메시지를 만들 수 있으므로 채널 확인 후 사람이 상태를 정리하는 방식으로 시작하세요.
Slack 메시지는 왔는데 데스크톱이나 휴대전화 알림이 안 와요.
이 경우 Apps Script 전송은 성공했고, 사용자의 Slack 알림 설정에서 문제가 생긴 것일 수 있습니다. Slack 모바일·데스크톱 알림 진단 가이드에서 채널별 설정과 기기 알림 권한을 확인하세요.
공식 참고 자료와 이어 읽기
- Slack Incoming Webhooks 공식 안내
- Apps Script 이벤트 객체: 스프레드시트 양식 제출
- Apps Script 설치형 트리거와 실행 계정
- Apps Script 속성 서비스와 스크립트 속성 관리
- UrlFetchApp 요청 옵션과 HTTP 오류 응답
- HTTPResponse 상태 코드·응답 확인
- LockService 동시 실행 제어
트리거 자체가 실행되지 않는다면 Apps Script 트리거 오류 점검표를, Sheets 자동화 전체 흐름을 찾는다면 Google Sheets 업무 자동화 허브를 참고하세요.