발행일: 2026-10-06(화) 11:44
← 목차로 돌아가기|하루 30분 n8n 시리즈 ② 실무 자동화 레시피 100
RECIPE 015

이메일 뉴스레터 오픈율 추적 → 시트 기록

  • ▸여러 쇼핑몰 페이지에서 HTTP Request로 가격 데이터를 수집할 수 있다
  • ▸HTML Extract로 가격 요소를 파싱하고 숫자로 정제할 수 있다
  • ▸최저가 변동 시 Slack 또는 이메일로 즉시 알림을 보낼 수 있다

✅사전 준비

  • □모니터링할 상품 URL 목록 준비 (쇼핑몰별 2~3개)
  • □각 URL의 가격 CSS 셀렉터 확인 (크롬 개발자 도구 F12)
  • □Google Sheets에 가격 이력 저장용 시트 생성
  • □Slack 또는 Gmail 자격증명 연결 완료

상품 목록 정의 — Edit Fields 또는 Code 노드

return [
  { json: { name: "상품A", url: "https://shop.example.com/product/1", selector: ".price" } },
  { json: { name: "상품B", url: "https://shop.example.com/product/2", selector: "#productPrice" } },
  { json: { name: "상품C", url: "https://shop.example.com/product/3", selector: "[data-price]" } },
];

가격 문자열 정제 — Code 노드

const raw = $input.first().json.extractedPrice ?? "";
// 숫자만 추출 (쉼표, 원, 공백 제거)
const price = parseInt(raw.replace(/[^0-9]/g, ""), 10);
return [{ json: { price, raw, ...$input.first().json } }];

이전 가격 대비 변동 체크 — IF 노드

가격 하락 감지:
{{ $json.price < $json.previousPrice }}

5% 이상 하락:
{{ ($json.previousPrice - $json.price) / $json.previousPrice > 0.05 }}

Slack 가격 하락 알림

💰 가격 인하 알림!
상품: {{ $json.name }}
이전: {{ $json.previousPrice.toLocaleString() }}원
현재: *{{ $json.price.toLocaleString() }}원*
변동: {{ ($json.previousPrice - $json.price).toLocaleString() }}원 ↓
🔗 {{ $json.url }}
⚠️ 주의일부 쇼핑몰은 봇 차단 정책이 있어 HTTP Request만으로 가격을 가져오지 못할 수 있습니다. User-Agent 헤더를 브라우저 값으로 설정하거나, 공식 API/제휴 서비스 이용을 권장합니다.
⚡

워크플로우 JSON

아래 JSON을 복사해 n8n에 바로 임포트하세요

📥 n8n 임포트 방법
n8n 화면 우측 상단 메뉴 (⋮) → Import from JSON → 아래 JSON 전체 복사 후 붙여넣기 → Import 클릭
{
  "name": "recipe015_newsletter_open_rate_tracking",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 10 * * *"
            }
          ]
        }
      },
      "id": "schedule-015-01",
      "name": "매일 오전 10시",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        200,
        400
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://us1.api.mailchimp.com/3.0/campaigns?sort_field=send_time&sort_dir=DESC&count=1",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "http-015-02",
      "name": "Mailchimp 최신 캠페인 가져오기",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        420,
        400
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://us1.api.mailchimp.com/3.0/reports/{{ $json.campaigns[0].id }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "http-015-03",
      "name": "캠페인 성과 데이터 가져오기",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        640,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "const r = $json;\nreturn [{\n  json: {\n    campaignName: r.campaign_title || '',\n    sendDate: r.send_time ? r.send_time.slice(0,10) : '',\n    openRate: r.opens?.open_rate ? (r.opens.open_rate * 100).toFixed(2) : '0.00',\n    clickRate: r.clicks?.click_rate ? (r.clicks.click_rate * 100).toFixed(2) : '0.00',\n    unsubscribeRate: r.unsubscribes?.unsubscribe_rate ? (r.unsubscribes.unsubscribe_rate * 100).toFixed(2) : '0.00',\n    totalSent: r.emails_sent || 0\n  }\n}];"
      },
      "id": "code-015-04",
      "name": "성과 데이터 정리",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        860,
        400
      ]
    },
    {
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": {
          "value": "={{ $env.NEWSLETTER_SHEET_ID }}"
        },
        "sheetName": {
          "value": "performance"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "campaignName": "={{ $json.campaignName }}",
            "sendDate": "={{ $json.sendDate }}",
            "totalSent": "={{ $json.totalSent }}",
            "openRate": "={{ $json.openRate }}",
            "clickRate": "={{ $json.clickRate }}",
            "unsubscribeRate": "={{ $json.unsubscribeRate }}"
          }
        },
        "options": {
          "upsertOptions": {
            "upsertKey": "campaignName"
          }
        }
      },
      "id": "sheets-015-05",
      "name": "Google Sheets 기록",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        1080,
        400
      ]
    }
  ],
  "connections": {
    "매일 오전 10시": {
      "main": [
        [
          {
            "node": "Mailchimp 최신 캠페인 가져오기",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mailchimp 최신 캠페인 가져오기": {
      "main": [
        [
          {
            "node": "캠페인 성과 데이터 가져오기",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "캠페인 성과 데이터 가져오기": {
      "main": [
        [
          {
            "node": "성과 데이터 정리",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "성과 데이터 정리": {
      "main": [
        [
          {
            "node": "Google Sheets 기록",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "timezone": "Asia/Seoul"
  },
  "meta": {
    "chapter": 2,
    "recipe": "015",
    "title": "이메일 뉴스레터 오픈율 추적 → 시트 기록",
    "difficulty": "⭐⭐",
    "estimatedTime": "30분",
    "apps": [
      "Mailchimp API",
      "Google Sheets"
    ]
  }
}
← 이전 레시피☰ 목차다음 레시피 →