Connect stage
The connect stage is the first point at which Stalwart can act on an SMTP client. It starts when a client opens a connection, before the client has sent any command. At this point the server knows only two things: the client’s IP address and the listener the client connected to. The server answers with its greeting, which announces its name and invites the client to continue. Settings at this stage decide which name the server presents, and a filter can refuse an unwanted client before it sends anything.
The stage is configured on the MtaStageConnect singleton (found in the WebUI under Settings › MTA › Session › Connect Stage). Its expressions can use the connection variables: listener, remote_ip, remote_port, local_ip, local_port, protocol, is_tls, asn and country.
Some connections never reach the connect stage. A connection from an address in the blocked IP addresses list is refused before it. An inbound throttle keyed on the client’s IP address can also refuse a connection, and in that case the connection is closed without a greeting.
Host name and greeting
Section titled “Host name and greeting”The server uses a name for itself throughout the session, in its greeting and in its replies. That name is hostname, and by default it is system('hostname'), which returns the host name of the system. The greeting itself is a separate setting, smtpGreeting. The server sends it as 220 <greeting>, and by default it is system('hostname') + ' Stalwart ESMTP at your service'.
The host name matters most on port 25. It should resolve to the server’s IP address and match the PTR record of that address. Receiving servers compare these names when Stalwart delivers mail to them, and some refuse mail from servers whose names do not match. A server with several listeners can present a different name on each of them. The following object body presents a different name on a listener named smtp-relay:
{ "hostname": { "match": {"0": {"if": "listener == 'smtp-relay'", "then": "'relay.example.org'"}}, "else": "system('hostname')" }}Filtering connections
Section titled “Filtering connections”A connection can be filtered with a system Sieve script, a script that the administrator installs and that runs inside the server. script selects the script to run for each new connection: it returns the script’s name, or false to run none. At this stage the script can test the environment variables of the connection, such as env.remote_ip, env.asn and env.country (Variables). When the script rejects the connection, the server sends the reply and closes the connection, so the client cannot send any command.
The following script refuses connections from one IP address:
require ["variables", "reject"];
if string "${env.remote_ip}" "192.0.2.88" { reject "554 5.7.1 Connection from this IP address is not accepted.";}The reject text must start with a reply code. This example uses 554, which RFC 5321 defines for a server that refuses a connection. A text without a code is sent as a protocol error reply (Replies and actions). Once the script is installed, here under the name connect-filter, it is selected with the following script value:
{ "script": {"else": "'connect-filter'"}}Sieve is not the only filter at this stage. Milters and MTA hooks whose stages include connect are consulted here as well. To refuse whole networks, no script is needed: the networks can be added to the blocked IP addresses instead.