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:
| Property | Value |
|---|---|
| Method | POST |
| Content-Type | application/json |
| User-Agent | MailLaser/3.0.0 |
| URL | Value 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:
| Field | Type | Description |
|---|---|---|
sender | string | The email address from the MAIL FROM command. |
recipient | string | The accepted email address from the RCPT TO command. |
subject | string | The Subject: header value. Empty string if no subject header exists. |
body | string | Plain 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.
| Field | Type | Description |
|---|---|---|
sender_name | string | Display 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_body | string | Raw HTML content from the text/html MIME part. Omitted when the email has no HTML content. |
headers | object | Key-value map of headers matching the configured MAIL_LASER_HEADER_PREFIX. Omitted when no prefixes are configured or no headers match. See Header passthrough. |
attachments | array | MIME attachments that passed the Cedar Attach policy. Omitted when no attachments are present. See Attachments. |
dmarc_result | string | DMARC outcome (pass, fail, none, temperror). Present only when MAIL_LASER_DMARC_MODE is monitor or enforce. See DMARC validation. |
authenticated_from | string | DMARC-aligned From: address. Present only when dmarc_result == "pass". |
Body processing
MailLaser determines the body and html_body fields through this logic:
- If the email has a
text/plainMIME part and atext/htmlMIME part (typical for multipart/alternative), thebodyis generated from the HTML usinghtml2text, andhtml_bodycontains the raw HTML. - If the email has only a
text/htmlpart, thebodyis generated from the HTML usinghtml2text, andhtml_bodycontains the raw HTML. - If the email has only a
text/plainpart, thebodycontains the plain text directly, andhtml_bodyis omitted. - If neither part is found,
bodyis an empty string andhtml_bodyis 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:
- The circuit breaker is checked. If the circuit is open, the email is dropped (see Resilience).
- The initial delivery attempt is made with a configurable timeout (
MAIL_LASER_WEBHOOK_TIMEOUT, default 30 seconds). - If the attempt fails or times out, retries occur with exponential backoff up to
MAIL_LASER_WEBHOOK_MAX_RETRIES(default 3). - 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.