Repository navigation
Outbound Shaping
Written on 24 September 2026 from
hmailserver/docs/OutboundShaping.md,IpWarmup.md,BounceSuppression.md,Complaints.mdandReputationWatch.md, and brought up to 6.3.4 (27 September 2026, schema 6104), on 26 September 2026. Everything on this page is new in 6.3.4, exceptMaxOutboundPerDestinationPerMinute, a fixed per-destination rate that 6.3.3 already has. The remote domain policies are schema 6045, the back-off and the ceilings have no schema step, and the IP warm-up is schema 6093. 6.3.5 (29 September 2026, schema 6105), 6.3.6 (6 October 2026, schema 6108) and 6.3.7, the latest release (17 October 2026, schema 6108), are not yet reflected here.
How this server slows itself down for a destination that asked, keeps one sender from using every delivery thread, and warms a new outbound address up the way the large providers expect - without touching mail to anybody else, and without spending a message's retries on a wait this server chose. And, beside those, the three things that read how the world is answering what it sends: bounces, complaints and blocklists.
flowchart TD
Q["A batch of recipients<br/>for one target"] --> A{"Remote domain policy:<br/>largest message?"}
A -->|"too big"| X["5.3.4, permanent"]
A --> B{"The destination's<br/>back-off window open?"}
B -->|"yes"| H["Held, 4.4.5 -<br/>not counted as an attempt"]
B --> C{"Policy's messages a minute,<br/>connection ceiling,<br/>tenant share, per-minute rate"}
C -->|"over"| H
C --> D{"MX lookup, MTA-STS,<br/>then IP warm-up's<br/>daily ceiling"}
D -->|"over today's ceiling"| W["Held until the next UTC day"]
D --> E["Gateway encryption,<br/>where the policy asks"]
E --> F["Connect: DANE, TLS, deliver"]
F -->|"421 or 'slow down'"| O["Open or double<br/>the back-off window"]
- The back-off: a destination said slow down
- Connection ceilings and the tenant share
- A deferral this server chose is not counted
- IP warm-up
- Where to see it
- Bounces, complaints and blocklists
- What it does not do
On by default since 6.3.4 - the one part of this page that changes behaviour on upgrade without a switch. When a destination answers a delivery with a request to slow down, it gets a back-off window: nothing is sent to it until the window ends, one delivery then probes it, and the same answer doubles the window. Deliveries to every other destination are untouched.
A reply is read as "slow down" when it is:
- a 421, at the banner or anywhere after it;
- a 4xx whose enhanced status is 4.7.0, 4.7.28, 4.7.500, 4.7.650, 4.7.652 or 4.3.2 - the codes the providers decorate their deferrals with;
- a 4xx whose text contains
rate limit,too many messages,too many connections,unusual rate,unexpected volume,temporarily deferred,throttl,try again later,server busy,back offorslow down(the full fixed list is in the document; it is English, and cannot be widened).
And never a 5xx, never 4.7.1 (greylisting), never a reply that says greylist, never a 4.2.x (one mailbox, not the destination), 4.5.3 or 4.4.x, never a refused connection or a DNS failure.
| Setting | Default | Meaning |
|---|---|---|
OutboundBackoffMinutes |
2 | The first window. 0 turns the back-off off |
OutboundBackoffMaxMinutes |
60 | The ceiling a doubling window stops at |
A relay is one destination. With SMTPRelayer set, or a route through a smart host, one
slow-down reply from it holds every message that goes through it for the window - which is what
the relay asked for, and worth knowing before the window is made long.
Both off by default (0), both 0 to 1000:
-
MaxOutboundConnectionsPerDestination- the most sessions open at once to one target that no remote domain policy gives amax_connectionsof its own (a policy's value wins). -
MaxOutboundConnectionsPerTenant- the most deliveries one tenant may have in flight. The tenant is the hosted domain of the envelope sender; mail relayed for outsiders, forwarded external mail and the null sender are one tenant,(external), so relayed mail cannot starve the hosted domains either.
Over a ceiling the batch is deferred one to five minutes. The tenant share is a share of
connections, bounded by MaxDeliveryThreads; it is not a volume control - the per-account
sending limits are (Security Hardening §17.5). The four settings are on the Control Panel's
Delivery of e-mail page beside MaxOutboundPerDestinationPerMinute, the Deck's Settings view,
/api/v1/settings and COM.
The back-off, the two ceilings, a remote domain policy's messages a minute and
MaxOutboundPerDestinationPerMinute each defer with 4.4.5 ("mail system congestion") and a
sentence naming the rule. When every failure of a delivery pass was such a deferral, the message's
next try is set to the end of the wait with its tries counter untouched:
Delivery deferred by this server's own shaping, not by a remote server.
Scheduling it for later delivery in N minute(s); the attempt is not counted against the retry limit.
Before this, a deferral this server inflicted on itself spent the message's retries, and with a small retry count a message could be bounced having never been offered to anybody. The hold is bounded: a message queued longer than its retry schedule spans is counted from then on, so a destination that says "slow down" for ever cannot hold mail for ever. Only a failure at a remote spends the retry budget.
Schema 6093. A large provider judges a sending address by its history, and a new address that starts sending thousands of messages a day looks exactly like a spammer's. A schedule holds one outbound address to a daily ceiling of recipients per large provider, rising day by day along a fixed plan, and the queue sends up to the ceiling and holds the rest - usually until the next UTC day - without spending a retry.
-
One address: the local address a delivery binds -
SMTPDeliveryBindToIP(Bind outbound connections to IP on Delivery of e-mail), or a global rule's bind to address action. A schedule does nothing until the address is on the host and one of those binds it; the Deck warns when the setting does not. -
Per provider, decided from the mail host the delivery connects to, never the recipient's domain - a company on Google Workspace is Google's:
Provider Mail hosts Google google.com,googlemail.com,aspmx.l.google.comMicrosoft outlook.com,hotmail.com,protection.outlook.com,olc.protection.outlook.comYahoo yahoodns.net,yahoo.com,aol.comApple icloud.com,apple.comProton protonmail.ch,proton.meEveryone else counted together, at five times the named providers' ceiling -
Three fixed plans, recipients per named provider per day:
Plan Day 1 Day 7 Last day Then standard 50 5,000 day 30: 100,000 no ceiling gentle 25 250 day 60: 50,000 no ceiling fast 100 40,000 day 15: 200,000 no ceiling -
Recipients, not messages - a message to forty people at Gmail is forty to Google.
Schedules are made on the Deck's queue page or with GET/POST /api/v1/warmup (PUT/DELETE /api/v1/warmup/{id}, and /history for the day-by-day counts), and are in the configuration
backup. Nothing is held until a schedule is made. The plans and the provider table are fixed;
there is no pool of addresses to spread a day across, and the ceilings rise by the calendar, not by
how the providers are answering - a provider already deferring the address is slowed for by the
back-off, not the warm-up.
-
GET /api/v1/queue/shaping(the queue's permission, server-wide): the open back-off windows - destination, since, until, the window's minutes, the reply and the host that gave it, how many deliveries it has held - and the connections open under each ceiling and each tenant.DELETE /api/v1/queue/shaping/{destination}clears one window once you have fixed the cause, and is recorded on the audit trail. - The Control Deck's Delivery queue shows the same as Slowed destinations, with a Resume button, the connection counts, and the warm-up schedules with their counts and a small editor.
- The application log says, for each batch held, which rule held it and until when.
The windows and the connection counts live in memory: a restart forgets them, which costs at most one more slow-down reply per destination. Nothing of it is shared between the nodes of a warm-standby pair.
Since 6.3.4. Three things read how the world is answering the mail this server sends; each is its own switch.
| Feature | What it does | Off until |
|---|---|---|
| Bounces and the suppression list | Every refusal and every RFC 3464 report for one of this server's senders is classified by its enhanced status code and counted per recipient and per sending domain; an address that hard-bounces as many times in a row as the threshold says goes on that domain's suppression list, and the next message to it is refused with a sentence (or dropped, or only observed). Visible and removable by hand on Monitoring & troubleshooting → Suppression list, the Deck, hmctl and PowerShell |
BounceProcessingEnabled |
| Complaints: the feedback loops | The abuse reports the large providers post when their readers press this is spam (RFC 5965) are parsed, recorded against the sending domain and account, counted, and past a threshold put the address on the same suppression list; a complaint rate per domain is in the metrics and raises the complaints.rate.high alert |
ComplaintProcessingEnabled and a ComplaintMailbox registered with the providers |
| The reputation watch | Once a day, asks the blocklists about the addresses this server sends from, and raises reputation.listed when one is listed |
On in a new installation, off after an upgrade (reputation_watch_enabled); with no bind address and none named it asks nothing |
The relay setting profile switches bounce processing on together with a per-destination
ceiling, and sender adds the feedback loops and a per-tenant ceiling
(Profiles and Environment). A mailing list keeps bounce counts of its own beside these
(Mailing Lists).
- The back-off's phrases and the warm-up's providers and plans are fixed, and cannot be edited.
- The tenant share is not a volume control; the per-account sending limits are.
- The back-off reads the first non-fatal reply a recipient got, so a genuine 421 from a second MX host after a plain 4xx from the first is not seen.
- The warm-up counts are not exported as metrics; they are on the Deck and the routes.
- Nothing here is a reputation service. It slows down when asked, holds to a plan, and tells you what came back; it does not ask the providers how they rate this server.
See also: Routes and Relays · Monitoring and Health · Troubleshooting · Encryption and Certificates · Stopping Spam
hMailServer 6.3.7, the latest release (17 October 2026, schema 6108) · AGPL-3.0-or-later · Repository · Mirror on GitHub · Report a documentation error (a GitLab issue naming the page)
Home — full index
Start here
1. Install and run
- Before You Install
- Installing hMailServer
- Installing on Linux
- Running in a Container
- Profiles and Environment
- The Control Panel
- The Control Deck
- Your First Domain and Mailbox
- Connecting a Mail Client
- The Webmail
- DNS for Your Domain
- Migration
2. Secure it
- Encryption and Certificates
- Database TLS
- Encryption for People
- Stopping Spam
- Stopping Viruses
- Security Hardening
- Secure Defaults
- The Service Account
- Secrets at Rest
- Sign-in and Identity
- Security Policy
3. Operate it
- Monitoring and Health
- The SNMP Agent
- Backup and Restore
- Message Storage
- Compliance and eDiscovery
- Troubleshooting
- Diagnosing Stalled Mail
- Relocating an Installation
- Upgrading hMailServer
- Upgrading Guide
- The Update Feed
- Migrating the Database Backend
- High Availability Runbook
- Warm Standby
- Runbooks Digest
4. Extend it
- Rules and Sieve
- Aliases Lists and Public Folders
- Rooms and Equipment
- Mailing Lists
- Routes and Relays
- Mail In to a Webhook
- Outbound Shaping
- The COM API and Scripting
- Event Scripts
- The REST API
- Command Line
- APIs Reference
5. Contribute to it
- Project Handbook
- Architecture
- Contributing
- Release Process
- Governance
- Assurance Case
- Regression Test Environment
- Fuzzing
- Regulatory Scope
- Third-Party Binaries
Look it up — from any journey
- Settings Reference
- Settings Overview
- Capabilities and Configuration
- Control Panel Reference
- Control Panel Pages
- Ports Reference
- Changes-Since-6210
- Version-History-to-6210
- Glossary
About this wiki
- hMailServer 6.3.7 is the latest release (17 October 2026, schema 6108)
- Pages say since 6.3.4 where a feature is new in it
- AGPL-3.0-or-later
- Repository, the one place the project is worked on
- Its mirror on GitHub, since 18 October 2026, with no Issues
- Questions: a GitLab issue with the Question template, GitHub Discussions Q&A, or the forum
- Report a documentation error: a GitLab issue naming the page