Outbound rate limiting expressions inverted?

Issue Description

I have created a outbound rate limit for a specific queue queue_name == 'local' using the domain as a key And a rate limit of 5 messages per second.

When testing this, i submitted 1000 email, which should process just over 3 minutes based on the rate rules. However they all sent in roughly 8 seconds, completely disregarding the rate limit.

When inverting the expression too queue_name != 'local' then the rate limit took effect.

Expected Behavior

The emails sent should have been processed over the period of roughly 3 minutes.

Actual Behavior

All emails processed in 8 econds.

Reproduction Steps

  1. Create a outbound rate limit
  2. Add an expression for the rate limit (such as a queue)
  3. observe the rate limit does not take effect
  4. Invert the expression
  5. Observe the rate limit now takes effect

Stalwart Version

v0.16.x

Installation Method

Binary (Windows)

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

Additional Context

I am tinkering around with creating low priority queues with outbound rate limits.

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 logic isn’t inverted: an outbound rate limit applies when its expression evaluates to true. What’s tripping this up is what queue_name means. It’s the virtual queue the message was assigned to (the defaults are local, remote, dsn and report), not a “was this local delivery” flag.

Your 1000-message test went to external recipients, so those messages are in the remote queue. queue_name == ‘local’ never matches them, so no limit applies; queue_name != ‘local’ matches them all, so the limit kicks in. That’s exactly the behavior you saw. Use queue_name == ‘remote’ to throttle outbound-to-internet (or whatever custom queue your queue strategy assigns)

Your 1000-message test went to external recipients, so those messages are in the remote queue. queue_name == ‘local’ never matches them, so no limit applies; queue_name != ‘local’ matches them all, so the limit kicks in. That’s exactly the behavior you saw. Use queue_name == ‘remote’ to throttle outbound-to-internet (or whatever custom queue your queue strategy assigns)

They werent external. They are on the local queue. My testing environment has no external sending capabilties.

stalwart.2026-07-12.txt (2.4 MB)

Fixed in v0.16.14 (not yet released). The issue was that the queue_name variable was not reachable from the rate limiters.