Controlling SMTP Responses with HTTP Headers

By default, Conduit maps the HTTP status code from your endpoint to an SMTP response code. A 2xx accepts the message. A 5xx causes a transient failure. A 4xx (429 excepted) rejects the message permanently.

Sometimes you need more precise control. For example, your endpoint returns 200 OK for every request. You still want to defer some messages, or to reject them with a specific SMTP reason. Two special response headers give you this control. Your endpoint sends them in its HTTP response.

Web UI availability: The HTTP response from your endpoint controls this feature. No setting in Conduit affects it, so there is nothing to configure in the UI or through the API.


Response headers

Header Required Description
X-Conduit-SMTP-Code Yes, to activate the override A 3-digit SMTP response code (200 to 599)
X-Conduit-SMTP-Message No Free text that Conduit adds to the SMTP response

Conduit reads both headers from the HTTP response that your webhook target sends back.


How Conduit reads the headers

  1. Conduit looks for X-Conduit-SMTP-Code in the response.
  2. If the header is absent, or it is not a valid 3-digit integer from 200 to 599, Conduit uses the normal classification from the HTTP status.
  3. If the header is valid, Conduit does the following:
    • It returns your code to the sending MTA.
    • It uses X-Conduit-SMTP-Message as the SMTP message. If that header is absent, it uses a default.
    • It takes the delivery outcome from the first digit of the code, and it ignores the HTTP status code:
SMTP code range Delivery outcome MTA behavior
200 to 299 Success The MTA accepts the message and does not retry
400 to 499 Transient failure The MTA retries on its own schedule
500 to 599 Permanent failure The MTA bounces the message

Message sanitization

Conduit sanitizes X-Conduit-SMTP-Message before it uses the value. This prevents SMTP response injection:

  • Conduit removes the CR (\r) and LF (\n) characters.
  • Conduit truncates the value to 512 bytes.
  • If the result is empty, Conduit uses a default for the class:
    • 2xx2.0.0 OK
    • 4xx4.0.0 Temporary failure, please retry
    • 5xx5.0.0 Delivery failed

Example: defer a message for a short time

Your endpoint receives an email, but the downstream system is unavailable. Return 200 OK, so that Conduit does not record a failure on your side. At the same time, tell Conduit to ask the MTA for a retry:

HTTP/1.1 200 OK
X-Conduit-SMTP-Code: 451
X-Conduit-SMTP-Message: 4.7.1 Downstream system unavailable, please retry later
Content-Length: 0

Conduit then does the following:

  • It records the delivery as a transient failure.
  • It returns 451 4.7.1 Downstream system unavailable, please retry later to the sending MTA.
  • The MTA retries the message on its normal schedule.

Example: reject a message permanently with a policy reason

Your endpoint examines the payload and finds that the message breaks a content policy. Return a permanent rejection:

HTTP/1.1 200 OK
X-Conduit-SMTP-Code: 550
X-Conduit-SMTP-Message: 5.7.1 Message rejected by content policy
Content-Length: 0

Conduit then does the following:

  • It records the delivery as a permanent failure.
  • It returns 550 5.7.1 Message rejected by content policy to the MTA.
  • The MTA creates a bounce (a non-delivery report) for the sender.

Example: accept a message with your own SMTP reply

Your endpoint accepts the message, and you want your own acceptance message for an audit:

HTTP/1.1 200 OK
X-Conduit-SMTP-Code: 250
X-Conduit-SMTP-Message: 2.0.0 Alert received and logged
Content-Length: 0

Reading the outcome

The delivery log shows the SMTP override. While an override is active, the error field of the log entry holds SMTP <code>: <message>.

To see this in the web UI, open Webhooks → [your webhook] → Logs. Or call:

GET /api/v1/webhooks/{id}/logs
Authorization: Bearer <access_token>

Interaction with the default HTTP status handling

The override activates only when X-Conduit-SMTP-Code is present and valid. If you omit the header, the normal mapping from the HTTP status applies:

HTTP status Default SMTP code Retryable
2xx 250 No
429 450 Yes
4xx (other) 550 No
5xx 450 Yes
Network error / timeout 450 Yes