Skip to content

Overview

The message transfer agent (MTA) of Stalwart is its SMTP server, the part of Stalwart that moves mail between systems. It has three jobs. It receives mail that other servers deliver for the domains it hosts. It accepts the mail that users submit for sending. And it delivers both kinds of mail to their destination: to local mailboxes, or over SMTP to the servers responsible for other domains.

Moving mail safely between independent servers takes more than SMTP itself, so the MTA also implements the standards that surround it. The authentication standards (SPF, DKIM, DKIM2, ARC and DMARC) let receivers decide whether a message really comes from the domain it claims. The transport security mechanisms (DANE, MTA-STS and TLS reporting) protect delivery between servers against interception. Finally, a set of extension points (Sieve scripts, milters and MTA hooks) lets administrators filter and modify mail as it passes through.

Every message follows the same path through the MTA, from the connection that brings it in to its final delivery. A message passes through the following steps:

  1. A client connects to a listener, a port on which Stalwart accepts SMTP or LMTP connections.
  2. The SMTP session proceeds through the connect, EHLO, AUTH, MAIL FROM, RCPT TO and DATA stages. At each stage, settings decide whether the client may continue. At every stage except AUTH, a system Sieve script, milters and MTA hooks can also inspect the command and reject it. Throughout the session, throttles limit how fast a client may send.
  3. When the message has been transferred, Stalwart verifies its authentication, analyses incoming reports and prepares its trace headers. It then runs the spam filter and the DATA-stage filters, and signs the message with DKIM. Message checks at DATA lists these checks in order.
  4. The accepted message is written to the queue. Only then does the client receive 250, the reply that confirms the server has taken responsibility for the message.
  5. For each recipient, the outbound strategy chooses the route, the schedule, the connection settings and the TLS policy. Messages for local recipients are stored in their mailboxes, where user Sieve scripts run. Messages for other domains are delivered to the domain’s MX hosts or to a relay. A failed attempt is retried according to the schedule, and when a message cannot be delivered at all, the sender receives a delivery status notification.

Messages submitted over JMAP follow the same path. They have no network connection, so they enter at the MAIL FROM stage of step 2.

The same SMTP server handles two kinds of traffic. They differ in who the client is and in what the client may do.

Incoming mail, also called MX traffic, is mail that other mail servers deliver for the local domains. The client does not authenticate, so it may address only local recipients, and its messages are verified and filtered. This traffic arrives on port 25, because that is where receiving servers expect it.

Submission is the traffic of users and applications that send messages through their own server. Here the client authenticates, and once it has done so it may address any recipient. Its messages are signed with DKIM and relayed to their destination. Submission uses ports 465 and 587.

The port number does not make this distinction on its own. Instead, the default expressions of the stage objects test local_port: they apply MX behaviour on port 25 and submission behaviour on every other port. Changing those expressions therefore changes how a port is treated. With the default expressions, the following rules apply:

  • Authentication is required on every port except 25 (AUTH stage).
  • Relaying to non-local recipients is allowed only to authenticated sessions (RCPT TO stage).
  • SPF, reverse DNS and DMARC checks are performed on port 25.
  • The spam filter runs for unauthenticated sessions.

A listener is the network port on which a service accepts connections. The SMTP service is provided by the NetworkListener objects (found in the WebUI under Settings › Network › Listeners) whose protocol is smtp or lmtp. A new installation has two of them, one on port 25 and one on port 465, and the others are added as needed. Listeners describes all listener settings.

The following table shows the ports commonly used for mail and how each is set up:

PortUseimplicitTlsAuthentication with default settingsCreated by default
25Incoming mail from other servers (MX), with STARTTLSfalseNot offeredYes
465Submission over implicit TLS (RFC 8314)trueRequiredYes
587Submission with STARTTLS (RFC 6409)falseRequired, after STARTTLSNo
24LMTP delivery from another MTA that handles SMTP itselffalseRequired, unless exempted as described belowNo

The implicitTls setting decides when encryption starts. When it is true, TLS starts as soon as the client connects. When it is false, the connection starts in clear text and the client upgrades it with STARTTLS. The following object adds a submission listener on port 587:

{
"name": "submission",
"protocol": "smtp",
"bind": {"[::]:587": true},
"implicitTls": false
}

LMTP (RFC 2033) is a variant of SMTP for the last step of delivery. It is used when another MTA in front of Stalwart receives the mail and hands it over to Stalwart for storage, and it is needed only in that arrangement. An LMTP listener needs one change to the AUTH stage. The default require expression of that stage, local_port != 25, also applies to LMTP sessions, and those sessions cannot authenticate on a cleartext connection. The expression must therefore exempt the LMTP listener, for example as local_port != 25 && protocol != 'lmtp'. Otherwise LMTP clients receive 503 5.5.1 You must authenticate first.

The greeting that clients see when they connect is not a listener setting. It is set by the smtpGreeting expression of the connect stage, although that expression can return a different greeting for each listener.