Knowledge base

Sending windows set in the message itself

scheduled delivery windows
Sending time becomes a property of the message

The header format is a comma-separated list of intervals:

x-schedule: 2026-08-29 17:01:11 / 2026-08-29 17:30:11, 2026-08-30 17:01:11 / 2026-08-30 17:30:11

You can list as many intervals as needed.

Two consequences make a schedule more than a convenience.

The message’s lifetime is canceled. The bounce-after setting does not apply to such a recipient: the message lives until the end of the last window and bounces when there is nothing left to try by. That is, when to give up is decided by the schedule, not by the retry policy.

A window is a permission, not a promise. If the queue is in retry mode at submission time, delivery will not start at the beginning of the window: it will start when the queue leaves that mode. A problematic recipient domain can eat up a whole window, and not a single attempt will be made inside it.

The main trap is that a window can be wasted. A schedule looks like a guarantee of “send between 17:01 and 17:30,” but in fact it is permission to try during that time. A queue stuck in retries since the morning will pass through the window without an attempt — and the message may not get another chance.

This cannot be checked in advance: the submitting side does not know the state of the queue at submission time.

What the Hub does. It does not use it. The Hub keeps the warm-up schedule on its side: the scheduler decides when to submit a message and submits it at that moment. It does not set the header with windows and does not grant permission to read it in sources — the vendor default remains there.

The difference between the two designs is not convenience but who is responsible for a missed window. As long as the schedule is in the Hub, it sees that the message did not go out and decides what to do. By putting the schedule into the message, it loses this control: a window can close inside the node without a single attempt.

Example configuration
# permission to read the header with windows is granted to the source
<source 10.0.0.0/24>
    process-x-schedule true    retain-x-schedule false
</source>
The first line enables the schedule, the second is left at the default: the header with windows is removed before delivery and is not shown to the recipient. The schedule itself arrives in the message; it is not in the configuration.
yellow — — directive names, blue — blocks. They are highlighted the same way in the text of the card.
▲

Common mistakes and problems

what people get wrong and how it ends3 mistakes▶

Treating a window as a sending guarantee

§ 11.13

What it costsIf the queue is in retry mode at submission time, there will be no attempt inside the window at all — delivery will start only after the queue leaves that mode. A mailing planned for an exact time will go out later or not at all.
How to spot itScheduled messages remained in the queue even though the window has passed.
How to do it rightSet several consecutive windows instead of one, and leave headroom on the last. A single narrow window is the most fragile option.

Expecting the message to bounce on expiry

§ 11.13

What it costsThe lifetime setting does not apply to a recipient with a schedule. The message stays in the queue until the end of the last window, even if that is days later, and takes up spool space all that time.
How to spot itThe queue holds messages older than the configured lifetime.
How to do it rightPlan the windows so that the last one closes no later than the deadline you consider reasonable.

Setting the header without granting permission

§ 3.3.7.58

What it costsWithout permission for the source, the engine delivers the message the usual way — immediately and without any schedule. No error occurs, and the header itself stays in the message and travels to the recipient.
How to spot itScheduled messages go out immediately, and the recipient sees a service header in the message.
How to do it rightGrant permission to the source block the submission falls under.
Compatibility
PowerMTA 6.0
described in the manual of this version · platform: any
The vendor does not state the first version for every directive — there is no note here. The name also appears in the 5.0 edition of the manual.
How to check on the node
The schedule is visible for recipients in the queue — as a separate column in the listing:
pmta list --schedule --maxitems=20
An empty column means the message has no schedule: either the header did not arrive or the source is not allowed to read it. Ours is always empty — the Hub does not use this mechanism.
In the Hub
Cost of a mistake
reversible: harms only while it is set
Scenarios
Address warm-up · Untangle a stuck queue