Google Forms 응답을 Slack으로 보내는 완벽 가이드 (Apps Script 속성 사용)
이 가이드는 Google Forms가 제출될 때, 해당 응답 데이터를 Slack으로 자동 전송하는 방법을 안내합니다.
준비물:
- Google 계정 (Gmail, Google Drive, Google Forms 접근 가능)
- Slack 워크스페이스 및 채널 (알림을 받을 채널)
- 해당 Slack 채널에 Incoming Webhooks 통합 앱 추가 및 웹훅 URL 발급 (가장 먼저 해야 할 중요 작업)
1단계: Slack Incoming Webhook URL 발급
- Slack 워크스페이스에 로그인합니다.
- 알림을 받을 특정 채널 (예: #입사자슬랙웹훅)을 선택합니다.
- 채널 이름 위에서 마우스 오른쪽 버튼을 클릭하거나, 채널 헤더의 드롭다운 메뉴를 클릭합니다.
- 통합 > 앱 추가 (또는 앱 디렉터리 열기)로 이동합니다.
- Incoming WebHooks 앱을 검색하여 추가합니다. (이미 추가되어 있다면 해당 앱을 찾아 구성합니다.)
- 웹훅 URL을 생성합니다. (일반적으로 Add to Slack 또는 Add configuration 버튼을 누른 후, 알림을 보낼 채널을 선택하면 URL이 생성됩니다.)
- 생성된 웹훅 URL (https://hooks.slack.com/services/...로 시작)을 정확하게 복사합니다. 이 URL은 나중에 Apps Script에서 사용합니다.
2단계: Google Forms 및 스프레드시트 준비
- 새로운 Google Forms 설문지를 만듭니다 (또는 기존 설문지를 사용합니다).
- 설문지 상단 메뉴에서 응답 탭을 클릭합니다.
- 초록색 스프레드시트 아이콘을 클릭하여 응답을 받을 새로운 스프레드시트를 만듭니다. (기존 스프레드시트에 연결할 수도 있습니다.)
- 스프레드시트가 열리면, 설문지 질문 제목들이 스프레드시트의 첫 번째 행(헤더)에 자동으로 매핑됩니다. (예: "성명", "입사일" 등)
3단계: Apps Script 코드 작성 및 설정
- 연결된 스프레드시트에서 확장 프로그램 > Apps Script를 클릭하여 Apps Script 편집기를 엽니다.
- 기존 코드를 모두 지우고, 아래 제공된 코드를 붙여넣습니다.
/**
* 구글 설문지 응답이 제출될 때 슬랙으로 알림을 보내는 앱스크립트 코드
*
* Copyright (c) 2025 Hyunjung Cho
* MIT 라이센스에 따라 배포됩니다.
* https://opensource.org/licenses/MIT
*/
/**
* 폼 제출 시 실행되는 함수
* @param {Object} e 폼 제출 이벤트 객체
*/
function onFormSubmit(e) {
// 스크립트 속성에서 웹훅 URL 가져오기
// 'SLACK_WEBHOOK_URL'은 스크립트 속성에서 설정할 키(이름)입니다.
const SLACK_WEBHOOK_URL = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL');
// 웹훅 URL이 제대로 설정되었는지 확인
if (!SLACK_WEBHOOK_URL) {
Logger.log("오류: SLACK_WEBHOOK_URL 스크립트 속성이 설정되지 않았습니다. 슬랙 알림을 보낼 수 없습니다.");
return; // 웹훅 URL이 없으면 함수 실행 중단
}
// 폼 응답 데이터 가져오기 (Google Forms 질문 제목과 정확히 일치해야 합니다)
const formResponse = e.namedValues;
// --- 여기에 실제 구글 폼의 질문 제목과 매핑되는 변수를 정의합니다 ---
// 예시: const 성명 = formResponse["성명"] ? formResponse["성명"].toString() : "정보 없음";
// 실제 폼 질문 제목에 맞게 수정하세요.
const 성명 = formResponse["성명"] ? formResponse["성명"].toString() : "정보 없음";
const 입사일 = formResponse["입사일"] ? formResponse["입사일"].toString() : "정보 없음";
const 주민등록번호 = formResponse["주민등록번호"] ? formResponse["주민등록번호"].toString() : "정보 없음";
const 생일 = formResponse["생일"] ? formResponse["생일"].toString() : "정보 없음";
const 주소 = formResponse["주소"] ? formResponse["주소"].toString() : "정보 없음";
const 휴대폰번호 = formResponse["휴대폰번호"] ? formResponse["휴대폰번호"].toString() : "정보 없음";
const 여권상영문이름 = formResponse["여권상 영문이름"] ? formResponse["여권상 영문이름"].toString() : "정보 없음";
const 여권번호 = formResponse["여권 번호"] ? formResponse["여권 번호"].toString() : "정보 없음";
const 여권만료일 = formResponse["여권 만료일"] ? formResponse["여권 만료일"].toString() : "정보 없음";
const 최종출신학교 = formResponse["최종 출신학교"] ? formResponse["최종 출신학교"].toString() : "정보 없음";
const 전공 = formResponse["전공"] ? formResponse["전공"].toString() : "정보 없음";
const 학력 = formResponse["학력"] ? formResponse["학력"].toString() : "정보 없음";
const 병역 = formResponse["병역"] ? formResponse["병역"].toString() : "정보 없음";
const 이메일 = formResponse["이메일"] ? formResponse["이메일"].toString() : "정보 없음";
// --- 매핑 끝 ---
// 메시지 구성
let message = "✨ *입사자 등록*\n";
message += `성명 : ${성명}\n`;
message += `입사일 : ${입사일}\n`;
message += `주민등록번호 : ${주민등록번호}\n`;
message += `생일 : ${생일}\n`;
message += `주소 : ${주소}\n`;
message += `휴대폰번호 : ${휴대폰번호}\n`;
message += `여권상 영문이름 : ${여권상영문이름}\n`;
message += `여권 번호 : ${여권번호}\n`;
message += `여권 만료일 : ${여권만료일}\n`;
message += `최종 출신학교 : ${최종출신학교}\n`;
message += `전공 : ${전공}\n`;
message += `학력 : ${학력}\n`;
message += `병역 : ${병역}\n`;
message += `이메일 : ${이메일}\n`;
// 스프레드시트 링크 추가
const spreadsheetUrl = SpreadsheetApp.getActiveSpreadsheet().getUrl();
message += `\n<${spreadsheetUrl}|📊 자세한 내용은 여기에서 확인>`;
// Slack에 전송할 페이로드 구성
const payload = {
"text": message
};
// Slack에 POST 요청 보내기
const options = {
"method": "post",
"contentType": "application/json",
"payload": JSON.stringify(payload)
};
// 웹훅 URL로 요청 전송
try {
const response = UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);
Logger.log("슬랙 알림 전송 성공: " + response.getContentText());
} catch (error) {
Logger.log("슬랙 알림 전송 실패: " + error.toString());
}
}
- 변경 사항 저장: Ctrl + S (Mac: ⌘ + S)를 눌러 코드를 저장합니다.
4단계: 스크립트 속성(Properties) 설정 (가장 중요)
스크립트 속성에 Slack 웹훅 URL을 안전하게 저장합니다.
- Apps Script 편집기 왼쪽 사이드바에서 **톱니바퀴 아이콘 (프로젝트 설정)**을 클릭합니다.
- 아래로 스크롤하여 "스크립트 속성" 섹션을 찾습니다.
- "+ 스크립트 속성 추가" 버튼을 클릭합니다.
- 속성 칸에 정확하게 SLACK_WEBHOOK_URL 이라고 입력합니다. (대소문자 구분 중요!)
- 값 칸에 1단계에서 복사한 실제 Slack 웹훅 URL을 붙여넣습니다. (예: https://hooks.slack.com/services/T01234/B01234/F01234)
- "스크립트 속성 저장" 버튼을 클릭합니다.
5단계: 트리거 설정 (핵심)
폼 제출 시 onFormSubmit 함수가 자동으로 실행되도록 트리거를 설정합니다.
- Apps Script 편집기 왼쪽 사이드바에서 **시계 아이콘 (트리거)**을 클릭합니다.
- 오른쪽 하단의 "+ 트리거 추가" 버튼을 클릭합니다.
- 다음과 같이 설정합니다:
- 실행할 함수 선택: 드롭다운에서 onFormSubmit을 선택합니다.
- 이벤트 소스 선택: 스프레드시트에서를 선택합니다.
- 이벤트 유형 선택: 양식 제출 시를 선택합니다.
- 저장 버튼을 클릭합니다.
- 권한 승인: 저장을 클릭하면 Google 계정 권한 승인 팝업이 나타날 수 있습니다.
- 권한 검토 또는 허용 버튼을 클릭합니다.
- 본인의 Google 계정을 선택합니다.
- (경고 메시지가 나오더라도) 고급을 클릭하고 ~으로 이동을 선택하여 모든 필요한 권한을 허용해 줍니다. (예: Google Docs, 외부 URL 연결, 스프레드시트 보기 등)
- 이 단계가 완료되어야 스크립트가 Slack에 메시지를 보낼 수 있습니다.
6단계: 테스트 및 확인
- Apps Script 편집기에서 함수를 직접 실행하지 마십시오. (그래야 e.namedValues 오류가 발생하지 않습니다.)
- Google Forms 설문지 링크로 이동하여 새로운 응답을 제출합니다.
- 응답을 제출한 후, Apps Script 편집기로 돌아와서 왼쪽 사이드바의 **실행 아이콘 (세 줄에 화살표 달린 모양)**을 클릭합니다.
- 가장 최근 onFormSubmit 함수가 완료됨 상태로 실행되었는지 확인합니다.
- 해당 실행 기록을 클릭하여 상세 로그에 슬랙 알림 전송 성공: ... 메시지가 출력되었는지 확인합니다.
- Slack 채널(예: #입사자슬랙웹훅)을 확인하여 알림 메시지가 도착했는지 최종 확인합니다.
문제 발생 시 디버깅:
- Slack 알림이 오지 않는데, 실행 로그에 슬랙 알림 전송 실패가 있다면:
- 로그의 자세한 오류 메시지를 확인합니다.
- Slack 웹훅 URL이 유효한지, Slack에서 해당 웹훅 통합이 활성화되어 있는지 다시 확인합니다.
- 실행 로그에 onFormSubmit 기록 자체가 없거나 실패로 표시된다면:
- 5단계의 트리거 설정을 다시 한번 꼼꼼히 확인하고 권한 승인을 완료했는지 확인합니다.
- 브라우저 캐시를 지우고 다시 시도해봅니다.
이 가이드라인을 따라하시면 다른 설문지를 작성할 때도 쉽게 적용하실 수 있을 것입니다.
신버전 웹훅 아이콘 변경 "icon_emoji": ":fire:"
/**
* 구글 설문지 응답이 제출될 때 슬랙으로 알림을 보내는 앱스크립트 코드
* (Block Kit을 사용하여 메시지 시각화 개선 - 주민등록번호 포함)
*
* Copyright (c) 2025 Hyunjung Cho
* MIT 라이센스에 따라 배포됩니다.
* https://opensource.org/licenses/MIT
*/
function onFormSubmit(e) {
const SLACK_WEBHOOK_URL = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL');
if (!SLACK_WEBHOOK_URL) {
Logger.log("오류: SLACK_WEBHOOK_URL 스크립트 속성이 설정되지 않았습니다. 슬랙 알림을 보낼 수 없습니다.");
return;
}
// 폼 응답 데이터 가져오기 (Google Forms 질문 제목과 정확히 일치해야 합니다)
const formResponse = e.namedValues;
// 필요한 필드 매핑 (주민등록번호 포함)
const 성명 = formResponse["성명"] ? formResponse["성명"].toString() : "정보 없음";
const 입사일 = formResponse["입사일"] ? formResponse["입사일"].toString() : "정보 없음";
const 주민등록번호 = formResponse["주민등록번호"] ? formResponse["주민등록번호"].toString() : "정보 없음"; // 주민등록번호 활성화
const 생일 = formResponse["생일"] ? formResponse["생일"].toString() : "정보 없음";
const 주소 = formResponse["주소"] ? formResponse["주소"].toString() : "정보 없음";
const 휴대폰번호 = formResponse["휴대폰번호"] ? formResponse["휴대폰번호"].toString() : "정보 없음";
const 여권상영문이름 = formResponse["여권상 영문이름"] ? formResponse["여권상 영문이름"].toString() : "정보 없음";
const 여권번호 = formResponse["여권 번호"] ? formResponse["여권 번호"].toString() : "정보 없음";
const 여권만료일 = formResponse["여권 만료일"] ? formResponse["여권 만료일"].toString() : "정보 없음";
const 최종출신학교 = formResponse["최종 출신학교"] ? formResponse["최종 출신학교"].toString() : "정보 없음";
const 전공 = formResponse["전공"] ? formResponse["전공"].toString() : "정보 없음";
const 학력 = formResponse["학력"] ? formResponse["학력"].toString() : "정보 없음";
const 병역 = formResponse["병역"] ? formResponse["병역"].toString() : "정보 없음";
const 이메일 = formResponse["이메일"] ? formResponse["이메일"].toString() : "정보 없음";
const spreadsheetUrl = SpreadsheetApp.getActiveSpreadsheet().getUrl();
// Slack 메시지 구성 (Block Kit 사용)
const blocks = [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "✨ 신규 입사자 등록",
"emoji": true
}
},
{
"type": "divider"
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": `*성명: ${성명}` },
{ "type": "mrkdwn", "text": `*입사일: ${입사일}` },
{ "type": "mrkdwn", "text": `*생일: ${생일}` },
{ "type": "mrkdwn", "text": `*휴대폰 번호: ${휴대폰번호}` }
]
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": `*주민등록번호: ${주민등록번호}` }, // 주민등록번호 추가
{ "type": "mrkdwn", "text": `*이메일: ${이메일}` }
]
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": `*주소: ${주소}` }
]
},
{
"type": "divider"
},
// 이전의 "자세한 개인 정보 (주민등록번호, 여권 등)는 보안상 별도 표기하지 않습니다." 섹션 제거
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": `*여권상 영문이름: ${여권상영문이름}` },
{ "type": "mrkdwn", "text": `*여권 번호: ${여권번호}` },
{ "type": "mrkdwn", "text": `*여권 만료일: ${여권만료일}` }
]
},
{
"type": "divider"
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": `*최종 출신학교: ${최종출신학교}` },
{ "type": "mrkdwn", "text": `*전공: ${전공}` },
{ "type": "mrkdwn", "text": `*학력: ${학력}` },
{ "type": "mrkdwn", "text": `*병역: ${병역}` }
]
},
{
"type": "divider"
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": `<${spreadsheetUrl}|📊 모든 응답 자세히 보기>`
}
]
}
];
// Slack에 전송할 페이로드 구성
const payload = {
"text": "새로운 입사자 등록 알림",
"blocks": blocks,
"username": "입사자 알림 봇",
"icon_emoji": ":fire:"
};
const options = {
"method": "post",
"contentType": "application/json",
"payload": JSON.stringify(payload)
};
try {
const response = UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);
Logger.log("슬랙 알림 전송 성공: " + response.getContentText());
} catch (error) {
Logger.log("슬랙 알림 전송 실패: " + error.toString());
}
}
'컴퓨터 > google spreadsheet' 카테고리의 다른 글
구글스프레드시트 slack 메시지 발송-조현정의AI실험실 (0) | 2025.05.20 |
---|---|
구글폼 구글스프레드시트 슬랙 연동 (0) | 2025.05.19 |
구글스프레드시트 AppsScript slack 보내기 (0) | 2025.05.19 |