Skip to main content

RCPT stage

The RCPT TO command is a used to specify the recipient of an email message during the SMTP message transfer. It is used in conjunction with the MAIL FROM command, which specifies the sender of the email. After the RCPT TO command is issued, the SMTP server responds with a status code indicating whether the recipient is valid and whether it is willing to accept the email message for that recipient. If the recipient is valid and the server is willing to accept the email, the SMTP client can then proceed to send the email message using the DATA command.

Directory

In order to handle mail for local accounts, it's necessary to configure a directory. This directory plays a crucial role in managing mail delivery as it fulfills several tasks:

  • Identifying Local Domains: Emails destined for these domains are processed and stored by the server.
  • Validating Recipients: It checks whether a given recipient's address corresponds to a valid, existing local account before accepting the email for delivery.
  • Verifying Addresses: The SMTP VRFY (verify) command is used to validate an email address without sending a message. If a sender uses this command, the server checks the directory to confirm whether the given address is valid.
  • Expanding Addresses: The SMTP EXPN (expand) command is used to get the actual delivery addresses when a single address is aliased to a group of addresses.

Without this directory configured, Stalwart SMTP won't accept any emails, as it has no way of validating or processing them. The only exception would be if relay functionality is enabled, allowing Stalwart SMTP to simply pass on emails to another server for delivery.

The directory to be used can be configured using the session.rcpt.directory attribute. For more information, please refer to the directory documentation.

Example:

[session.rcpt]
directory = "'sql'"

Relay

Relaying is a fundamental operation in email delivery, it refers to the process of transferring an email from one mail server to another. In more detail, when an email is sent, it may not directly reach its final destination server. Instead, it often travels through multiple intermediate servers - these servers "relay" the email towards its final destination. This is especially true when the sender and recipient are on different networks or domains.

In the context of Stalwart SMTP, the relay parameter dictates whether the server is permitted to relay messages intended for non-local domains. If relaying is enabled, Stalwart SMTP acts as an intermediary, accepting messages from sending clients or servers and forwarding them to their ultimate destinations.

This functionality can be beneficial in various scenarios, such as when Stalwart SMTP is configured as a front-end server in a larger email infrastructure. However, care must be taken to properly secure relay functionality, as an open relay can be exploited for spamming purposes. Thus, it's crucial to ensure only authorized users or networks are allowed to use Stalwart SMTP for relaying messages.

The session.rcpt.relay setting specifies whether the SMTP server should relay messages for non-local domain names. This attribute is useful when configured as an expression that only allows relaying for authenticated users.

For example:

[session.rcpt]
relay = [ { if = "!is_empty(authenticated_as)", then = true },
{ else = false } ]

Subaddressing

Subaddressing, also known as plus addressing or detailed addressing, is a mechanism that allows the creation of dynamic, disposable email addresses under a primary email address. By adding a + sign and any string of text to the local part (the part before the @) of an email address, users can create an infinite number of unique email addresses. For example, [email protected] is a subaddress of [email protected]. The primary benefit of this feature is that it allows users to filter and sort their incoming mail more efficiently, providing an easy way to manage subscriptions, sign-ups, and more without needing to create multiple separate email accounts.

Standard

To enable subaddressing, set the sub-addressing option to true in the session.rcpt section of the configuration file. For example:

[session.rcpt]
subaddressing = true

Custom

In addition to the standard subaddressing that uses the + symbol in the local part of the email address, Stalwart SMTP also supports custom subaddressing expressions. This ability provides enhanced obfuscation tactics against spammers by enabling users to create non-standard ways of handling subaddressing.

This functionality works by matching the user's email address using a custom expression, defined by the session.rcpt.sub-addressingg parameter in the configuration. If the if expression returns true, the email address generated by the then expression is used. If the if expression returns false, the else expression is used. If the else expression is not defined or false, the original email address is used.

To understand this better, let's take a look at the following example:

[session.rcpt]
sub-addressing = [ { if = "matches('^([^.]+)\.([^.]+)@(.+)$', rcpt)", then = "$2 + '@' + $3" },
{ else = false } ]

Here, the if expression uses a regex pattern designed to capture three groups separated by the '.' and '@' symbols in the incoming email address. The then expression then reassembles these captured groups in a new format. In this specific example, the configuration is rewriting the recipient address by removing the first part before the dot, essentially transforming '[email protected]' to '[email protected]'.

Catch-all addresses

A catch-all email address is a mailbox that is designed to receive all messages sent to incorrect or non-existent email addresses within a specific domain. It acts as a sort of safety net, ensuring that no email messages are lost due to misspelling or outdated email addresses. For instance, if someone were to accidentally send a message to [email protected] instead of [email protected], the catch-all address would receive the message. This feature can be especially useful in a business environment where missing an important email communication can lead to undesirable consequences.

Standard

Catch-all addresses can be enabled by setting the catch-all option to true in the session.rcpt section of the configuration file. For example:

[session.rcpt]
catch-all = true

To designate a specific account as the catch-all address, add @<DOMAIN_NAME> as an associated email address for the account. If you are using an SQL directory with the sample directory schema, you can find an example of how to create catch-all addresses in the adding email aliases section.

Custom

In addition to the standard catch-all functionality described above, it is also possible to define custom recipient addresses to act as a catch-all. This customization is achieved by using an expression in the session.rcpt.catch-all parameter in the configuration, much like the subaddressing feature. If the if expression returns true, the email address generated by the then expression is used as a catch-all email address. If the if expression returns false, the else expression is used. If the else expression is not defined or false, the email is rejected.

Let's examine this example:

[session.rcpt]
catch-all = [ { if = "matches('(.+)@(.+)$', rcpt)", then = "'info@' + $2" },
{ else = false } ]

In this configuration, the if expression is using a regular expression designed to capture the local part and the domain part of an incoming email address. The then expression then creates the catch-all address by replacing the local part with 'info' while retaining the original domain. For instance, if a message is sent to '[email protected]' and there's no such recipient, the email would be redirected to '[email protected]'.

Address rewriting

Recipient addresses can be rewritten using regular expressions, adding a high degree of flexibility and control to the handling of incoming messages. This can be particularly useful in several scenarios. For instance, if you need to correct common misspellings of recipient addresses, obfuscate the original recipient's address for privacy reasons, or redirect mail traffic from one address to another, regex rewriting can be a potent solution.

Recipient address rewriting is configured using the session.rcpt.rewrite attribute. For example, the following configuration will replace the '.' in the recipient address with a '+' sign:

[session.rcpt]
rewrite = [ { if = "is_local_domain('', rcpt_domain) & matches('^([^.]+)\.([^.]+)@(.+)$', rcpt)", then = "$1 + '+' + $2 + '@' + $3" },
{ else = false } ]

For more information, please refer to the address rewriting documentation.

Sieve script

In order to provide more flexibility and control over the handling of incoming messages, Sieve scripts can also be executed during the RCPT TO stage of the SMTP transaction. Typically, Sieve scripts are run at the delivery stage, but running them during the RCPT TO stage opens up more possibilities. At this stage, the sending server is indicating who the email is for. With the ability to manipulate this with Sieve scripts, administrators have an array of tools at their disposal.

For instance, scripts can be configured to reject certain recipients based on specific criteria, such as the recipient address or domain. This can be useful in managing email traffic and preventing unwanted emails. Address rewriting is another option, allowing for automatic correction of common misspellings or redirecting emails from one address to another. Additionally, more advanced functionality like greylisting, a common method of defending against spam, can be implemented. This involves temporarily rejecting emails from unknown sources and asking the sender to try again later - a test most spam sources fail.

The session.rcpt.script attribute specifies the Sieve script to execute during the RCPT TO stage. For more information, please refer to the Sieve scripts documentation.

For example, the following script implements greylisting using an SQL database:

[session.rcpt]
script = [ { if = "is_empty(authenticated-as")", then = "'greylist'" },
{ else = false } ]

[sieve.trusted.scripts]
greylist = '''
require ["variables", "vnd.stalwart.execute", "envelope", "reject"];

set "triplet" "${env.remote_ip}.${envelope.from}.${envelope.to}";

if not query "SELECT 1 FROM greylist WHERE addr=? LIMIT 1" ["${triplet}"] {
query "INSERT INTO greylist (addr) VALUES (?)" ["${triplet}"];
reject "422 4.2.2 Greylisted, please try again in a few moments.";
}
'''

Limits

The following attributes under the session.rcpt key, control the maximum number of recipients allowed per message, as well as how to handle invalid recipients.

  • max-recipients: Specifies the maximum number of recipients allowed per message.
  • rcpt.errors.total: Specifies the maximum number of invalid recipients allowed before a session is disconnected.
  • rcpt.errors.wait: Specifies the amount of time to wait when an invalid recipient is received.

Example:

[session.rcpt]
max-recipients = 25

[session.rcpt.errors]
total = 5
wait = "5s"