RECIPE 060
Mailchimp 캠페인 성과 → Sheets 자동 기록
- ▸Mailchimp 이메일 캠페인 발송 후 성과 지표 자동 수집
- ▸오픈율, 클릭률, 구독 취소율을 Google Sheets에 기록
- ▸성과 기준 미달 시 마케팅팀 Slack 알림
✅사전 준비
- □Mailchimp API 키 발급 (Account → Extras → API Keys)
- □Mailchimp 서버 접두사 확인 (API 키 끝 예: us21)
- □Google Sheets 성과 기록용 시트 생성
- □KPI 기준값 설정 (예: 오픈율 20% 이상)
캠페인 목록 조회
Node: HTTP Request
Method: GET
URL: https://us21.api.mailchimp.com/3.0/campaigns
Query Parameters:
status: sent
count: 10
sort_field: send_time
sort_dir: DESC
Authentication: Basic Auth
Username: anystring
Password: YOUR_API_KEY캠페인 리포트 조회
Node: HTTP Request
Method: GET
URL: https://us21.api.mailchimp.com/3.0/reports/{{ $json.id }}
Authentication: Basic Auth
Username: anystring
Password: YOUR_API_KEY
// 추출 필드
openRate: $json.opens.open_rate
clickRate: $json.clicks.click_rate
unsubscribeRate: $json.unsubscribes.unsubscribe_rate성과 미달 알림 조건 (IF 노드)
Condition 1: {{ $json.opens.open_rate }} < 0.2 (오픈율 20% 미만)
Condition 2: {{ $json.clicks.click_rate }} < 0.02 (클릭률 2% 미만)
두 조건 중 하나라도 충족 시 → Slack 알림💡 TIPMailchimp 서버 접두사(us1, us21 등)는 계정마다 다릅니다. API 키 마지막 부분(예: `abc123-us21`)에서 `us21`이 서버 접두사입니다.
⚡
워크플로우 JSON
아래 JSON을 복사해 n8n에 바로 임포트하세요
📥 n8n 임포트 방법
n8n 화면 우측 상단 메뉴 (⋮) → Import from JSON → 아래 JSON 전체 복사 후 붙여넣기 → Import 클릭
n8n 화면 우측 상단 메뉴 (⋮) → Import from JSON → 아래 JSON 전체 복사 후 붙여넣기 → Import 클릭
{
"recipeId": "recipe060",
"title": "HR KPI 대시보드 자동 업데이트",
"chapter": 5,
"category": "HR & 조직 운영 자동화",
"difficulty": "⭐⭐",
"estimatedTime": "35분",
"usedApps": [
"Google Sheets",
"Slack"
],
"description": "매주 월요일 오전 8시에 직원 명단 시트에서 입사자·퇴직자·현재 직원 수·이직률 등 HR 핵심 지표를 자동 집계하여 대시보드 시트를 업데이트하고 주요 변화를 Slack에 요약 발송합니다.",
"nodes": [
{
"id": "trigger_schedule",
"type": "trigger",
"service": "Schedule",
"name": "매주 월요일 오전 8시",
"config": {
"interval": "weekly",
"dayOfWeek": "monday",
"time": "08:00"
}
},
{
"id": "get_employee_data",
"type": "action",
"service": "Google Sheets",
"name": "직원 명단 전체 조회",
"config": {
"operation": "readRows",
"spreadsheetId": "{{$env.HR_SHEET_ID}}",
"sheetName": "직원명단",
"columns": [
"이름",
"입사일",
"퇴직일",
"재직상태",
"부서",
"직책"
]
}
},
{
"id": "calc_kpi",
"type": "action",
"service": "Function",
"name": "HR KPI 계산",
"config": {
"code": "const employees = $items();\nconst today = new Date($now.toISO());\nconst thisWeekStart = new Date(today);\nthisWeekStart.setDate(today.getDate() - 7);\nconst thisMonthStart = new Date(today.getFullYear(), today.getMonth(), 1);\n\n// 현재 재직자\nconst activeEmployees = employees.filter(e => e.json['재직상태'] === '재직');\n\n// 이번 주 입사자\nconst newHiresThisWeek = employees.filter(e => {\n const joinDate = new Date(e.json['입사일']);\n return joinDate >= thisWeekStart && joinDate <= today;\n});\n\n// 이번 달 퇴직자\nconst resignedThisMonth = employees.filter(e => {\n if (!e.json['퇴직일']) return false;\n const resignDate = new Date(e.json['퇴직일']);\n return resignDate >= thisMonthStart && resignDate <= today;\n});\n\n// 이직률 (월간)\nconst turnoverRate = activeEmployees.length > 0 \n ? ((resignedThisMonth.length / activeEmployees.length) * 100).toFixed(1)\n : 0;\n\n// 평균 근속 기간 (개월)\nconst avgTenure = activeEmployees.length > 0\n ? (activeEmployees.reduce((sum, e) => {\n const joinDate = new Date(e.json['입사일']);\n const months = (today - joinDate) / (1000 * 60 * 60 * 24 * 30);\n return sum + months;\n }, 0) / activeEmployees.length).toFixed(1)\n : 0;\n\n// 부서별 인원\nconst deptCount = {};\nactiveEmployees.forEach(e => {\n const dept = e.json['부서'] || '미분류';\n deptCount[dept] = (deptCount[dept] || 0) + 1;\n});\n\nreturn [{ json: {\n week: $now.format('YYYY-WW주'),\n totalActive: activeEmployees.length,\n newHiresThisWeek: newHiresThisWeek.length,\n resignedThisMonth: resignedThisMonth.length,\n turnoverRate: parseFloat(turnoverRate),\n avgTenureMonths: parseFloat(avgTenure),\n deptBreakdown: JSON.stringify(deptCount),\n recordedAt: $now.format('YYYY-MM-DD HH:mm')\n} }];"
}
},
{
"id": "update_dashboard",
"type": "action",
"service": "Google Sheets",
"name": "KPI 대시보드 업데이트",
"config": {
"operation": "appendRow",
"spreadsheetId": "{{$env.HR_SHEET_ID}}",
"sheetName": "HR_KPI대시보드",
"row": {
"기준주차": "{{$json['week']}}",
"총재직자수": "{{$json['totalActive']}}",
"이번주신규입사": "{{$json['newHiresThisWeek']}}",
"이번달퇴직자": "{{$json['resignedThisMonth']}}",
"이직률(%)": "{{$json['turnoverRate']}}",
"평균근속(개월)": "{{$json['avgTenureMonths']}}",
"부서별인원": "{{$json['deptBreakdown']}}",
"기록일시": "{{$json['recordedAt']}}"
}
}
},
{
"id": "get_last_week",
"type": "action",
"service": "Google Sheets",
"name": "전주 데이터 조회",
"config": {
"operation": "readRows",
"spreadsheetId": "{{$env.HR_SHEET_ID}}",
"sheetName": "HR_KPI대시보드",
"limit": 2
}
},
{
"id": "calc_change",
"type": "action",
"service": "Function",
"name": "전주 대비 변화 계산",
"config": {
"code": "const rows = $items();\nif (rows.length < 2) return [{ json: { changeMsg: '(이전 데이터 없음)' } }];\n\nconst current = rows[rows.length - 1].json;\nconst previous = rows[rows.length - 2].json;\n\nconst headcountChange = current['총재직자수'] - previous['총재직자수'];\nconst turnoverChange = (current['이직률(%)'] - previous['이직률(%)']).toFixed(1);\n\nconst sign = n => n > 0 ? `+${n}` : `${n}`;\n\nreturn [{ json: {\n ...current,\n headcountChange: sign(headcountChange),\n turnoverChange: sign(turnoverChange)\n} }];"
}
},
{
"id": "send_slack_summary",
"type": "action",
"service": "Slack",
"name": "주간 HR KPI 요약 발송",
"config": {
"operation": "sendMessage",
"channel": "{{$env.HR_SLACK_CHANNEL}}",
"message": "📊 {{$json['week']}} HR KPI 현황\n\n👥 총 재직자: {{$json['totalActive']}}명 (전주 대비 {{$json['headcountChange']}}명)\n🆕 이번 주 신규 입사: {{$json['newHiresThisWeek']}}명\n👋 이번 달 퇴직: {{$json['resignedThisMonth']}}명\n📉 이직률: {{$json['turnoverRate']}}% (전주 대비 {{$json['turnoverChange']}}%p)\n⏳ 평균 근속: {{$json['avgTenureMonths']}}개월\n\n👉 대시보드 전체 보기: {{$env.HR_DASHBOARD_URL}}"
}
}
],
"edges": [
{
"from": "trigger_schedule",
"to": "get_employee_data"
},
{
"from": "get_employee_data",
"to": "calc_kpi"
},
{
"from": "calc_kpi",
"to": "update_dashboard"
},
{
"from": "update_dashboard",
"to": "get_last_week"
},
{
"from": "get_last_week",
"to": "calc_change"
},
{
"from": "calc_change",
"to": "send_slack_summary"
}
],
"tips": [
"이직률이 전주 대비 2% 이상 급등한 경우 HR 팀장에게 별도 DM으로 경고 알림을 보내는 IF 분기를 추가해보세요.",
"부서별 인원 현황은 Google Sheets 피벗 차트와 연동하면 시각적으로 표현할 수 있어요.",
"채용 중인 포지션 수와 평균 채용 기간(Time to Fill)도 함께 추적하면 더욱 완성도 높은 HR 대시보드가 돼요."
],
"qrUrl": "www.koreaaitimes.com/books/n8n-vol2/recipe060"
}