Throttling
Throttling is a mechanism that restricts the rate at which outbound messages are sent to a remote SMTP server. It is used to prevent the remote SMTP server from being overwhelmed by too many outgoing messages, which can lead to performance degradation, connectivity issues, or even being marked as a spammer by ISPs. Concurrency limiting and rate limiting are two techniques used in Stalwart SMTP to control the amount of outbound traffic.
Settings
Stalwart SMTP supports an unlimited number of outbound throttles, which can be dynamically configured to limit email delivery based on multiple variables. Throttles are defined as TOML arrays under the queue.throttle[]
keys using the following attributes:
concurrency
: Specifies the maximum number of concurrent requests that the throttle will allow.rate
: Specifies the rate limit that the throttle will impose.key
: An optional list of context variables that determine where this throttle should be applied.match
: An optional rule that indicates the conditions under which this throttle should be applied.enable
: An boolean attribute that specifies whether the throttle is enabled. If not specified, the throttle is ignored.
Throttles can either include both a concurrency limit and rate limit, or just one of the two strategies.
Concurrency limit
Concurrency limiting is the process of limiting the number of simultaneous connections to a remote server. This is useful in preventing overloading a remote server by establishing too many connections. For example, a rule can be configured to limit the number of concurrent connections to a single IP address to prevent overwhelming the remote host.
The queue.throttle[].concurrency
attribute determines the number of concurrent outbound connections that the throttle will allow. For example, to limit the server to maintain a maximum number of 5 concurrent outgoing connections globally:
[[queue.throttle]]
concurrency = 5
enable = true
Please note that the above example will impose a global concurrency limiter, to apply a more granular limiter please refer to the throttle groups section below.
Rate limit
Rate limiting is the process of limiting the number of outgoing requests over a specific period of time. This is useful in preventing sending too many messages in a short amount of time, which could result in being marked as spammer by the remote host. For example, a rule can be configured to rate limit the number of outgoing emails per minute to a remote IP address or domain name.
The queue.throttle[].rate
attribute determines the number of outgoing messages over a period of time that the rate limiter will allow. For example, to limit the server to send a maximum of 100 messages per seconds:
[[queue.throttle]]
rate = "100/1s"
enable = true
Please note that the above example will impose a global rate limiter, to apply a more granular limiter please refer to the throttle groups section below.
Groups
The queue.throttle[].key
attribute enables the creation of throttle groups based on a combination of context variables. Available context variables are:
remote_ip
: The remote IP address.local_ip
: The local IP address (only available when a source IP is configured).mx
: The remote host's MX hostname.sender
: The return path specified in theMAIL FROM
command.sender_domain
: The domain component of the return path specified in theMAIL FROM
command.rcpt
: The recipient's address specified in theRCPT TO
command.rcpt_domain
: The domain component of the recipient's address specified in theRCPT TO
command.
For example, to implement a concurrency limiter per remote IP address:
[[queue.throttle]]
key = ["remote_ip"]
concurrency = 5
enable = true
And, to limit the rate at which messages are sent to any domain name to 25 messages per hour:
[[queue.throttle]]
key = ["rcpt_domain"]
rate = "25/1h"
enable = true
Expressions
Throttle expressions enable the imposition of concurrency and rate limits only when a specific condition is met. These expressions can be configured using the queue.throttle[].match
attribute. For example, to impose a concurrency and rate limiter by sender only for messages sent to the IP address 192.0.2.20:
[[queue.throttle]]
match = "remote_ip = '192.0.2.20'"
key = ["sender", "rcpt_domain"]
concurrency = 5
rate = "100/1h"
enable = true