Core Concepts

Webhook delivery

When MailLaser receives and parses a valid email, it sends the extracted content to your configured webhook URL as an HTTP POST request with a JSON body.


HTTP request details

Every webhook delivery uses these HTTP settings:

PropertyValue
MethodPOST
Content-Typeapplication/json
User-AgentMailLaser/3.0.0
URLValue of MAIL_LASER_WEBHOOK_URL

The User-Agent header reflects the application name and version from the Cargo package metadata. When MAIL_LASER_WEBHOOK_SIGNING_SECRET is configured, each request also carries X-MailLaser-Timestamp and X-MailLaser-Signature-256 — see Webhook signing.

In release builds, MailLaser enforces HTTPS-only connections to the webhook URL. In debug builds, HTTP is also permitted for local development.


JSON payload format

The payload contains the parsed email content:

{
  "sender": "user@example.com",
  "sender_name": "John Doe",
  "recipient": "alerts@myapp.com",
  "subject": "Monthly Report",
  "body": "Please find the report attached.\n\nBest regards,\nJohn",
  "html_body": "<html><body><p>Please find the report attached.</p><p>Best regards,<br>John</p></body></html>",
  "headers": {
    "X-Custom-Id": "12345",
    "X-Priority": "high"
  }
}

Required fields

These fields are always present in every payload:

FieldTypeDescription
senderstringThe email address from the MAIL FROM command.
recipientstringThe accepted email address from the RCPT TO command.
subjectstringThe Subject: header value. Empty string if no subject header exists.
bodystringPlain text body content. If the email is HTML-only, this contains a text conversion generated by html2text.

Optional fields

These fields are omitted entirely from the JSON when they have no value. They are not set to null; they are absent from the payload.

FieldTypeDescription
sender_namestringDisplay name from the From: header (e.g., "John Doe" from John Doe <john@example.com>). Omitted when the From: header contains only an email address or is absent.
html_bodystringRaw HTML content from the text/html MIME part. Omitted when the email has no HTML content.
headersobjectKey-value map of headers matching the configured MAIL_LASER_HEADER_PREFIX. Omitted when no prefixes are configured or no headers match. See Header passthrough.
attachmentsarrayMIME attachments that passed the Cedar Attach policy. Omitted when no attachments are present. See Attachments.
dmarc_resultstringDMARC outcome (pass, fail, none, temperror). Present only when MAIL_LASER_DMARC_MODE is monitor or enforce. See DMARC validation.
authenticated_fromstringDMARC-aligned From: address. Present only when dmarc_result == "pass".

Body processing

MailLaser determines the body and html_body fields through this logic:

  1. If the email has a text/plain MIME part and a text/html MIME part (typical for multipart/alternative), the body is generated from the HTML using html2text, and html_body contains the raw HTML.
  2. If the email has only a text/html part, the body is generated from the HTML using html2text, and html_body contains the raw HTML.
  3. If the email has only a text/plain part, the body contains the plain text directly, and html_body is omitted.
  4. If neither part is found, body is an empty string and html_body is omitted.

Text conversion

The html2text library converts HTML to readable plain text. It preserves paragraph structure, converts links to reference-style notation, and handles bold/italic formatting. The output width is set to 80 characters.


Delivery behavior

Webhook delivery is handled by the WebhookActor, which runs as a persistent actor in the acton-reactive framework. The actor processes emails sequentially, applying resilience patterns to each delivery attempt.

For each email:

  1. The circuit breaker is checked. If the circuit is open, the email is dropped (see Resilience).
  2. The initial delivery attempt is made with a configurable timeout (MAIL_LASER_WEBHOOK_TIMEOUT, default 30 seconds).
  3. If the attempt fails or times out, retries occur with exponential backoff up to MAIL_LASER_WEBHOOK_MAX_RETRIES (default 3).
  4. The circuit breaker state is updated based on the outcome.

Webhook delivery is fire-and-forget from the SMTP session's perspective. The SMTP session responds with 250 OK: Message accepted for delivery as soon as the email data is parsed and passed to the webhook actor. A webhook failure does not cause the SMTP transaction to fail.


Request signing

Setting MAIL_LASER_WEBHOOK_SIGNING_SECRET causes each delivery to carry X-MailLaser-Timestamp and X-MailLaser-Signature-256 headers so your receiver can verify origin and payload integrity. For header format, verification recipes, and rotation guidance, see Webhook signing.


Response handling

MailLaser checks the HTTP status code of the webhook response:

  • 2xx: Logged as successful. The circuit breaker's failure counter resets.
  • 4xx or 5xx: Logged as an error. Counts as a failure for retry and circuit breaker purposes.
  • Timeout: Logged as a timeout. Counts as a failure.

The response body from the webhook endpoint is not read or logged. MailLaser only examines the status code.

Previous
SMTP server