Use Case

배송 알림 서비스 구축

카카오톡, SMS, 이메일로 실시간 배송 알림 보내기

쇼핑몰 연동 WMS/물류 시스템 배송 알림 서비스

배송 알림 서비스를 구축하면

  • 고객 만족도 상승 - 고객이 직접 배송 조회할 필요 없음
  • CS 문의 감소 - "제 택배 어디 있어요?" 문의 대폭 감소
  • 브랜드 경험 향상 - 세심한 배송 알림으로 신뢰도 상승
  • 마케팅 접점 확보 - 배송완료 알림에 리뷰 요청, 쿠폰 포함 가능

지원 알림 채널

💬
카카오 알림톡

가장 높은 도달률

📱
SMS/LMS

모든 휴대폰 지원

📧
이메일

상세 정보 전달

🔔
앱 푸시

자체 앱 알림

동작 흐름

송장 등록 배송 상태 변경 웹훅 수신 알림 발송

알림 이벤트

이벤트 설명 알림 예시
tracking.polled 폴링 완료 (상태 변경 시) currentStatus에 따라 분기: "발송되었습니다" / "배송 출발" / "배송 완료"
tracking.completed 전체 배송 완료 "배송이 완료되었습니다. 리뷰를 남겨주세요!"

구현 가이드

1단계: 웹훅 수신 서버 구축

1 웹훅 엔드포인트 생성

// Express.js 웹훅 서버
const express = require('express');
const app = express();

app.post('/webhook/delivery', express.json(), async (req, res) => {
  const { event, items } = req.body;

  console.log(`이벤트 수신: ${event}`);

  for (const item of items) {
    switch (event) {
      case 'tracking.polled':
        await sendNotification(item, '상태 변경');
        break;
      case 'tracking.completed':
        await sendNotification(item, '전체 배송완료');
        break;
    }
  }

  res.json({ received: true });
});

app.listen(3000);

2단계: 카카오 알림톡 연동

2 알림톡 발송 함수

const axios = require('axios');

async function sendKakaoAlimtalk(phone, templateCode, variables) {
  // 카카오 비즈메시지 API (예시)
  const response = await axios.post(
    'https://api.kakao.com/v2/api/talk/memo/send',
    {
      template_object: {
        object_type: 'text',
        text: formatMessage(templateCode, variables),
        link: {
          web_url: `https://yourshop.com/tracking/${variables.trackingNumber}`
        }
      }
    },
    {
      headers: { 'Authorization': `Bearer ${KAKAO_ACCESS_TOKEN}` }
    }
  );

  return response.data;
}

// 템플릿 메시지 포맷
function formatMessage(templateCode, vars) {
  const templates = {
    'DELIVERY_START': `[${vars.shopName}] 주문하신 상품이 발송되었습니다.\n\n` +
      `상품: ${vars.productName}\n` +
      `송장번호: ${vars.trackingNumber}\n` +
      `택배사: ${vars.courierName}\n\n` +
      `배송조회: ${vars.trackingUrl}`,

    'DELIVERY_COMPLETE': `[${vars.shopName}] 배송이 완료되었습니다!\n\n` +
      `상품: ${vars.productName}\n` +
      `배송완료: ${vars.deliveredAt}\n\n` +
      `상품은 만족스러우셨나요?\n` +
      `리뷰 작성하기: ${vars.reviewUrl}`
  };

  return templates[templateCode];
}

3단계: SMS 발송 연동

3 SMS 발송 함수

// NHN Cloud SMS API 예시
async function sendSMS(phone, message) {
  const response = await axios.post(
    `https://api-sms.cloud.toast.com/sms/v3.0/appKeys/${APP_KEY}/sender/sms`,
    {
      body: message,
      sendNo: '15881234',  // 발신번호
      recipientList: [
        { recipientNo: phone }
      ]
    },
    {
      headers: {
        'Content-Type': 'application/json',
        'X-Secret-Key': SECRET_KEY
      }
    }
  );

  return response.data;
}

// 알림 발송 메인 함수
async function sendNotification(data, eventType) {
  const order = await Order.findOne({
    where: { trackingNumber: data.trackingNumber }
  });

  if (!order) return;

  const message = createMessage(eventType, order, data);

  // 채널 우선순위: 카카오 → SMS → 이메일
  try {
    // 카카오 알림톡 먼저 시도
    await sendKakaoAlimtalk(order.phone, `DELIVERY_${eventType}`, {
      shopName: '쇼핑몰명',
      productName: order.productName,
      trackingNumber: data.trackingNumber,
      courierName: getCourierName(data.courierCode),
      trackingUrl: `https://yourshop.com/tracking/${data.trackingNumber}`,
      deliveredAt: new Date().toLocaleString('ko-KR'),
      reviewUrl: `https://yourshop.com/review/${order.id}`
    });
  } catch (kakaoError) {
    // 카카오 실패 시 SMS로 대체
    console.log('카카오 알림톡 실패, SMS로 대체 발송');
    await sendSMS(order.phone, message);
  }
}

4단계: 이메일 알림

4 이메일 발송 (상세 정보 포함)

const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASS
  }
});

async function sendEmail(to, subject, trackingData) {
  const progressHtml = trackingData.progresses
    .map(p => `
      
        ${p.dateTime}
        ${p.location}
        ${p.description}
      
    `).join('');

  const html = `
    

배송 안내

택배사: ${trackingData.courierName}

송장번호: ${trackingData.trackingNumber}

현재 상태: ${trackingData.statusText}

배송 진행 상황

${progressHtml}
시간 위치 상태
`; await transporter.sendMail({ from: '"쇼핑몰" ', to, subject, html }); }

고급 기능

알림 중복 방지

// Redis를 사용한 중복 알림 방지
const Redis = require('ioredis');
const redis = new Redis();

async function shouldSendNotification(trackingNumber, eventType) {
  const key = `notification:${trackingNumber}:${eventType}`;

  // 이미 발송된 알림인지 확인
  const exists = await redis.exists(key);
  if (exists) {
    return false;  // 이미 발송됨
  }

  // 7일간 중복 방지 (배송 완료 후 충분한 기간)
  await redis.setex(key, 7 * 24 * 60 * 60, 'sent');
  return true;
}

// 웹훅 핸들러에서 사용
app.post('/webhook/delivery', async (req, res) => {
  const { event, items } = req.body;

  for (const item of items) {
    if (await shouldSendNotification(item.trackingNumber, event)) {
      await sendNotification(item, event);
    }
  }

  res.json({ received: true });
});

사용자 알림 설정

// 사용자별 알림 선호 설정
const userPreferences = {
  channels: ['kakao', 'email'],  // 수신 채널
  events: ['IN_TRANSIT', 'DELIVERED'],  // 수신할 이벤트
  quietHours: { start: 22, end: 8 }  // 야간 알림 금지
};

async function sendNotificationWithPreference(userId, data, eventType) {
  const prefs = await UserPreference.findOne({ where: { userId } });

  // 이벤트 설정 확인
  if (!prefs.events.includes(eventType)) {
    return;
  }

  // 야간 시간 확인
  const hour = new Date().getHours();
  if (hour >= prefs.quietHours.start || hour < prefs.quietHours.end) {
    // 야간에는 큐에 저장 후 아침에 발송
    await NotificationQueue.create({
      userId, data, eventType,
      scheduledAt: getNextMorning()
    });
    return;
  }

  // 선호 채널로 발송
  for (const channel of prefs.channels) {
    await sendByChannel(channel, data);
  }
}

알림 메시지 템플릿

효과적인 알림 메시지 작성 팁

  • 간결하게 - 핵심 정보만 포함 (상품명, 송장번호, 현재 상태)
  • CTA 포함 - 배송조회 링크, 리뷰 작성 버튼
  • 브랜드 일관성 - 쇼핑몰 이름, 로고 활용
  • 적절한 타이밍 - 중요한 이벤트만 알림 (너무 잦으면 차단)

다른 유스케이스

지금 바로 알림 서비스를 구축하세요

웹훅으로 실시간 배송 상태를 받아 고객에게 알림을 보내세요

무료로 시작하기 →