이벤트 기반 이메일 운영

전달 업데이트를 위해 대시보드를 폴링하지 마세요. 수락, 전달, 바운스, 불만 이벤트를 애플리케이션과 워크플로로 직접 푸시합니다.

웹훅으로 제품 상태를 동기화하고, 재시도를 트리거하며, 팀에 알리고, 고객 상태를 정확하게 유지합니다.

Webhook delivery depends on stable routing and proper retry logic. Pair with email routing for failover-aware delivery and deliverability monitoring for reputation-aware event handling.

웹훅 이벤트 스트림 보기

웹훅 기능

웹훅은 이메일을 제품이 실시간으로 해석할 수 있는 이벤트 스트림으로 바꿉니다.

전달 상태 동기화

메시지가 수락에서 전달 또는 바운스로 이동할 때 사용자 대면 상태를 업데이트합니다.

실패 자동화

일시적 또는 영구적 실패가 감지되면 재시도 경로와 내부 알림을 트리거합니다.

평판 보호

불만 및 바운스 이벤트를 자동 처리해 나쁜 주소가 향후 발송에서 제외되도록 합니다.

워크플로 통합

이벤트를 CRM, 데이터 웨어하우스, 큐 워커, 사고 대응 시스템으로 공급합니다.

서명 검증

들어오는 웹훅 서명을 검증해 신뢰할 수 있는 Sendarix 이벤트만 처리합니다.

재시도 안전 소비자

중복 전달 및 지연 이벤트를 안전하게 처리하는 멱등 핸들러를 설계합니다.

웹훅 라이프사이클

신뢰할 수 있는 이벤트 기반 자동화를 구축하기 위한 직관적인 흐름.

1. 메시지 보내기

메시지가 API 또는 SMTP를 통해 전달 파이프라인에 들어갑니다.

2. 이벤트 생성

전달 시스템이 상태 이벤트(수락, 전달, 바운스, 불만)를 생성합니다.

3. 웹훅 전달

이벤트가 즉시 처리를 위해 엔드포인트에 게시됩니다.

4. 앱 반응

시스템이 사용자 상태를 업데이트하고, 작업을 트리거하거나 팀에 자동으로 알립니다.

Real-World Scenario: Bounce-Driven Suppression

An application POSTs a message via the email API. The recipient server returns a hard bounce, which is captured by email webhooks and relayed to your system. Your handler adds the address to the suppression list, ensuring no further send attempts. email analytics reflects the suppressed status in the next reporting cycle.

Supported Event Types

Sendarix delivers webhooks for the following event types. Filter by event type when configuring your endpoint.

Event Type Description
acceptedMessage accepted by Sendarix infrastructure
deliveredMessage accepted by recipient mail server
bouncePermanent delivery failure (invalid address)
soft_bounceTemporary delivery failure (mailbox full, Greylisted)
complaintRecipient marked message as spam
unsubscribeRecipient clicked unsubscribe link
openMessage opened (tracking pixel fired)
clickTracked link clicked
deferredTemporary delay - will retry automatically

Example Webhook Payload

Below is a simplified example of a delivery event:

{
  "event": "delivered",
  "message_id": "abc123",
  "recipient": "user@example.com",
  "timestamp": 1710000000
}

Common Webhook Implementation Mistakes

Not handling retries properly

Ignoring duplicate events (lack of idempotency)

Not verifying webhook signatures

Slow endpoints causing delivery timeouts

Pair webhooks with the email API for event-driven automation, and use email analytics to monitor delivery rates and identify issues in real time.

Payload Examples

Every webhook delivers a JSON payload with a consistent envelope structure. Below are examples of the most common event types.

Envelope Structure

All payloads share this top-level structure:

{
  "event_id": "evt_8f3k2j1h9g6d",
  "event_type": "delivered",
  "timestamp": "2026-04-19T14:32:01Z",
  "message_id": "msg_abc123xyz",
  "recipient": "user@example.com",
  "data": {
    // event-specific fields
  }
}

Delivered Event

Fired when a message is accepted by the recipient's mail server.

{
  "event_id": "evt_8f3k2j1h9g6d",
  "event_type": "delivered",
  "timestamp": "2026-04-19T14:32:01Z",
  "message_id": "msg_abc123xyz",
  "recipient": "user@example.com",
  "data": {
    "smtp_response": "250 OK",
    "server": "mail-sor-iad.example.com",
    "delivery_latency_ms": 312
  }
}

Bounce Event

Fired when a message is rejected by the recipient's mail server. Includes bounce type (hard/soft) and error code.

{
  "event_id": "evt_9h4k3l2m7n5p",
  "event_type": "bounce",
  "timestamp": "2026-04-19T14:30:45Z",
  "message_id": "msg_abc123xyz",
  "recipient": "invalid@example.com",
  "data": {
    "bounce_type": "hard",
    "bounce_category": "invalid_email",
    "smtp_code": 550,
    "smtp_message": "No such user",
    "was_automatic": true
  }
}

Complaint Event

Fired when a recipient marks your message as spam. Automatically suppressed for future sends.

{
  "event_id": "evt_1a2b3c4d5e6f",
  "event_type": "complaint",
  "timestamp": "2026-04-19T15:01:22Z",
  "message_id": "msg_abc123xyz",
  "recipient": "user@example.com",
  "data": {
    "complaint_type": "abuse",
    "feedback_type": "auth-failure",
    "user_agent": "Mozilla/5.0 (complaint reporter)"
  }
}

Open Event

Fired when a message is opened by the recipient (requires tracking pixel).

{
  "event_id": "evt_7g8h9i0j1k2l",
  "event_type": "open",
  "timestamp": "2026-04-19T14:45:10Z",
  "message_id": "msg_abc123xyz",
  "recipient": "user@example.com",
  "data": {
    "ip": "203.0.113.42",
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
    "os": "Windows 10",
    "client": "Chrome 124.0"
  }
}

Click Event

Fired when a recipient clicks a tracked link in the message.

{
  "event_id": "evt_3m4n5o6p7q8r",
  "event_type": "click",
  "timestamp": "2026-04-19T14:47:33Z",
  "message_id": "msg_abc123xyz",
  "recipient": "user@example.com",
  "data": {
    "link_id": "lnk_abc123",
    "url": "https://yoursite.com/confirm?token=xyz",
    "ip": "203.0.113.42",
    "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_4)",
    "os": "iOS 17.4"
  }
}

Retry Logic and Failure Handling

Webhook delivery uses exponential backoff with jitter to handle transient failures without overwhelming your endpoint.

Retry Schedule

Failed deliveries (non-2xx, timeout, connection error) are retried at increasing intervals: attempt 1 immediately, attempt 2 after 30 seconds, attempt 3 after 5 minutes, attempt 4 after 30 minutes, attempt 5 after 2 hours, attempt 6 after 5 hours. After 6 failed attempts, the event is marked as permanently failed and no further retries occur.

1
Immediate
2
30s
3
5min
4
30min
5
2hr
6
5hr

Best Practices for Retry-Safe Handlers

Use the event ID in a deduplication table or cache to prevent duplicate processing.

Acknowledge the HTTP request immediately (< 1 second) and process events asynchronously.

Return 2xx before validating signatures to avoid timeout-triggered retries of valid events.

Log received event IDs to aid debugging and manual replay if needed.

Implement a dead-letter queue for events that permanently fail so they can be manually inspected.

Timeout Behavior

If your endpoint does not respond within 10 seconds, the delivery is marked as failed and enters the retry queue immediately.

Security and Verification

Webhook endpoints should validate that requests originate from Sendarix and are not replayed or tampered with.

HMAC Signature Verification

Each webhook request includes an X-Sendarix-Signature header containing an HMAC-SHA256 signature of the raw request body, signed with your endpoint's shared secret. Always verify this signature before processing the payload.

// Node.js signature verification example
const crypto = require('crypto');

function verifySignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express.js middleware
app.post('/webhooks', (req, res) => {
  const signature = req.headers['x-sendarix-signature'];
  const timestamp = req.headers['x-sendarix-timestamp'];
  const secret = process.env.WEBHOOK_SECRET;
  
  // Check timestamp freshness (reject > 5 min old)
  if (Date.now() - parseInt(timestamp, 10) * 1000 > 300000) {
    return res.status(401).send('Timestamp expired');
  }
  
  // Verify signature
  const rawBody = req.rawBody; // must be raw buffer, not parsed JSON
  if (!verifySignature(rawBody, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process event
  const event = JSON.parse(rawBody);
  res.status(200).send('OK');
});

Timestamp Validation

Requests also include an X-Sendarix-Timestamp header. Reject any request where the timestamp is older than 5 minutes to prevent replay attacks.

Security Best Practices

Never expose your webhook secret in client-side code or version control.

Use HTTPS endpoints only. HTTP endpoints will be rejected.

Rotate secrets periodically and immediately upon suspected compromise.

Validate both signature and timestamp on every request.

Log all validation failures for security audit purposes.

Idempotent Event Handling

Duplicate webhook deliveries are a reality, not an edge case. Network timeouts trigger Sendarix retries, and your endpoint may receive the same event more than once. Idempotent handlers ensure duplicates do not corrupt your application state.

Why Duplicates Happen

Sendarix retries any delivery that returns non-2xx, times out, or fails DNS. If your endpoint returns 200 OK but the response is lost mid-network, Sendarix retries and delivers a second copy. Some load balancers also cause duplicate deliveries when retrying failed requests upstream.

Idempotency Pattern

The standard approach uses a deduplication table keyed on event_id. Before processing, check if the event_id has been processed. If yes, return 200 OK immediately. If no, process the event, mark it as processed, then return 200 OK.

Implementation Example

This example uses a simple in-memory store. In production, use Redis or your database for durability across restarts.

// Node.js idempotent webhook handler
const processedEvents = new Map(); // Replace with Redis/DB in production

app.post('/webhooks', (req, res) => {
  const event = req.body;
  const eventId = event.event_id;

  // Idempotency check - reject if already processed
  if (processedEvents.has(eventId)) {
    console.log(`Duplicate event received: ${eventId}`);
    return res.status(200).send('OK'); // Still return 200 to stop retries
  }

  // Process the event
  try {
    switch (event.event_type) {
      case 'delivered':
        updateNotificationStatus(event.message_id, 'delivered');
        break;
      case 'bounce':
        suppressRecipient(event.recipient);
        break;
      case 'complaint':
        suppressRecipient(event.recipient, 'complaint');
        break;
    }

    // Mark as processed before returning
    processedEvents.set(eventId, Date.now());
    return res.status(200).send('OK');
  } catch (err) {
    console.error('Processing error:', err);
    return res.status(500).send('Processing failed');
  }
});

// TTL cleanup - run periodically in production
setInterval(() => {
  const cutoff = Date.now() - 24 * 60 * 60 * 1000;
  for (const [id, timestamp] of processedEvents) {
    if (timestamp < cutoff) processedEvents.delete(id);
  }
}, 60 * 60 * 1000);

Best Practices

Always check event_id before processing, never after.

Mark events processed atomically: use INSERT ON CONFLICT UPDATE (Postgres) or equivalent.

Keep processed event IDs for at least 24 hours to handle delayed retries.

Process business logic in a separate transaction from the dedup check to avoid race conditions.

Consider setting a TTL on your dedup cache so it does not grow indefinitely for high-volume event streams.

Webhook Endpoint Design Best Practices

A robust webhook endpoint goes beyond signature verification. These practices ensure your integration handles production workloads reliably and avoids the pitfalls that cause data inconsistency and missed events.

Set Appropriate Timeouts

Configure your HTTP client with a 10-second timeout for webhook requests. Sendarix waits up to 10 seconds for a response before triggering a retry. If your handler takes longer (e.g., database writes, external API calls), acknowledge the request immediately with 200 OK and process asynchronously via a job queue.

Process Asynchronously

Webhook handlers should acknowledge within 1 second and defer actual work to a background job. This prevents timeout-triggered retries during slow processing and keeps your endpoint responsive for high event volumes. Use Redis, SQS, or a database-backed job queue.

Return 2xx for Retryable vs Permanent Failures

Return 200 OK for successful processing or permanent failures (unknown event type, invalid payload structure). Return non-2xx only for transient errors (database unavailable, dependency timeout). This tells Sendarix whether to retry immediately or stop retrying.

Log Before and After Processing

Log the event_id, timestamp, and event_type on receipt before processing. Log the outcome (success/failure) and any error details after processing. This gives you a complete record for debugging missed events and reconstructing state during incidents.

Implement a Dead-Letter Queue

After 6 failed delivery attempts, Sendarix marks the event as permanently failed. However, your handler may encounter errors that are not retriable (e.g., a specific recipient is blacklisted in your system, a custom business rule fails). Route these to a dead-letter queue for manual inspection rather than returning a retryable error code.

Handle High-Volume Bursts

Campaign launches and provider incidents can generate webhook bursts of 10,000+ events per minute. Ensure your endpoint scales horizontally (multiple instances behind a load balancer) and your job queue can absorb spikes without losing events or falling behind.

Common Webhook Implementation Mistakes

These mistakes cause the most production incidents in webhook integrations. Avoid them to build a reliable event-driven system.

Processing Synchronously in the HTTP Handler

If your handler writes to a database, calls an external API, or performs complex computation before returning 200 OK, you risk timeouts and unnecessary Sendarix retries. Always enqueue work and return 200 immediately.

Not Validating Event Order

Events may arrive out of order (e.g., a complaint arrives before the delivered event for the same message). Your system must handle this by using message_id as the primary key for state, not relying on event arrival order.

Returning 500 for Permanent Failures

If processing fails because the event is malformed or violates a business rule, return 200 OK to tell Sendarix not to retry. Returning 500 causes Sendarix to retry, which generates duplicate processing attempts and potentially corrupts your state.

Ignoring HTTP Method Validation

Some webhook libraries accept GET and POST to the same endpoint. Sendarix sends POST only. Validate the HTTP method and return 405 Method Not Allowed for any other verb to prevent unexpected behavior.

Processing Without Idempotency Checks

Without event_id deduplication, retry-triggered duplicates cause double-processing: marking a user as unsubscribed twice, decrementing a credit balance twice, sending a notification twice. This is the most common cause of data corruption in webhook integrations.

Hardcoding Webhook Secret

Embedding the webhook secret in source code means rotation requires a code deployment. Store secrets in environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault) and rotate without redeployment.

Not Monitoring Endpoint Health

If your endpoint goes down, events queue at Sendarix for up to 5 hours. Monitor your endpoint's availability, queue depth in the Sendarix dashboard, and set up alerts for queue depth exceeding 1,000 events or processing lag exceeding 5 minutes.

Integrating Webhooks with Your Email Stack

Improving Deliverability with Webhook Data

Webhook event data is your primary signal for improving deliverability. Combine bounce and complaint events with your deliverability dashboard to identify reputation issues before they affect your sender score. High bounce rates (>5%) signal list quality problems; high complaint rates trigger provider-level filtering.

Transactional Email with Real-Time Tracking

Webhook events integrate with your transactional email workflow to provide real-time status updates in your application UI. When a delivery confirmation webhook arrives, update the order status. When a bounce fires, trigger an alternative notification path.

Email Analytics Powered by Webhook Events

Raw webhook events feed your email analytics pipeline with complete delivery and engagement data. Stream events to BigQuery or Redshift for custom reporting, A/B test analysis, and long-term trend tracking beyond what the Sendarix dashboard provides.

Common Webhook Use Cases

Real-time event delivery enables patterns that are difficult or impossible to implement with polling.

User Notification State Sync

Update the notification_status field in your user database when messages are delivered or bounce. Show "Email sent" → "Delivered" in the UI without refreshing.

Suppression List Automation

Automatically add bounced and complained addresses to your suppression list via webhook handler. Prevents wasted send attempts and protects sender reputation.

CRM Engagement Tracking

Feed open and click events into your CRM to score leads, trigger follow-up sequences, or update deal stages based on email engagement.

Incident Alerting

Monitor bounce rates and complaint rates via webhooks. Alert on-call engineers when bounce rates exceed 5% or complaint webhooks fire, indicating potential reputation issues.

Data Warehouse Streaming

Stream all email events to your data warehouse (BigQuery, Redshift, Snowflake) via webhook handler for real-time analytics, ML feature engineering, or compliance archival.

Transactional Workflow Triggers

Trigger downstream workflows when email events fire: send a Slack message to sales when a lead opens a demo email, update shipping status when delivery confirmation arrives.

Start Receiving Email Events in Real Time

Configure your webhook endpoint in minutes. Get delivery, bounce, complaint, open, and click events as they happen.

가장 흔한 구현

고객 타임라인 업데이트, 알림 재시도, 규정 준수 로깅, 지원 대시보드, CRM 참여 동기화.

권장 조합

이벤트 기반 제품 로직을 위해 이메일 API와 함께 사용하고, 스트림 간 성과 검토를 위해 이메일 분석과 함께 사용하세요.

What sets Sendarix apart: Webhooks on Sendarix are not a polling mechanism — they are pushed events with built-in retry, signature verification, and delivery confirmation. You get infrastructure control over event routing, not just a webhook URL.

자주 묻는 질문

웹훅이 폴링을 완전히 대체할 수 있나요?

대부분의 이벤트 기반 워크플로에서는 예. 팀은 여전히 기록 분석 및 보고를 위해 분석을 사용합니다.

시작하기에 가장 중요한 이벤트는 무엇인가요?

전달, 바운스, 불만으로 시작하세요. 그다음 참여 또는 사용자 정의 워크플로 이벤트로 확장합니다.

웹훅은 대규모 시스템 전용인가요?

아닙니다. 작은 앱도 즉시 상태 동기화와 수동 지원 디버깅 감소의 이익을 봅니다.

웹훅 요청이 진짜인지 어떻게 확인하나요?

제공된 경우 공유 비밀, 서명 또는 HMAC 헤더를 사용하고, 재생을 차단하기 위해 타임스탬프를 검증하며, 프로덕션 상태를 업데이트하기 전에 검사에 실패한 페이로드를 거부합니다.

웹훅이 발생할 때 엔드포인트가 다운되면?

재시도 정책에 의존하고 핸들러를 멱등하게 만드세요. 수신한 이벤트 ID를 기록해 재시도의 중복이 데이터베이스나 사용자 알림을 손상시키지 않도록 합니다.

웹훅 처리를 HTTP 요청에서 동기적으로 해야 하나요?

보통 아니오. 빠르게 승인하고 작업을 작업 실행기에 넣고 비동기로 처리해 느린 작업이 타임아웃과 불필요한 재시도를 유발하지 않도록 합니다.

동일 이벤트를 여러 내부 서비스에 팬아웃할 수 있나요?

예, 메시지 버스 또는 라우터를 통해. 페이로드를 검증하고 정규화하는 단일 진입점을 유지한 다음 청구, CRM, 데이터 웨어하우스 또는 알림 소비자에게 배포합니다.

웹훅이 바운스 및 불만 처리에 어떻게 도움이 되나요?

억제 목록 업데이트, 위험한 캠페인 일시 중지 또는 계정 플래그를 거의 실시간으로 할 수 있어 지원 티켓으로 몇 시간 후에 문제를 발견하는 대신 유리합니다.

스테이징과 프로덕션에 별도 웹훅 URL이 필요한가요?

강력히 권장합니다. 격리된 엔드포인트는 테스트 이벤트가 라이브 사용자 데이터에 닿는 것을 방지하고 자격 증명을 독립적으로 순환하기 쉽게 합니다.

What is the format of webhook payloads?

All payloads are JSON with a consistent envelope: event type, timestamp, message ID, and event-specific data. See the Payload Examples section for full schemas.

What happens if our endpoint returns a non-2xx response?

Any response outside the 2xx range triggers a retry. Timeouts, connection refusals, and DNS failures also count as failures and trigger retry logic.

How long does Sendarix wait for our endpoint to respond?

Default timeout is 10 seconds. If your endpoint does not respond within this window, the request is considered failed and enters the retry queue.

Can we filter which events we receive?

Yes. Configure event type filters per endpoint to receive only the events relevant to your integration (e.g., bounces and complaints only).

What HTTP methods does Sendarix use for webhook delivery?

Sendarix sends POST requests only. If your endpoint receives a GET, PUT, PATCH, or DELETE request to the webhook URL, return 405 Method Not Allowed. This prevents accidental processing of unrelated traffic that may hit your endpoint.

How do we handle webhooks during deployment downtime?

Sendarix queues events during the retry window. If your endpoint is down for less than 5 hours, all events are preserved and delivered when your endpoint returns. For extended downtime (maintenance windows, incidents), queue events in Sendarix and process them after recovery via the event replay API.

Should our webhook endpoint be idempotent across different event types?

Yes. Process the event_id regardless of event_type. A given event_id represents one specific event (e.g., evt_abc123 = bounce for msg_xyz). If you receive evt_abc123 twice, return 200 OK on the second attempt without reprocessing. The event_id is globally unique across all event types.

How do we test webhooks in a staging environment without affecting production data?

Configure a separate webhook endpoint in your staging environment with its own secret. Use the Sendarix sandbox mode to send test events that do not count against production limits or affect real recipient addresses. This allows integration testing without generating fake suppression entries or polluting analytics.

What is the maximum number of events we can receive per second?

Sendarix delivers events in real time with no artificial rate limit on webhook delivery. During burst scenarios (e.g., a campaign delivery wave), your endpoint may receive hundreds of events per second. Design your endpoint to scale horizontally and your job queue to absorb these spikes. Monitor queue depth via the API to detect when processing falls behind.

신뢰할 수 있는 이메일 인프라로 전환할 준비가 되셨습니까?

카드 없이 무료로 시작하거나, 대량·엔터프라이즈는 영업팀에 문의하세요.

발송 시작영업 문의