Contents
Why pools matter
A single source IP can only carry so much mail before the volume itself becomes a reputation risk, and a single IP is a single point of failure: if it develops a problem, the stream it carries stops. Virtual MTA pools solve both. A pool gathers several IPs under one name, spreads traffic across them, and lets the operator manage the group as a unit. Pools are the mechanism by which a PowerMTA deployment scales beyond one IP per stream and gains the resilience of having alternatives when one IP falters.
This guide exists because pool configuration is straightforward but the distribution behavior, and the strategic choices around it, reward understanding. Round-robin versus weighted, pool-level throttling versus per-IP limits, how pools support warming, how to pull an IP out of rotation during an incident: these are the practical decisions an operator makes when working with pools. The structure of this guide: what a virtual MTA pool is, round-robin distribution, weighted distribution, configuring a pool, assigning pools to domains and streams, the relationship between pool throttling and per-IP rates, using pools for IP warming, removing an IP from rotation, and the diagnostic workflow when pool distribution does not behave as expected.
What a virtual MTA pool is
A virtual MTA pool is a named group of virtual MTAs that PowerMTA treats as a single routing target.
A single VMTA binds to one source IP through its smtp-source-host directive. A pool gathers several VMTAs, and therefore several IPs, under one pool name. When a domain block or a message stream is routed to the pool, PowerMTA spreads that traffic across all the pool's member IPs rather than concentrating it on one.
Operators build pools for three main reasons:
| Reason | What the pool provides |
|---|---|
| Volume distribution | A high stream shares across IPs, none overloaded |
| Redundancy | One IP can fail without stopping the stream |
| Reputation spreading | Reputation builds across IPs, not concentrated |
Volume distribution. A stream sending more than one IP can healthily carry needs multiple IPs, and a pool spreads the load so no single IP exceeds its safe volume.
Redundancy. If one IP in a pool develops a reputation problem or a technical fault, the other members keep carrying the stream, and the operator can pull the troubled IP without halting delivery.
Reputation spreading. A stream distributed across several IPs builds its reputation across all of them. This diversifies the reputation exposure: a problem affecting one IP does not take down the whole stream's delivery.
The pool is defined with a virtual-mta-pool block listing its members, and then referenced anywhere a single VMTA could be referenced.
Round-robin distribution
Round-robin is PowerMTA's default pool distribution. PowerMTA cycles through the pool members in turn, routing each successive message through the next member IP. Over time, every IP in the pool carries an approximately equal share of the traffic.
If a pool has four IPs and round-robin distribution, roughly a quarter of the stream's messages go out from each IP. The distribution is even, and it stays even as long as the pool composition is unchanged.
Round-robin is the right choice when the pool members are equivalent:
- All the IPs are warmed and established.
- All the IPs are healthy.
- All the IPs are meant to carry the same load.
- There is no reason to favor one IP over another.
When those conditions hold, equal distribution is exactly what the operator wants: every IP stays at the same volume level, builds reputation at the same pace, and the load is balanced. Round-robin is the simple, correct default for a pool of equivalent IPs, and a pool of established production IPs sending an ordinary stream is the textbook case for it.
Weighted distribution
Weighted distribution lets the operator assign each pool member a weight, and PowerMTA distributes traffic in proportion to the weights rather than equally.
A member with a higher weight carries a larger share; a member with a lower weight carries a smaller share. If a pool has three IPs with weights 5, 5, and 1, the first two each carry roughly five-elevenths of the traffic and the third carries one-eleventh.
Weighted distribution is the right choice when the pool members are not equivalent and should deliberately carry unequal load:
| Situation | Weighting approach |
|---|---|
| One IP still warming | Low weight on the warming IP |
| Mixed-capacity IPs | Weight proportional to capacity |
| Deliberately favoring some IPs | Higher weight on the favored IPs |
| Gradually shifting load to a new IP | Raise the new IP's weight over time |
The classic case is IP warming, covered in detail below: a pool containing established IPs plus one warming IP gives the warming IP a small weight so it receives only the limited volume appropriate to its warmup stage, while the established IPs carry the bulk.
The general rule is clean: round-robin when the pool members should carry equal load, weighted when they should carry deliberately unequal load.
Configuring a pool
A pool is defined with a virtual-mta-pool block listing its member VMTAs.
A basic round-robin pool:
<virtual-mta-pool marketing-pool>
virtual-mta mkt-ip-1
virtual-mta mkt-ip-2
virtual-mta mkt-ip-3
virtual-mta mkt-ip-4
</virtual-mta-pool>
This pool, marketing-pool, contains four VMTAs. With no weights specified, PowerMTA uses round-robin and each member carries an equal share.
A weighted pool assigns a weight to each member:
<virtual-mta-pool marketing-pool>
virtual-mta mkt-ip-1 5
virtual-mta mkt-ip-2 5
virtual-mta mkt-ip-3 5
virtual-mta mkt-ip-warming 1
</virtual-mta-pool>
Here the three established IPs each have weight 5 and the warming IP has weight 1, so the warming IP carries one-sixteenth of the traffic and the established IPs share the rest.
The member VMTAs are defined separately with their own smtp-source-host bindings:
<virtual-mta mkt-ip-1>
smtp-source-host 203.0.113.50 m1.example.com
domain-key k1,example.com,/etc/pmta/keys/example.pem
</virtual-mta>
<virtual-mta mkt-ip-2>
smtp-source-host 203.0.113.51 m2.example.com
domain-key k1,example.com,/etc/pmta/keys/example.pem
</virtual-mta>
The pool references VMTAs by name; the VMTAs carry the actual IP bindings. After defining or changing a pool, pmta reload applies the change.
Assigning pools to domains and streams
A pool is used by referencing it where a single VMTA could be referenced.
Assigning a pool to a domain block. A domain block can route a recipient domain to a pool:
<domain gmail.com>
virtual-mta-pool marketing-pool
max-msg-rate 12000/h
</domain>
With this, mail to gmail.com is distributed across the marketing-pool's IPs.
Assigning a pool via the X-Virtual-MTA header. The submitting application can route a message to a pool by injecting the pool name in the X-Virtual-MTA header:
X-Virtual-MTA: marketing-pool
This is the common pattern for per-stream routing: the application injects X-Virtual-MTA naming the pool for the stream, marketing-pool for marketing, transactional-pool for transactional, and PowerMTA distributes within that pool.
The two approaches combine: the application selects the pool by stream via the header, and domain blocks can refine routing within or across pools. The pool is the unit of routing the application or the config points at, and PowerMTA handles the distribution across the pool's members from there.
Pool throttling versus per-IP rates
A pool has throttling at two levels, and understanding both prevents confusion.
Pool-level throttling. When a domain block assigns a pool, the domain block's rate limits, such as max-msg-rate, apply across the whole pool. A max-msg-rate of 12000/h on a domain block routed to a four-IP pool means the total rate to that domain across all four IPs is capped at 12000/h.
Per-IP rates. Within the pool, each IP can also have its own rate limit, controlling how fast that individual IP sends. This is set with directives like source-ip-max-msg-rate or per-VMTA rate limits, ensuring no single pool member exceeds its safe individual rate even if the pool-level limit would otherwise allow it.
| Level | Controls | Set via |
|---|---|---|
| Pool level | Total rate across all pool IPs | Domain block max-msg-rate |
| Per-IP level | Rate of each individual pool IP | Per-VMTA / source-ip rate limits |
The two levels work together. The pool-level limit caps the total to a destination; the per-IP limits ensure the distribution does not push any single IP past its healthy rate. An operator running a pool of IPs to a destination wants both: a sensible total rate to the ISP, and a sensible per-IP rate so each member stays at a safe individual volume.
The per-IP rates also interact with weighted distribution. Weighting controls the proportion of traffic each member receives; per-IP rate limits cap the absolute rate of each member. An operator using a weighted pool for warming might give the warming IP a low weight and also a low per-IP rate limit, belt and braces, so the warming IP cannot exceed its warmup volume even if the weighting somehow would have sent it more.
Using pools for IP warming
One of the most valuable uses of weighted pools is IP warming. A weighted pool lets a warming IP join a stream while receiving only the small volume its warmup stage allows.
The pattern: the pool contains the established IPs at full weight and the warming IP at a low weight. The warming IP receives a small share of the stream, appropriate to its warmup week, while the established IPs carry the bulk. As the warmup progresses, the operator raises the warming IP's weight week by week, gradually shifting more of the stream onto it, until at the end of the warmup it carries a full equal share.
Week 1, the warming IP at very low weight:
<virtual-mta-pool sending-pool>
virtual-mta established-1 10
virtual-mta established-2 10
virtual-mta established-3 10
virtual-mta warming-ip 1
</virtual-mta-pool>
Mid-warmup, the warming IP's weight raised:
<virtual-mta-pool sending-pool>
virtual-mta established-1 10
virtual-mta established-2 10
virtual-mta established-3 10
virtual-mta warming-ip 5
</virtual-mta-pool>
End of warmup, the warming IP at full equal weight:
<virtual-mta-pool sending-pool>
virtual-mta established-1 10
virtual-mta established-2 10
virtual-mta established-3 10
virtual-mta warming-ip 10
</virtual-mta-pool>
This weighted-pool approach to warming has a real advantage over warming an IP in isolation: the warming IP is part of a real production stream, so the mail it sends is genuine engaged traffic, exactly the kind of mail a warmup needs, rather than artificial warmup traffic. The weighting controls the volume, and the per-IP rate limit on the warming IP provides a hard cap as a safety net. Combining the weighted pool with the per-IP rate limit, and raising the weight on the warmup schedule, gives a clean, controlled warming process integrated into normal sending.
Removing an IP from rotation
When an IP in a pool develops a problem, the operator needs to take it out of rotation. There are two ways, for two situations.
The fast operational way, for an immediate response. Pause the queues using that VMTA with pmta pause queue and the wildcard pattern matching all queues for the VMTA:
# Take a pool member out of active sending immediately
pmta pause queue */troubled-vmta
# When the IP recovers, bring it back
pmta resume queue */troubled-vmta
This takes the IP out of active sending immediately, with no configuration change. The IP is still in the pool definition but is not delivering, and the other pool members carry its share. This is the right move for an immediate incident response: fast and reversible.
The configuration way, for a longer-term removal. Edit the virtual-mta-pool block to remove the troubled VMTA from the member list, or set its weight very low, then pmta reload:
<virtual-mta-pool sending-pool>
virtual-mta established-1 10
virtual-mta established-2 10
virtual-mta established-3 10
# troubled-ip removed from rotation
</virtual-mta-pool>
This makes the removal part of the configuration, which is right for a longer-term removal because a runtime pause would be lost on a restart, while a configuration change persists.
The general approach during a reputation incident: use pmta pause queue for the immediate response to stop sending from the affected IP right away, then if the problem proves longer-term, follow up with the configuration change. Either way, the pool's other members keep carrying the stream, which is precisely the redundancy benefit a pool provides over a single IP.
When a pool member is taken out of rotation, its share of the traffic redistributes to the remaining members. A four-IP pool that loses one IP now has three IPs carrying what four used to carry, so each remaining IP's volume rises by a third. If the pool was already near its per-IP rate limits, removing a member can push the survivors past their healthy rate. When pulling an IP from a pool, check whether the remaining members can absorb the redistributed load without exceeding their safe per-IP rates. If they cannot, the operator may need to reduce the stream's total volume while the IP is out, rather than letting the remaining IPs overload.
Diagnosing pool distribution issues
When a pool does not distribute traffic as expected, the diagnostic workflow:
Step 1: confirm the actual distribution. Query the accounting log for the source IP on recent deliveries for the stream, grouped by IP, to see the real distribution across the pool members.
SELECT
coalesce(dlvProxyServerIp, dlvSourceIp) AS source_ip,
count() AS deliveries
FROM pmta_accounting
WHERE type = 'd'
AND timeLogged >= now() - INTERVAL 1 DAY
GROUP BY source_ip
ORDER BY deliveries DESC;
Step 2: compare against the expected distribution. For a round-robin pool, the members should be roughly equal. For a weighted pool, the proportions should match the weights. A distribution that does not match is the symptom to diagnose.
Step 3: check the pool definition. Verify the virtual-mta-pool block lists the members and weights the operator intends. A missing member, an unintended weight, or a typo in a VMTA name explains a wrong distribution.
Step 4: check whether members are paused. Run pmta show queues and look for paused queues. A pool member that is paused, perhaps from an earlier incident response that was never resumed, carries no traffic, and the remaining members carry more. A forgotten pause is a common cause of a pool that distributes unevenly.
Step 5: check per-IP rate limits. If a pool member has a low per-IP rate limit, it cannot carry its weighted share even though the weighting would send it more. The per-IP limit caps the member regardless of weight. A member persistently below its expected share may be hitting its per-IP rate cap.
Step 6: check member health. A pool member in backoff because of throttling from a destination delivers slowly, so it carries less than its share even though it is technically in the pool. Check whether any member is in backoff.
Step 7: verify after reload. If the pool was recently changed, confirm pmta reload was run and pmta show settings reflects the current pool definition.
An operator we worked with noticed that one IP in a four-IP marketing pool was showing a much higher volume than the other three, and they were concerned the imbalance was hurting that IP's reputation. They expected round-robin distribution to keep all four roughly equal, and three of the four were indeed equal, but the fourth was carrying far more than its quarter share. The pool definition looked correct: four members, no weights, so round-robin and equal shares were expected. The accounting log confirmed the imbalance but did not explain it. The cause turned out to be a pmta pause queue from a month earlier. One of the four pool members had had a brief reputation wobble, and an operator had quite correctly paused that IP's queues as an immediate incident response. The wobble resolved within a day, but nobody ran pmta resume queue to bring the IP back. So for a month, the pool had effectively been operating as a three-IP pool: PowerMTA's round-robin was distributing across the three unpaused members, and one of those three was, by the operator's confused reading, the one carrying too much, when in fact all three unpaused members were carrying a third each, which is more than the quarter the operator expected, while the paused fourth member carried nothing. The fix was a single command, pmta resume queue for the paused member, after which the pool returned to four-way round-robin and all four IPs carried an equal quarter. The lesson is the diagnostic step about checking for paused members: a pool that distributes unevenly is very often a pool with a member that was paused during an incident and never resumed. The pause is the correct immediate response to a reputation problem, but it is a runtime state, and it needs a deliberate resume when the problem clears, or it quietly persists and skews the pool for as long as nobody notices.
PowerMTA virtual MTA pools are how a deployment scales beyond one IP per stream and gains resilience. A pool groups VMTAs, and therefore IPs, under one name, distributing traffic across them, by default round-robin for equal-load pools and optionally weighted for deliberately unequal distribution. Weighted pools are particularly valuable for IP warming, letting a warming IP join a real production stream at a controlled low share that rises on the warmup schedule. Pool throttling works at two levels, a pool-wide total and per-IP caps, and both should be set deliberately. When an IP needs to leave rotation, pmta pause queue handles the immediate incident response and a configuration change handles a longer-term removal, with the other pool members carrying the stream either way. The most common pool distribution problem is a member that was paused during an incident and never resumed, which the diagnostic workflow catches by checking for paused queues. Operators who understand round-robin versus weighted, set both throttling levels, and remember that a pause needs a matching resume, get pools that distribute predictably and scale cleanly.