신규 고객모든 신규 계정에 DNS와 CDN 무료 요금제를 제공합니다.계정 만들기

이벤트 및 웹훅

발송 기록에서 메시지 상태를 확인하고, 서명된 전달, 반송, 스팸 신고, 열람, 클릭 이벤트를 자체 엔드포인트로 받습니다.

5 분 소요 업데이트 2026년 10월 20일

발송하는 모든 메시지에는 메시지 ID가 부여되며, 대기, 전달, 재시도, 반송 과정에 따라 여러 상태를 거칩니다. 이 과정은 콘솔의 발송 기록에서 확인하거나, API로 조회하거나, 웹훅을 통해 각 이벤트를 자체 서버로 받을 수 있습니다.

메시지 상태

각 수신자 사본에는 하나의 상태가 있습니다. 상태는 앞으로만 진행됩니다. 예를 들어 전달된 메시지가 이후 반송이나 스팸 신고 상태가 될 수는 있지만 대기 상태로 돌아가지는 않습니다.

상태콘솔 레이블의미
queued대기 중수락되어 전달을 기다리는 중입니다
deferred지연 재시도수신 서버가 일시적 오류를 반환했습니다. 최대 72시간 동안 전달을 재시도합니다.
delivered전달됨수신 서버가 메시지를 수락했습니다
bounced반송전달 중에 또는 나중에 수신된 반송 보고서를 통해 전달이 영구적으로 실패했습니다. 아래 반송 유형을 참조하십시오.
complained스팸 신고수신자가 메시지를 스팸으로 표시했습니다
rejected거부됨수신자가 억제되었거나, 샌드박스에서 허용되지 않거나, 콘텐츠가 거부되는 등의 이유로 발송 전에 거부되었습니다
failed실패72시간 동안 재시도한 후에도 전달할 수 없었거나 대기열에 넣을 수 없었습니다

열람, 클릭, 수신 거부는 상태가 아닙니다. 이들은 메시지에 기록되며(opened_at, clicked_at, unsubscribed_at) 웹훅 이벤트로 전송됩니다. 발송 기록에서 열람된 메시지에는 열람함 태그가 추가로 표시됩니다.

반송 유형

유형발생 조건결과
하드알 수 없는 사용자 등 영구적인 5xx 거부주소가 전역 억제 목록에 추가됩니다
소프트메일함 용량 초과(x.2.2) 또는 시스템, 네트워크, 정책에 따른 거부(x.3.x~`x.7.x`, 예: IP 평판 차단)주소가 억제되지 않습니다

발송 기록

스트림의 발송 기록 탭에는 최근 30일간의 메시지가 시각, 수신자, 제목, 카테고리, 출처(API 또는 SMTP), 상태와 함께 나열됩니다. 수신자, 상태, 출처, 카테고리, 날짜 범위로 필터링할 수 있습니다.

메시지를 클릭하면 메시지 상세가 열립니다. 상태, 발신자, 제목, 카테고리, 태그, 수신 서버의 마지막 응답, 그리고 각 전달 시도의 SMTP 코드, 응답, 반송 유형, MX 호스트, IP가 포함된 이벤트 목록이 표시됩니다.

개요 탭에는 같은 데이터가 7일 또는 30일 기준으로 집계됩니다. 발송, 전달률, 반송률, 스팸 신고율, 열람, 클릭이 표시됩니다.

웹훅

웹훅은 이벤트가 발생할 때마다 고객의 HTTPS 엔드포인트로 전송하므로, 예를 들어 애플리케이션에서 하드 반송 후 사용자의 주소를 유효하지 않은 것으로 표시할 수 있습니다.

웹훅 설정

  1. 스트림을 열고 Webhook 탭으로 이동합니다.
  2. 수신 URL에 공용 인터넷상의 https:// URL을 입력합니다. 사설 및 로컬 주소는 허용되지 않습니다.
  3. 이벤트에서 받을 이벤트를 선택합니다. 기본적으로 모든 이벤트가 선택되어 있습니다.
  4. 저장을 클릭합니다. URL을 처음 저장할 때 서명 시크릿이 한 번 표시됩니다. whsec_로 시작합니다. 서버에 저장하십시오.
  5. 테스트 전송을 클릭하여 test 이벤트를 보내고 엔드포인트가 응답하는지 확인합니다.

새 비밀 키를 받으려면 서명 시크릿 재설정을 클릭합니다. 이전 비밀 키는 즉시 작동을 멈춥니다. 이벤트 수신을 중단하려면 URL을 지우고 저장합니다.

이벤트

이벤트콘솔 레이블전송 시점
delivered전달됨수신 서버가 메시지를 수락했을 때
deferred지연(tarpit)전달 시도가 일시적으로 실패했을 때. 시도할 때마다 한 번씩 전송됩니다.
bounced반송영구적으로 실패했을 때. data.bounce_type은 hard 또는 soft입니다.
complained스팸 신고수신자가 메시지를 스팸으로 신고했을 때
failed실패72시간 후 전달을 포기했을 때
rejected거부발송 서버가 수신자를 거부했을 때
opened열기메시지가 처음 열람되었을 때(열람 추적 필요)
clicked클릭추적 링크를 클릭할 때마다(클릭 추적 필요)
unsubscribed수신 거부수신자가 수신 거부했을 때

HTTP API 자체에서 거부한 수신자는 API 응답의 rejected 필드로 반환되며 웹훅을 생성하지 않습니다.

요청 형식

각 이벤트는 JSON 본문이 포함된 POST로 전송됩니다.

http
POST /your/webhook HTTP/1.1
Content-Type: application/json
User-Agent: Yeap-TM-Webhook/1
X-Yeap-Signature: t=1760955304,v1=5f2b9c...e81a

{
  "id": "evt_01JAQ40B2C3D4E5F6G7H8J9K0M",
  "type": "bounced",
  "stream_id": 12,
  "message_id": "01JAQ3Z9V8K4M2N6P7R5S1T0XW",
  "created_at": "2026-10-20T10:15:04+00:00",
  "data": {
    "rcpt": "alice@example.org",
    "smtp_code": 550,
    "smtp_response": "5.1.1 The email account that you tried to reach does not exist",
    "bounce_type": "hard",
    "mx": "mx.example.org"
  }
}

id는 이벤트마다 고유하므로 중복을 무시하는 데 사용하십시오. data의 내용은 이벤트에 따라 다릅니다.

이벤트data 필드
delivered, deferred, bounced, complained, failed, rejectedrcpt, 그리고 가능한 경우 smtp_code, smtp_response, bounce_type, mx, at
openedrcpt, ip, user_agent
clickedrcpt, url, ip, user_agent
unsubscribedrcpt, category, via
testmessage

서명 검증

X-Yeap-Signature 헤더는 t=<timestamp>,v1=<signature> 형식입니다. 서명은 전체 서명 비밀 키(whsec_ 포함)를 키로 사용하여 <timestamp>.<raw request body>에 대해 계산한 HMAC-SHA256의 16진수 값입니다. 요청을 검증하는 방법:

  1. JSON을 파싱하기 전에 수신한 원본 본문을 그대로 읽습니다.
  2. t + "." + body에 대해 HMAC을 계산하고 상수 시간 비교로 v1과 비교합니다.
  3. 재전송 공격을 막기 위해 타임스탬프가 5분보다 오래된 요청은 거부합니다.

Python:

python
import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    ts, sig = parts.get("t", ""), parts.get("v1", "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > tolerance:
        return False
    expected = hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

Node.js:

javascript
const crypto = require('crypto');

function verify(secret, header, rawBody, tolerance = 300) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const ts = Number(parts.t);
  if (!ts || Math.abs(Date.now() / 1000 - ts) > tolerance) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 || '');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

응답 및 재시도

  • 10초 이내에 2xx 상태로 응답하십시오. 그 밖의 응답은 실패로 간주됩니다.
  • 실패한 전송은 점점 늘어나는 간격으로 재시도되며, 간격은 1분에서 시작해 최대 4시간까지 늘어납니다. 재시도는 이벤트 발생 24시간 후에 중단됩니다.
  • 이벤트는 두 번 이상 도착하거나 순서가 바뀌어 도착할 수 있습니다. 이벤트 id로 중복을 건너뛰고, 메시지 상태로 현재 상태를 판단하십시오.

Webhook 탭의 최근 전송 표에는 최근 100건의 전송이 이벤트, 상태(전송 대기 대기, 성공 성공, 재시도 중 재시도 중, 포기됨 포기됨), 시도 횟수, 마지막 오류, 다음 시도 시각과 함께 표시됩니다.

관련 문서

이 페이지가 도움이 되었습니까?