Skip to main content
Learn what events Lettermint can send and how to handle them. Subscribe to the events you need when creating a webhook.

Common envelope

All webhook events share a consistent envelope:
{
  "id": "54d7e8c9-1195-4ba0-9d3f-b9af92305add",
  "event": "message.delivered",
  "timestamp": "2025-08-08T20:14:00.000Z",
  "data": { /* event-specific object */ }
}
Fields:
  • id: Unique identifier (UUIDv4) for the specific delivery event. Useful for idempotency.
  • event: Event type.
  • timestamp: ISO timestamp when the event occurred.
  • data: Event-specific fields (documented per event below).
Common data fields:
  • message_id: The unique identifier for the message.
  • subject: The email subject line.
  • metadata: Custom metadata attached to the message (if any).
  • tag: The tag assigned to categorize the message (e.g., “newsletter”, “order-confirmation”). Will be null if no tag was assigned.

Event payloads

message.created

Message accepted for processing. Example payload:
{
  "id": "54d7e8c9-1195-4ba0-9d3f-b9af92305add",
  "event": "message.created",
  "timestamp": "2025-08-08T20:14:00.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "from": {
      "email": "updates@acme.com",
      "name": "Acme Updates"
    },
    "to": ["user@example.com"],
    "cc": ["cc@example.com"],
    "bcc": ["bcc@example.com"],
    "reply_to": "help@acme.com",
    "subject": "Welcome to Acme",
    "metadata": {
      "X-Campaign-ID": "welcome-2025"
    },
    "tag": "welcome"
  }
}

message.sent

Message sent to recipient server.
{
  "id": "7f9c8e2a-1b3d-4f6e-b7d2-5c9f3a7e8b0c",
  "event": "message.sent",
  "timestamp": "2025-08-08T20:15:00.000Z",
  "data": {
    "message_id": "123e4567-e89b-12d3-a456-426614174000",
    "subject": "Your weekly newsletter",
    "recipient": "user@example.com",
    "metadata": {
      "X-User-ID": "user-123"
    },
    "tag": "newsletter"
  }
}

message.delivered

Message successfully delivered.
{
  "id": "9b0c4a4e-4e29-4d8b-8b3a-3f0f3e6d2f9b",
  "event": "message.delivered",
  "timestamp": "2025-08-08T20:15:12.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Your order has shipped",
    "recipient": "user@example.com",
    "response": {
      "status_code": 250,
      "enhanced_status_code": "2.0.0",
      "content": "OK  1640705112 qp1355551phe.1 - gsmtp"
    },
    "metadata": {
      "X-Transaction-ID": "txn-456"
    },
    "tag": "order-confirmation"
  }
}

message.hard_bounced

Permanent delivery failure (e.g., user does not exist).
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "event": "message.hard_bounced",
  "timestamp": "2025-08-08T20:15:30.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Summer sale - 50% off!",
    "recipient": "user@example.com",
    "response": {
      "status_code": 250,
      "enhanced_status_code": "2.0.0",
      "content": "OK  1640705112 qp1355551phe.1 - gsmtp"
    },
    "metadata": {
      "X-Campaign-ID": "summer-sale"
    },
    "tag": "marketing"
  }
}

message.soft_bounced

Temporary delivery failure (e.g., mailbox full, transient error).
{
  "id": "9b0c4a4e-4e29-4d8b-8b3a-3f0f3e6d2f9b",
  "event": "message.soft_bounced",
  "timestamp": "2025-08-08T20:15:30.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Your order #789 update",
    "recipient": "user@example.com",
    "response": {
      "status_code": 250,
      "enhanced_status_code": "2.0.0",
      "content": "OK  1640705112 qp1355551phe.1 - gsmtp"
    },
    "metadata": {
      "X-Order-ID": "order-789"
    },
    "tag": "order-notification"
  }
}

message.spam_complaint

Recipient reported the message as spam.
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "event": "message.spam_complaint",
  "timestamp": "2025-08-08T20:16:00.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Weekly digest - August edition",
    "recipient": "user@example.com",
    "metadata": {
      "X-Newsletter-ID": "weekly-digest"
    },
    "tag": "newsletter"
  }
}

message.failed

Processing failure within Lettermint.
{
  "id": "9b0c4a4e-4e29-4d8b-8b3a-3f0f3e6d2f9b",
  "event": "message.failed",
  "timestamp": "2025-08-08T20:14:12.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Password reset request",
    "recipient": "user@example.com",
    "reason": "A network error occurred.",
    "response": {
      "status_code": 250
    },
    "metadata": {
      "X-Session-ID": "sess-abc123"
    },
    "tag": null
  }
}

message.suppressed

Message was suppressed due to previous bounce or complaint.
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "event": "message.suppressed",
  "timestamp": "2025-08-08T20:14:05.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Your account statement",
    "recipient": "user@example.com",
    "reason": "hard_bounce",
    "metadata": {
      "X-Account-ID": "acc-xyz789"
    },
    "tag": "transactional"
  }
}

message.policy_rejected

Message rejected by policy (spam or content filter). This occurs when a message’s spam score exceeds the configured threshold before delivery.
{
  "id": "c4d5e6f7-a8b9-0123-cdef-456789abcdef",
  "event": "message.policy_rejected",
  "timestamp": "2025-08-08T20:14:03.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Limited time offer!!!",
    "reason": "Spam score threshold exceeded",
    "score": 7.5,
    "spam_symbols": [
      {
        "name": "BAYES_SPAM",
        "score": 3.5,
        "options": [],
        "description": "Bayes spam probability is very high"
      },
      {
        "name": "SUBJ_ALL_CAPS",
        "score": 1.5,
        "options": [],
        "description": "Subject is all capitals"
      }
    ],
    "metadata": {
      "X-Campaign-ID": "promo-123"
    },
    "tag": "marketing"
  }
}
Fields:
  • reason: Human-readable rejection reason (e.g., “spam content”, “policy violation”)
  • score: The spam score that triggered the rejection
  • spam_symbols: Array of spam rule matches with name, score, options, and description

message.unsubscribed

Recipient unsubscribed from the mailing list.
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567891",
  "event": "message.unsubscribed",
  "timestamp": "2025-08-08T20:16:30.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "August newsletter highlights",
    "recipient": "user@example.com",
    "unsubscribed_at": "2025-08-08T20:16:30.000Z",
    "metadata": {
      "X-Campaign-ID": "newsletter-august"
    },
    "tag": "newsletter"
  }
}

message.opened

Recipient opened the email. Requires open tracking to be enabled on the route.
This event is only available for routes with open tracking enabled. Open tracking is a beta feature available on paid plans.
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "event": "message.opened",
  "timestamp": "2025-08-08T20:17:00.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Your order has shipped",
    "metadata": {
      "X-Order-ID": "order-12345"
    },
    "tag": "shipping",
    "recipient": "user@example.com",
    "opened_at": "2025-08-08T20:17:00+00:00",
    "first_open": true,
    "device_type": "desktop",
    "client_type": "browser",
    "client_name": "Chrome",
    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
    "bot": {
      "detected": false,
      "probability": 5
    }
  }
}
Fields:
  • opened_at: Timestamp when the open was detected
  • first_open: Whether this is the first time this recipient opened the email
  • device_type: Device category: desktop, mobile, or tablet
  • client_type: Client category: browser, email_client, etc.
  • client_name: Specific client name: Chrome, Safari, Outlook, etc.
  • user_agent: The user agent string from the request
  • bot.detected: Whether the open appears to be from an automated source (bot, proxy, scanner)
  • bot.probability: Confidence score (0-100) that this is a bot interaction

message.clicked

Recipient clicked a link in the email. Requires click tracking to be enabled on the route.
This event is only available for routes with click tracking enabled. Click tracking is a beta feature available on paid plans.
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567892",
  "event": "message.clicked",
  "timestamp": "2025-08-08T20:18:30.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Your weekly recommendations",
    "metadata": {
      "X-Campaign-ID": "weekly-recs"
    },
    "tag": "recommendations",
    "recipient": "user@example.com",
    "clicked_at": "2025-08-08T20:18:30+00:00",
    "destination_url": "https://example.com/product/123",
    "link_index": 0,
    "anchor_text": "View Product",
    "first_click": true,
    "device_type": "mobile",
    "client_type": "browser",
    "client_name": "Safari",
    "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15",
    "bot": {
      "detected": false,
      "probability": 2
    }
  }
}
Fields:
  • clicked_at: Timestamp when the click occurred
  • destination_url: The original destination URL that was clicked
  • link_index: Zero-based index of the link in the email (order of appearance)
  • anchor_text: The visible text of the clicked link
  • first_click: Whether this is the first time this recipient clicked any link in this email
  • device_type: Device category: desktop, mobile, or tablet
  • client_type: Client category: browser, email_client, etc.
  • client_name: Specific client name: Chrome, Safari, Outlook, etc.
  • user_agent: The user agent string from the request
  • bot.detected: Whether the click appears to be from an automated source (security scanner, link preview bot)
  • bot.probability: Confidence score (0-100) that this is a bot interaction

message.inbound

Inbound email received on an inbound route. Only available for inbound route types. This event includes the complete parsed email with headers, body (text and HTML), attachments, and spam filtering results.
This event is only available for webhooks attached to inbound routes. See the Inbound Mail guide for setup instructions.
Example payload:
{
  "id": "e3d4f5a6-b7c8-9012-d3e4-f5a6b7c89012",
  "event": "message.inbound",
  "timestamp": "2025-10-02T14:30:00.000Z",
  "data": {
    "route": "support-inbox",
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "envelope": {
      "remote_ip": "203.0.113.42",
      "remote_hostname": "mail.example.com",
      "helo": "smtp.example.com",
      "mail_from": "customer@example.com"
    },
    "from": {
      "email": "customer@example.com",
      "name": "John Doe",
      "subaddress": null
    },
    "to": [
      {
        "email": "support@acme.com",
        "name": null,
        "subaddress": null
      }
    ],
    "cc": [],
    "recipient": "support@acme.com",
    "subaddress": null,
    "reply_to": "customer@example.com",
    "subject": "Question about my order",
    "date": "2025-10-02T14:30:00.000Z",
    "body": {
      "text": "Hi, I have a question about my recent order...",
      "html": "<p>Hi, I have a question about my recent order...</p>"
    },
    "tag": null,
    "headers": [
      {
        "name": "Message-ID",
        "value": "<abc123@mail.example.com>"
      },
      {
        "name": "X-Mailer",
        "value": "Apple Mail (2.3445.104.11)"
      }
    ],
    "attachments": [
      {
        "filename": "receipt.pdf",
        "content": "JVBERi0xLjQKJeLjz9MK...",
        "url": null,
        "content_type": "application/pdf",
        "size": 45678,
        "content_id": null
      }
    ],
    "is_spam": false,
    "spam_score": 1.2,
    "spam_symbols": [
      {
        "name": "DKIM_VALID",
        "score": -0.1,
        "options": [],
        "description": "Message has valid DKIM signature"
      },
      {
        "name": "SPF_PASS",
        "score": -0.1,
        "options": [],
        "description": "SPF check passed"
      },
      {
        "name": "BAYES_HAM",
        "score": -3.0,
        "options": [],
        "description": "Bayesian classifier identified message as non-spam"
      }
    ]
  }
}
Payload fields:
  • route: Route identifier/slug
  • message_id: Unique message ID
  • envelope: SMTP envelope data from the sending server
    • remote_ip: IP address of the sending mail server
    • remote_hostname: Reverse DNS (PTR) hostname of the sending server
    • helo: HELO/EHLO domain the sender identified as
    • mail_from: Envelope sender address (MAIL FROM command, may differ from the From header)
  • from: Sender information with optional subaddress
  • to: Array of TO recipients with optional subaddresses
  • cc: Array of CC recipients with optional subaddresses
  • recipient: Primary envelope recipient
  • subaddress: Parsed subaddress from recipient (e.g., “tag” from “user+tag@example.com”)
  • reply_to: Reply-To address if specified
  • subject: Email subject line
  • date: Email received timestamp (ISO 8601)
  • body.text: Plain text body content
  • body.html: HTML body content
  • tag: Custom tag from X-LM-Tag or X-Tag header
  • headers: All email headers excluding standard ones (From, To, Subject, etc.)
  • attachments: File attachments (see attachment delivery modes below)
  • is_spam: Whether message exceeded spam threshold
  • spam_score: Calculated spam score from Rspamd
  • spam_symbols: Array of spam rule objects, each containing name, score, options, and description fields
Attachment delivery modes: By default, attachments include base64-encoded content. You can configure your inbound route to use URL delivery mode instead, where attachments include a signed url for downloading. URLs are valid for 28 days. See the Inbound Mail guide for configuration.
Security: Always validate webhook signatures and sanitize email content before processing. Email bodies may contain malicious HTML or scripts.

webhook.test

Special event that can be triggered from the Dashboard for connectivity testing.
{
  "id": "test-7f9c8e2a-1b3d-4f6e-b7d2-5c9f3a7e8b0c",
  "event": "webhook.test",
  "timestamp": "2025-08-08T20:14:12.000Z",
  "data": {
    "message": "This is a test webhook from Lettermint",
    "webhook_id": "9f9bf19c-4a2c-45f3-a6c7-bc937224ec5a",
    "timestamp": 1754921294
  }
}

Next Steps