How to configure a global authenticated outbound relay (smarthost) in Stalwart 0.16.12?

Issue Description

Need help configuring a global authenticated outbound relay (smarthost) in Stalwart 0.16.12. I configured the Relay Route and the Outbound Strategy according to my understanding of the official documentation, but outbound SMTP still connects directly to recipient MX servers.
How to configure a global authenticated outbound relay (smarthost) in Stalwart 0.16.12?I am trying to configure a global authenticated outbound relay (smarthost) in Stalwart 0.16.12.

I created a Relay Route with SMTP authentication and configured the Outbound Strategy so that all non-local recipients use that route.

The relay is reachable and TLS connectivity has been verified.

However, when sending to external recipients, Stalwart still connects directly to the recipient MX server instead of using the configured relay.

The Web UI and CLI both show the relay configuration correctly.

Am I missing an additional configuration step, or should the Relay Route be sufficient for this use case?

Expected Behavior

Every outbound message destined for a non-local domain should be sent through the configured authenticated SMTP relay (smtps.aruba.it:465) instead of being delivered directly to the recipient MX server.

Actual Behavior

The configured Relay Route is ignored.

Instead of connecting to the configured relay host (smtps.aruba.it:465), Stalwart opens a direct SMTP connection to the recipient MX server (for example gmail-smtp-in.l.google.com).

Delivery Trace and packet capture both confirm that the configured relay is never used.

Reproduction Steps

  1. Install Stalwart Mail Server 0.16.12 on Debian.

  2. Create a Relay Route pointing to smtps.aruba.it:465 with SMTP authentication enabled.

  3. Configure MtaOutboundStrategy:

    IF is_local_domain(rcpt_domain)
    local
    ELSE
    aruba

  4. Send an email to an external recipient (for example Gmail).

  5. Observe the SMTP connection.

  6. Stalwart connects directly to the recipient MX instead of the configured relay.

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

PostgreSQL

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

The most common causes of a “Relay Route” being silently ignored are mismatches in how the route expression selects it, so the fix is almost always in the route expression syntax on MtaOutboundStrategy, not in the relay itself.

How it should be wired together

  1. Define your relay as an MtaRoute with @type: "Relay" and a name (for example "aruba"):
{
  "@type": "Relay",
  "name": "aruba",
  "address": "smtps.aruba.it",
  "port": 465,
  "protocol": "smtp",
  "implicitTls": true,
  "authUsername": "[email protected]",
  "authSecret": {"@type": "Value", "secret": "yourpassword"}
}
  1. On the MtaOutboundStrategy singleton, the route field must be a proper expression object, and string results (both route names and the local check) must be single-quoted inside the JSON string, e.g.:
{
  "route": {
    "match": [
      {"if": "is_local_domain(rcpt_domain)", "then": "'local'"}
    ],
    "else": "'aruba'"
  }
}

The pseudo-code you posted (IF ... local ELSE aruba) is not valid — if the then/else values aren’t quoted string literals like 'aruba', the expression will fail to resolve to a route name and Stalwart falls back to its built-in default ('mx'), which is exactly the direct-to-MX behaviour you’re seeing.

  1. The name returned by the route expression ('aruba' in this example) must exactly match the name field of your Relay MtaRoute. If there’s any mismatch (typo, case difference), delivery fails to resolve the named route — check whether your setup actually falls back to mx due to a name mismatch as well.

You can verify what’s actually being evaluated with:

stalwart-cli get MtaOutboundStrategy
stalwart-cli get MtaRoute

and confirm the route name returned by the expression matches one of the returned MtaRoute names.

Reference: MTA Outbound Routing and MtaOutboundStrategy.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

Hello,

Thank you for your reply.

I have already verified those points.

The Relay Route exists and its name is exactly:


aruba

The current outbound strategy returned by stalwart-cli is:


Routing

Condition:
is_local_domain(rcpt_domain)
→ 'local'

Default:
'aruba'

The exported configuration also contains:


"else":"'aruba'"

so the route expression appears to evaluate to the correct string literal.

The Relay Route name and the returned value match exactly.

Despite this, outbound SMTP still connects directly to the recipient MX server instead of the configured relay.

Could you please confirm whether there is any additional configuration required in 0.16.12 for a Relay Route to be used as a global smarthost?

I can also provide the exported configuration if that would help.

I needed similar, and mine is setup as and working properly