Skip to content

/ Infrastructure · Operational guide

KumoMTA traffic shaping: a practical guide with per-receiver examples.

The part of KumoMTA that turns a high-performance MTA into one that mailbox providers actually want to talk to. This guide covers the mental model, the four tunables that matter most, the static-versus-automated decision, the three-file pipeline, real per-receiver examples for Gmail and Yahoo and Microsoft and Apple, and the iteration methodology that keeps you from burning reputation while you tune.

Published 2026-06-18 By Lukas Bergström, Head of Deliverability Operations ~15 min read

In short

KumoMTA traffic shaping is the layer that controls how aggressively your MTA opens connections, reuses them, and paces messages toward each receiver. It is configured across three files that merge in order — upstream defaults, community-tuned baselines, your custom overrides — and it operates per egress path, which combines an egress source with a site name derived from MX rollup. The four tunables that matter most are connection_limit, max_message_rate, max_connection_rate, and max_deliveries_per_connection. Static rules express the baseline; Traffic Shaping Automation adjusts in real time when receivers push back. Both layered together is the production-grade pattern.

  • 3 files

    Defaults from KumoMTA, community shaping.toml from the KumoCorp repo, and your custom file — merged in that order with later files overriding individual keys.

  • 4 tunables

    Connection limit, message rate, connection rate, and deliveries per connection are the levers that account for the vast majority of receiver responses.

  • Per MX

    Throttling applies to site name (the MX rollup) rather than destination domain. Ten domains sharing Google Workspace MX share one rate counter.

  • TSA daemon

    Traffic Shaping Automation runs as a separate service (kumo-tsa-daemon.service) that listens for log events and instructs kumod to adjust shaping in real time.

/ 01 — Mental model

Why does KumoMTA need traffic shaping when other tools seem fine without it?

The first mental shift required to understand KumoMTA shaping is that the limits are imposed by the receiving side, not by the sending side. Gmail, Yahoo, Microsoft, and Apple each maintain their own assessment of how aggressively you are allowed to deliver to them, scored by your sender reputation, the engagement history of your recipients, and the operational load on their infrastructure at any given moment. Those assessments translate into rate limits and connection caps that you do not see, but that you collide with when shaping is too aggressive.

The second mental shift is that shaping happens at the egress path, which is a combination of an egress source — your sending IP and EHLO domain — and a site name, derived by merging the MX hostnames of the destination. This is why KumoMTA throttles ten Google Workspace customer domains together: they all roll up to the same MX site, and the receiver enforces a single rate budget against your IP. Treating them as separate would split a budget that the receiver does not split, leading to surprises in production.

The third mental shift is that good shaping is dynamic. The right rate for Yahoo on Monday morning is not the right rate for Yahoo on Friday afternoon. Static shaping captures your baseline understanding of what each receiver tolerates; Traffic Shaping Automation captures the receiver's real-time signal that the baseline needs to flex. Production deployments need both.

The vocabulary that recurs

Egress source
A sending IP plus an EHLO domain. Defines the identity at the SMTP layer.
Egress pool
A named group of egress sources that messages can be routed through. Tenant isolation lives here.
Site name
The identifier KumoMTA computes by merging MX hostnames for a destination. Throttling unit.
Egress path
Egress source combined with site name. This is what shaping rules apply to.
Ready queue
The queue from which messages are dispatched along an egress path once shaping permits.

/ 02 — Tunables

The four tunables that account for most receiver responses.

KumoMTA exposes dozens of shaping options. The four below account for the vast majority of receiver responses in practice. Get these right per receiver, layer Traffic Shaping Automation on top, and you are most of the way to a polite MTA. The remaining tunables matter at the edges; these four matter on day one.

Tunable 1

connection_limit

Maximum number of simultaneous outbound SMTP connections KumoMTA will open toward a given site name from a given egress source. Sets the parallelism ceiling.

Typical Gmail: 50 to 100. Typical Yahoo: 20 to 50. Typical Microsoft: 30 to 60. These are starting points, not final values.

Tunable 2

max_message_rate

Maximum number of messages KumoMTA will send through the egress path per unit of time. Expressed in formats like 100/min or 10000/hour.

The lever for absolute throughput. Drives most of the conversation when a receiver starts deferring.

Tunable 3

max_connection_rate

Maximum rate at which KumoMTA opens new connections to the site. Distinct from connection_limit because a low rate with high reuse can outperform a high rate with low reuse.

Microsoft is famously sensitive here. Open too many connections too fast and you get throttled even at moderate message rates.

Tunable 4

max_deliveries_per_connection

How many messages KumoMTA will send down a single open connection before closing it and opening a new one. Trades off connection reuse efficiency against receiver expectations.

Gmail handles high values (100 to 200) gracefully. Some receivers prefer 10 to 50 and respond with deferrals beyond that.

Interaction nobody warns about

These four tunables interact. A high max_message_rate with a low connection_limit forces messages through fewer connections faster, which can trigger receiver-side rate limits per connection. A low max_deliveries_per_connection with a high max_connection_rate causes thrash, opening and closing connections faster than the receiver wants. Tune them as a system, not in isolation.

/ 03 — Layers

When should you use static shaping versus Traffic Shaping Automation?

Both, layered. The choice is not exclusive. Static shaping defines the baseline you believe is correct. Automation adjusts that baseline in real time when receivers push back. The two layers solve different problems and need each other.

Traffic Shaping Automation (kumo-tsa-daemon) Listens to log events · Matches receiver responses against regex rules · Issues real-time config changes to kumod Dynamic · Receiver-reactive · Cluster-aware overrides at runtime Merged static shaping rules defaults.toml + community/shaping.toml + your shaping_custom.toml (merged in order) Static · Author-intended · Configuration-time applied to every egress path kumod — SMTP delivery, ready queues, egress sources Receives merged rules + automation overrides · Sends to receivers

When static shaping alone is sufficient

  • Low daily volume per receiver (under fifty thousand)
  • Stable sending patterns with no campaign spikes
  • Established reputation with no recent complaints
  • Single-node deployment where cluster-aware automation is overkill

When you need automation on top

  • Multi-million daily volume with campaign spikes
  • Multi-tenant deployments where reputation varies by tenant
  • Mailbox providers known for inconsistent throttling (Microsoft, Apple)
  • Cluster deployments where throttle coordination across nodes matters

/ 04 — Pipeline

How the three-file shaping pipeline merges defaults, community values, and your overrides.

The shaping helper reads three files in order. Each file can add new scopes or modify keys within existing scopes. When the same scope appears in multiple files, the later file overrides individual keys rather than replacing the entire scope. This lets you inherit defaults, benefit from community-tuned values, and override only the parts you know better for your specific sending.

1

/opt/kumomta/share/policy-extras/shaping.toml

Upstream defaults · Shipped with KumoMTA

The default shaping baseline maintained by the KumoMTA team. Updated with each KumoMTA release. Covers all common receivers with conservative throttles that work for most senders. Do not edit this file directly; it will be overwritten on upgrade.

2

/opt/kumomta/share/community/shaping.toml

Community knowledge · KumoCorp/kumomta repo

Community-maintained file with tuned values contributed by operators running KumoMTA at scale. Hosted on GitHub at the KumoCorp/kumomta repository. Includes provider-specific automation rules for common receiver response patterns. Pulled in by the shaping helper automatically; do not edit directly, but contributing improvements back to the community is welcomed.

3

/opt/kumomta/etc/policy/shaping_custom.toml

Your overrides · Source-controlled in your repo

Your overrides. This is the file you edit when you know something about your sending that the defaults and community values do not capture. Source-control it in your infrastructure repository. Most production deployments touch fewer than ten scopes here; the rest comes from layers one and two.

Validation tool

KumoMTA ships with a validator at /opt/kumomta/sbin/validate-shaping. Run it against your custom file before every reload to catch syntax errors before they touch production.

$ /opt/kumomta/sbin/validate-shaping /opt/kumomta/etc/policy/shaping_custom.toml
OK

/ 05 — Per receiver

Real shaping configurations for the four major receivers.

The examples below show production-grade starting points for the four receivers that handle most B2C and transactional email globally. These are starting points, not final values. Your actual tuning depends on your reputation, volume, and the specific complaints history you are working against. Use them as the baseline to iterate from.

Gmail (Google Workspace)

Most forgiving major receiver if your reputation is decent. High connection reuse works well.

["gmail.com"]
mx_rollup = true
connection_limit = 100
max_message_rate = "500/min"
max_connection_rate = "60/min"
max_deliveries_per_connection = 200
enable_tls = "Required"
idle_timeout = "30s"

Yahoo (also AOL, Verizon)

More sensitive to connection count than message rate. Lower concurrency, longer-running connections work better.

["yahoo.com"]
mx_rollup = true
connection_limit = 30
max_message_rate = "200/min"
max_connection_rate = "15/min"
max_deliveries_per_connection = 100
enable_tls = "Required"
idle_timeout = "60s"

Microsoft (Outlook, Hotmail, Live)

The most variable of the four. Provider-level rollup via MX suffix captures the entire Microsoft ecosystem in one rule.

[provider."microsoft"]
match = [{MXSuffix=".olc.protection.outlook.com"}]
connection_limit = 50
max_message_rate = "300/min"
max_connection_rate = "20/min"
max_deliveries_per_connection = 50
enable_tls = "Required"
idle_timeout = "45s"

Apple (iCloud, mac.com, me.com)

Quieter ecosystem with idiosyncratic behavior. Conservative defaults work better than aggressive tuning.

[provider."apple"]
match = [{MXSuffix=".mail.icloud.com"}]
connection_limit = 20
max_message_rate = "100/min"
max_connection_rate = "10/min"
max_deliveries_per_connection = 50
enable_tls = "Opportunistic"
idle_timeout = "60s"

/ Interactive — the traffic shaper

Where do your limits land for each receiver?

Receiver

\u2014

\u2014

Receiver character

\u2014

Illustrative mental model, not published limits. Mailbox providers do not publish their thresholds, and your real tolerance moves with your reputation \u2014 a warmed, trusted IP gets far more room than a cold one. Use this for the shape of the trade-off, then tune against real responses.

/ 06 — Automation

What does Traffic Shaping Automation do in practice?

TSA watches the response stream from receivers, matches lines against regex patterns you define, and applies actions when matches accumulate to a threshold. The system is reactive by design — it does not predict what will happen, it reacts to what already happened, fast.

Anatomy of an automation rule

Each rule has four parts: a regex pattern that matches receiver responses, an action to take when matched, an optional trigger threshold, and an optional duration. The pattern goes inside an automation array scoped to a receiver or provider.

[provider."microsoft"]
match = [{MXSuffix=".olc.protection.outlook.com"}]
automation = [
  { regex = "4\\.7\\.0 .* deferred",
    action = "Suspend",
    duration = "1h" },

  { regex = "5\\.7\\.500 .* request not allowed",
    action = { SetConfig = {
      name = "max_message_rate",
      value = "50/min" } },
    trigger = { Threshold = "3/hr" },
    duration = "2h" },

  { regex = "too many connections",
    action = { SetConfig = {
      name = "connection_limit",
      value = 20 } },
    duration = "30m" }
]

Action types

  • "Suspend" — stop delivery to this egress path entirely for the duration
  • SetConfig — temporarily change a tunable on this path for the duration
  • "Bounce" — generate a synthetic bounce, useful for permanent failure responses receivers send incorrectly

Trigger semantics

  • No trigger: action fires immediately on first match
  • Threshold = "N/window": action fires when N matches accumulate within the time window
  • Threshold-based rules are how you avoid overreacting to a single noisy response

/ 07 — Cluster

Shaping across multiple KumoMTA nodes without dividing throttles manually.

Single-node deployments handle shaping locally and never have to think about coordination. Once a cluster has two or more kumod nodes, naive shaping breaks: each node enforces its own throttles independently, so a global limit of one hundred connections per minute becomes effectively two hundred across two nodes. KumoMTA solves this with cluster-aware TSA.

The pattern

The TSA daemon listens on an HTTP endpoint that all kumod nodes publish to. Each node sends its observed receiver responses to the daemon; the daemon aggregates across nodes and instructs each kumod what to do. Throttles become global rather than per-node because the decision lives in one place even though enforcement lives in many.

The HTTP endpoint can be a single TSA daemon or a load-balanced pool of daemons for fault tolerance. The kumod nodes only need to subscribe to one daemon instance to receive updates.

Cluster TSA setup · init.lua snippet

-- All cluster nodes publish responses to
-- all TSA daemons; subscribe to one for updates
local shaping = require "policy-extras.shaping"
local shaper = shaping:setup_with_automation {
  publish = {
    "http://127.0.0.1:8008",
    "http://10.0.1.10:8008",
    "http://10.0.1.11:8008",
  },
  subscribe = { "http://127.0.0.1:8008" },
  extra_files = {
    "/opt/kumomta/etc/policy/shaping_custom.toml",
  },
}

/ 08 — Anti-patterns

What goes wrong in shaping configurations we have seen.

Anti-pattern 1 · Copy-pasting throttles across receivers

What happens: the same shaping rule is applied to Gmail, Yahoo, Microsoft, and Apple because it worked for Gmail. Why it fails: each receiver has different sensitivity profiles. Gmail forgives high connection counts; Yahoo does not. Microsoft cares about connection rate; Gmail cares less. Better: tune each receiver as its own object, using the community shaping.toml as a starting point.

Anti-pattern 2 · Overriding everything in shaping_custom.toml

What happens: the team copies the community shaping.toml into their custom file and starts editing it as if it were the only file. Why it fails: they lose the benefit of community updates that flow through the upstream layers. When the community improves Microsoft handling next month, the override blocks the improvement. Better: custom file should only override the specific keys you have reason to change. Let the layers below carry the rest.

Anti-pattern 3 · Tuning without observability

What happens: shaping values get changed based on a hunch or a single observed deferral. Why it fails: noise in receiver responses is high. A single deferral does not justify a config change; a sustained pattern across hours does. Better: wire the official Grafana dashboard from grafana.com before tuning. Look at deferred-then-delivered ratio per receiver, not at individual responses.

Anti-pattern 4 · Automation rules without thresholds

What happens: every TSA rule fires on the first match because no trigger was specified. Why it fails: normal sending generates occasional noise responses that are not signal. A single 4.7.0 line from Microsoft does not mean Microsoft is throttling you; three in an hour might. Better: use threshold triggers on rules that respond to common transient responses; reserve immediate-action rules for unambiguous signals like 5.7.500-style permanent failures.

Anti-pattern 5 · Cluster deployments without cluster-aware TSA

What happens: three kumod nodes each run their own TSA daemon with no cross-publishing. Why it fails: each node enforces shaping based on its local observations, so a global rate limit gets exceeded three times over. Better: configure publish to include all TSA daemons in the cluster. Throttle decisions become coordinated even though enforcement remains distributed.

/ 09 — Iteration

How do you iterate shaping rules without burning reputation?

The methodology below comes from operators who have iterated shaping across multiple receivers and rebuilt reputation more than once after pushing too hard. It is the cheapest way to tune over the long run. Slower to converge, yes, but far less likely to cost you reputation along the way.

Principle 1

One tunable at a time

Change one shaping value, observe for at least twenty-four hours, then decide whether to keep, revert, or adjust further. Changing two or more values simultaneously makes it impossible to attribute downstream effects to the right cause.

Principle 2

Watch receiver-side, not just sender-side

Sender-side queue depth and connection error rate are leading indicators. The real signals live receiver-side: Postmaster Tools reputation, SNDS color codes, Yahoo Insights complaint rates. A change that looks fine in your dashboard but degrades receiver-side reputation is a bad change.

Principle 3

When in doubt, ratchet down

Receivers respond predictably to lower rates and unpredictably to higher ones. Pushing throughput toward the maximum the receiver tolerates is what causes most self-inflicted incidents. Run at eighty percent of what you think the ceiling is and you will spend much less time fighting placement issues, much less time explaining unexpected deferrals to product owners, and considerably less time rebuilding reputation after an aggressive tuning session went sideways on a Friday afternoon.

/ 10 — FAQ

Questions operators ask once they are tuning.

What happens if I run KumoMTA with no traffic shaping configured?

KumoMTA will attempt to deliver messages as quickly as the operating system and network allow, with no concurrent connection caps, no per-destination rate limits, and no backoff on receiver pushback. For a low-volume server sending to a handful of recipients this is fine. For anything that touches Gmail, Yahoo, Microsoft, or Apple at scale, the absence of shaping will trigger receiver-side throttling within minutes, possibly followed by temporary blocks and reputation damage.

Should I write static shaping rules or use Traffic Shaping Automation?

Both, layered. Static rules in your shaping_custom.toml express the baseline you believe is correct for each receiver based on volume and reputation. Traffic Shaping Automation runs on top of that baseline and adjusts in real time when receivers push back. The two layers solve different problems. Static shaping makes the system polite by default. Automation makes it responsive when receivers signal that polite is not polite enough.

How does KumoMTA's three-file shaping pipeline decide which rule wins?

The three files are loaded in order: the upstream defaults shipped with KumoMTA, the community-managed shaping.toml from the KumoCorp repository, and your custom shaping file. When a scope appears in more than one file, options are merged rather than replaced, with later files overriding individual keys. The pattern lets you inherit reasonable defaults, benefit from community-tuned values for common receivers, and override only the parts you know better than the community for your specific sending.

Why does KumoMTA throttle by MX site name instead of by destination domain?

Because reputation is enforced at the receiving infrastructure, not at the recipient domain. When ten different domains all use Google Workspace, they share the same MX hosts, the same throttles, and the same anti-spam infrastructure. Throttling at the domain level means you would maintain ten separate rate counters that all hit the same Google rate limits independently, leading to either over-throttling or under-throttling. KumoMTA computes a site name by merging the MX hostnames for each destination and applies shaping to the site.

How do you iterate shaping rules without damaging deliverability?

Three principles. First, change one tunable at a time and observe for at least twenty-four hours before making the next change. Second, watch the receiver-side signals (Postmaster Tools, SNDS, Yahoo Insights) at least as carefully as the sender-side queue depth and connection rate. Third, when in doubt, ratchet down rather than up. Receivers respond predictably to lower rates and unpredictably to higher ones.

Can shaping rules be different per tenant when running multi-tenant KumoMTA?

Yes, and this is one of the reasons multi-tenant ESPs and agencies move to KumoMTA in the first place. The shaping pipeline is keyed on the egress path, which combines egress source and site name. Different tenants assigned to different egress sources can have completely separate shaping behavior toward the same receiver. A premium tenant with established reputation can have looser throttles than a starter tenant, because the former has the reputation to absorb the pace.

/ Next step

Shaping not behaving like you expect? Let us look at it with you.

The deliverability team at Email Delivery Platform operates KumoMTA traffic shaping across multiple tenants and receivers daily. If you are seeing deferrals you cannot explain, throttles that fire when you do not expect them, or reputation drift you cannot tie to a config change, we can review your shaping with you on a scoping call.