Run it

Deliverability

How a new address warms up, how provider settings work, and what each provider tells you.

Receivers decide whether mail reaches the inbox, and they judge each sending address and domain by its history with them. NitroMTA cannot give an address a history. It can pace a new one at each receiver, back off when a receiver pushes back, and stop mailing anyone who complains or no longer exists.

This page covers how warmup works, how provider defaults and your own configuration fit together, what each provider tells you, and how to configure warmup for any provider.

Warming up a new address

Warmup is optional, and a daily cap is what turns it on. An egress with no cap sends as much as it is given, which suits an address that already has a sending history. A new address has none, so start it with a cap, as installation does, or afterwards:

echo '{"op":"put_cap","account":1,"address":"203.0.113.10","daily_cap":50}' | \
  sudo -u nitromta nitromta admin --config /etc/nitromta/config.toml

The egress then sends at most 50 messages a day to each receiver. Once each UTC day, the engine judges every capped egress on what its receivers replied the day before:

  • a cap rises one rung after a day under every threshold below, on which replies reached half of it;
  • a signal over its threshold to hold keeps the cap where it is;
  • a signal over its threshold to lower takes the cap down a rung, and never below the first;
  • past the last rung there is no cap at that receiver, and warmup is done there.

These are the default thresholds:

SignalMeasured againstHolds the cap atLowers the cap at
ComplaintsDeliveries0.1%0.3%
Permanent failuresReplies2%5%
DeferralsReplies5%20%
ThrottlesRepliesAny1%

A throttle is a 421, or a reply the receiver rules know as a receiver refusing an address for now. A deferral is any other temporary failure. A provider's entry can set its own, as Outlook's does.

Each receiver climbs on its own. A receiver gets a cap of its own once its replies in a day reach 100 or half its cap, whichever is fewer. Until then it shares the egress's own cap with the other small receivers, and they are judged together on the defaults.

A cap with no room puts mail off in the store, so a warming address never delays mail to other receivers. That mail still expires when its lifetime ends ([submission] lifetime_seconds, three days by default), so send a warming address no more than its caps allow, and keep the rest on the sender you have.

A put_egress line can start warmup on an egress with no cap, and never changes it after that: running one again, to change a HELO name, leaves the caps where warmup has taken them. put_cap changes a cap, and warmup's next judgment starts from what you set. nitromta list --config <file> egresses shows each egress's caps and last judgment. A small receiver may never send enough to test its cap, so when you judge an address warm, end its warmup with put_cap and no daily_cap.

With [warmup] automatic = false, the engine judges nothing and caps change only by put_cap, by hand or from a system of your own.

How provider settings work

The engine groups the exchanges a provider runs into one receiver. Its settings come from three layers, and the first that gives a field wins:

  1. your configuration, under [receivers.<Provider>];
  2. the provider's entry in the rules the engine ships, rules/receivers.toml;
  3. the [defaults] entry in those rules, which every provider falls through to, and which applies as it is to any receiver with no entry of its own.

Any field of any provider can be configured, and a new name adds a provider, if it lists its exchanges. The shipped provider entries set connection limits, TLS and throttle rules, and differ by provider.

For warmup, every receiver falls through to the default ladder, 50, 100, 200, 500, 1,000, 2,000, 5,000, 10,000 a day and on to 1,000,000, past which there is no cap. The exception is the shipped Outlook entry, which climbs more cautiously: its ladder takes 14 clean days to reach 10,000, where the default takes 7, and a deferral holds it from 0.5%, not 5%. Both are defaults, which your configuration overrides like any other.

These are the receivers the rules ship, by the names queue, explain, put_cap and your configuration use:

ReceiverCoversComplaints the engine can count
GoogleGmail and Google WorkspaceNone: Gmail sends no per-recipient reports
OutlookOutlook.com and HotmailYes, once your addresses are enrolled, for messages with one recipient
Office365, Office365DaneMicrosoft 365None known: operators report Microsoft's program covering its consumer mail
YahooYahoo Mail and AOLYes, once your DKIM domain is enrolled
AppleiCloud MailNone: Apple offers no feedback loop
Comcast, OrangeTheir own mailSee Comcast's and Orange's postmaster pages

A receiver is defined by its exchanges, so settings cannot split one: Gmail and Google Workspace share a cap, as they share exchanges, and Microsoft's consumer mail and Microsoft 365 are configured separately, as they do not.

What each provider tells you

What each provider's own documentation says, except where this says otherwise. Policies change.

Gmail and Google Workspace

Gmail sends no complaint report for a message. Its feedback loop is aggregate and shown in Postmaster Tools, so the engine never counts a complaint at Google, and warmup there runs on deferrals, throttles and failures alone.

Postmaster Tools shows the spam rate of DKIM-authenticated mail to Gmail accounts, for domains you verify. Google asks for a rate below 0.1%, and never reaching 0.3%. Its data is typically "updated within 24 hours but can take longer", and may be incomplete on days of low volume, so a quiet dashboard on a new address does not mean no complaints.

When it shows complaints, lower the cap yourself, one rung down from the one nitromta list shows:

echo '{"op":"put_cap","account":1,"address":"203.0.113.10","site":"Google","daily_cap":500}' | \
  sudo -u nitromta nitromta admin --config /etc/nitromta/config.toml

The engine cannot see what Postmaster Tools shows. To keep clean SMTP replies from raising the cap while you investigate, disable promotion for this provider in the configuration and restart the engine:

[receivers.Google.warmup]
promote = false

This holds automatic increases for Google on every sending IP. Mail continues under each IP's current cap, and adverse signals can still lower it. Other providers keep their own promotion settings. nitromta list shows the hold; set promote = true and restart when you want clean days to raise caps again. The default is true, inherited from [receivers.defaults.warmup].

Outlook.com and Hotmail

Microsoft's Junk Mail Reporting Program (JMRP) sends a report when a user marks a message as junk, to an address you set in SNDS, once you have registered your addresses there.

Microsoft's SNDS pages do not say what those reports contain. Operators who receive them report that they carry no return path, no recipient and no body, and replace whatever looks like an address, while the Message-ID and custom headers remain.

So the engine sends each message's return path token in a header of its own as well, X-NitroMTA-Report, which is how such a report finds its message. It cannot say which recipient complained, so it only reaches suppression, events and warmup for a message with one recipient. Send one recipient per message if you want Outlook's complaints to count.

Operators report JMRP covering Microsoft's consumer mail, so expect no complaint reports for Microsoft 365.

Yahoo Mail and AOL

Yahoo's Complaint Feedback Loop sends a report in the standard format when a user marks a message as spam. The domain in your DKIM signature's d= must be enrolled through Sender Hub, and reports go to an address you verify there. Yahoo asks for a spam rate below 0.3%, measured on mail delivered to the inbox, so its figure can differ from yours.

Apple iCloud Mail

Apple says "We don't offer a feedback loop (FBL)", so no complaint reaches the engine. That is not the same as no complaints: Apple counts user feedback in its reputation of a sender, and you hear of it only through its replies.

Receiving complaint reports

A provider sends its reports to an address you choose. Point it at an address on your return path's domain, whose MX is already this host, and name that address in the configuration, then restart the engine:

[feedback]
# As setup wrote it, and:
loops = ["[email protected]"]

A report finds its message by the Original-Mail-From field, or the Return-Path or X-NitroMTA-Report of the copy it carries. Found, it suppresses its recipient, makes a Complaint event, and counts toward warmup at the receiver that message was delivered to. A report that names no recipient is taken to be about its message's only delivery, so on a message sent to several recipients it does none of these. A report that names no message is set aside as evidence and does nothing else.

The listener answers each of these the same way, so check a provider's reports in the metrics after your first few. reports_unmatched_total counts the reports that found none of your deliveries, and a provider whose reports raise it is not reaching suppression, events or warmup.

By default an unsigned report may count only for a message originally sent to one recipient. Reports for messages sent to several recipients must be signed by an enrolled reporter before they suppress or count: every recipient shares the message token. Other reports are kept as events, and a later authenticated copy can still apply its effects. To count only reports signed by providers you enrolled with, see [feedback] trusted.

Configuring warmup for a provider

Warmup is configured under [receivers.<Provider>.warmup], and under [receivers.defaults.warmup] for everything that falls through. Each field replaces the one below it and leaves the rest:

FieldWhat it sets
promoteWhether clean days may raise caps; false keeps reductions but holds increases
ladderThe daily caps, each above the one before
sampleThe replies in a day that give a receiver a cap of its own, if fewer than half its cap
complaints, failures, deferrals, throttles[hold, lower], in basis points, where 100 is 1% and a hold of 0 means any

Gmail and Outlook throttle differently, so one ladder rarely suits both. This example starts Outlook lower, holds it on any deferral, and lets Gmail climb faster:

# Outlook starts lower, and any deferral holds it.
[receivers.Outlook.warmup]
ladder = [
  20, 40, 60, 100, 150, 200, 300, 500, 750, 1000, 1500,
  2000, 3000, 5000, 7500, 10000, 20000, 40000, 70000,
  100000, 150000, 250000, 400000, 600000, 1000000,
]
deferrals = [0, 2000]

# Gmail climbs faster than the default.
[receivers.Google.warmup]
ladder = [
  50, 150, 500, 1500, 5000, 15000, 40000, 70000, 100000,
  150000, 250000, 400000, 600000, 1000000,
]

Against the default, for a receiver with a clean day each day and replies reaching half its cap:

Clean daysDefaultThis OutlookThis Gmail
0502050
110040150
220060500
35001001,500
41,0001505,000
52,00020015,000
65,00030040,000
710,00050070,000

A ladder says where a cap goes next, not where it starts. A receiver starts on the egress's own cap, and until it has a cap of its own it is judged on the defaults. Give it one as you start warmup, and it starts there and is judged on its own settings from the first day:

sudo -u nitromta nitromta admin --config /etc/nitromta/config.toml <<END
{"op":"put_cap","account":1,"address":"203.0.113.10","daily_cap":50}
{"op":"put_cap","account":1,"address":"203.0.113.10","site":"Outlook","daily_cap":20}
END

The engine reads these settings as it starts. An egress already warming moves to the new ladder at its next judgment, at the next rung above its cap.

These numbers are an example, and yours should follow what your own receivers reply. Google asks you to start low and increase slowly, and gives no schedule. Three things to weigh:

  • Any deferral. At higher caps, one temporary failure a day is likely, so deferrals = [0, 2000] can stop a cap rising at all. The shipped Outlook setting, [50, 2000], does the same as any deferral up to 200 replies a day, and is a rate of 0.5% above that.
  • A faster Gmail. Gmail's complaints reach you a day or more late, and may not show at low volume, so a fast ladder climbs furthest while it can least see them.
  • A slower Outlook. More of your Outlook mail waits behind its cap, and it still expires at the end of its lifetime.
NitroMTA is open source under Apache-2.0. By Nitrosend and Kam. Want it managed? Use Nitrosend →Docs by Sourcey