# Mail Queue

> See what Postfix is still trying to deliver and why, act on it — retry, hold, release or delete, one message or everything matching a search — and track what happened to any message the server already handled, from the mail log.

Source: https://www.corepanel.net/docs/email/mail-queue/
Last updated: 2026-10-09
Part of the CorePanel documentation — https://www.corepanel.net/docs

---

When a customer says "my mail is not arriving", there are two places to look.
[Email deliverability](https://www.corepanel.net/docs/email/deliverability) covers the first: whether this server's
name, reverse DNS and reputation get its mail accepted at all. **Mail queue** covers the
second: what is still sitting on the server waiting to leave, and what the receiving side
said the last time it was tried.

The page has two tabs. **Queue** shows what is waiting now. **Track delivery** answers
the question that usually comes next: what happened to a message that is no longer queued.
It shows whether the message was delivered, where to and what the other side said. It also
shows whether the message bounced, or was refused before it was accepted.
See [Track delivery](#track-delivery).

The page lives at **Email → Mail queue** and is available on every edition. Only
super-administrators can open it, because one queue holds the outbound mail of every
account on the server, and the mail log names every account's correspondents. Resellers
cannot see it, and an MCP agent token cannot read it either.

![The Mail queue page on its Queue tab, next to the Track delivery tab, with the Live switch and Refresh button above the tiles. A row of tiles counts the queues: 52 messages in all (411 KB), 48 deferred, 1 on hold, 3 active, and 0 incoming and 0 in maildrop. Below the tiles are a search box for sender, recipient or queue ID and a bar reading "52 messages queued" with an "Act on the whole queue" button. The table lists each message with its queue ID, a queue badge and how long ago it arrived; the sender and the first recipient, such as wordpress@vantalabs.dev → anna.rossi3@gmail.com; the last attempt's answer, such as Gmail's "421-4.7.28 … unusual rate" or "Host or domain name not found"; its size; and an actions menu. On the right, a "Who is filling it" panel ranks the senders: wordpress@vantalabs.dev with 46 messages, Bounce (no sender) with 4, and billing@corepanel.io and news@east-region.cloud with 1 each.](https://www.corepanel.net/_astro/mail-queue-dark.CM1R0jh7.png)

Nothing on this page is cached. Each refresh reads the queue directly from Postfix
(`postqueue -j`), and the **Live** switch re-reads it every 15 seconds.

## The queues

The tiles show every queue's size whatever the search is set to, so the overall picture
stays in view while you look at one sender. Clicking a tile filters the table to that
queue.

| Queue | What is in it |
|---|---|
| **Deferred** | Mail that could not be delivered yet and will be tried again. This is where problems show up. |
| **On hold** | Mail that you (or another tool) parked. Postfix leaves it alone until it is released or deleted. |
| **Active** | Mail being delivered right now. |
| **Incoming** | Mail that has just been accepted and has not been scheduled yet. |
| **Maildrop** | Mail submitted locally (PHP `mail()`, `sendmail`) that Postfix has not picked up yet. |

Postfix keeps retrying deferred mail, waiting longer between attempts each time. After five
days it gives up and returns the message to the sender as undeliverable.

## Reading a message

Each row shows the message's **sender** and its first **recipient**, with a count of any
others. The **Last attempt** column shows what the receiving server answered, word for
word. It is usually enough to tell what kind of problem you have:

- **`421`/`451` with "rate", "volume" or "reputation"**: the provider is throttling this
  server. Retrying now will not help. If one sender accounts for most of the queue, that
  sender is the problem.
- **"Host or domain name not found"**: the recipient's domain has no mail server, or DNS
  could not be resolved. A typo in the address is the usual cause.
- **"Connection timed out" / "Connection refused"**: the recipient's server is down or
  unreachable. The message delivers by itself once it comes back.
- **"Not tried yet"**: the message is new or is being delivered right now.

A sender shown as **Bounce (no sender)** is a delivery report. Postfix sends these with an
empty sender so that they can never bounce back themselves. A queue full of bounces
usually means the server is sending spam: someone sends to addresses that do not exist,
and the failures come back here.

Click a queue ID to open the message. The dialog shows the reason for every recipient,
the message headers and the start of its body, each cut at 64 KiB. Everything is shown as
plain text and never rendered. The headers are usually where you find out who sent a
message. On mail submitted on the server itself, by PHP's `mail()` or by `sendmail`, the
first `Received:` line reads `from userid N`. That number is the Linux user ID of the
account that sent it.

## Who is filling it

The panel on the right ranks the senders with the most messages among those the search
matches. During a spam run this panel tells you what is happening: one address, often
`wordpress@` or a contact form, with hundreds of messages. Click a sender to show only its
mail. **Bounce (no sender)** can be picked the same way.

A sender picked here is matched **exactly**, unlike the search box, which matches any part
of the sender or a recipient. The difference matters when you act on everything matching.
Searching for `a@gmail.co` also matches mail *to* `maria@gmail.com`, so deleting by that
search would remove other customers' mail too. Picking the sender only reaches messages
sent from that exact address. A chip next to the search box shows the sender filter, and
its **×** removes it.

## Acting on messages

| Action | What it does |
|---|---|
| **Retry now** | Asks for immediate delivery of deferred mail instead of waiting for the next scheduled attempt. Messages in any other queue are skipped. |
| **Hold** | Moves messages to the hold queue, where Postfix leaves them alone. A message that is being delivered right now is held once that attempt finishes. |
| **Release** | Moves held messages back to the deferred queue, from where they are tried again. |
| **Delete** | Removes messages from the server **without telling anyone**: the sender gets no bounce. This cannot be undone. |

There are two ways to choose which messages an action reaches:

- **Selected messages.** Tick rows (or the header box for the whole page) and use the
  buttons above the table, or use a single row's **⋯** menu.
- **Everything matching.** With nothing ticked, **Act on all matching** (or **Act on the
  whole queue** when no filter is set) applies the action to every message the current
  search and queue selection match. This includes messages beyond the ones listed on the
  page. It is the tool for a spam run: search for the sender, then hold or delete
  everything it queued.

Delete always asks for confirmation, and so does any action on "everything matching". The
server applies the filter again when you confirm. So the count can differ from the one the
dialog showed: messages that arrived in the meantime are included, and messages that were
delivered are not.

When the action finishes, a notice reports how many messages it reached. It also reports
how many it skipped (for example, retrying a held message), and how many were no longer in
the queue (delivered or removed between your last refresh and your click).

### Stopping a spam run

1. Click the sender at the top of **Who is filling it**. The queue now shows only mail from
   that exact address.
2. Choose **Act on all matching → Hold**. Nothing more from that sender leaves the server
   while you investigate, and nothing is lost if it turns out to be legitimate.
3. Open one of the messages and read its headers to find the script or mailbox that sent
   it. Fix the cause: change the mailbox password, or remove or patch the form.
4. Delete the held messages with **Act on all matching → Delete**. Release them instead if
   they turn out to be real mail.

## Limits

- The table lists the **newest 500** messages that match. When more match, a note under
  the table says so. Actions on "everything matching" still reach all of them.
- Each message lists its first 20 recipients. The recipient count is always the real one. A
  message with so many recipients that listing them would be unreasonable shows only the
  count, but it can still be held, released or deleted like any other.
- Retrying a selection is done one message at a time. When more than 1,000 messages are
  selected, or every deferred message is, the panel flushes the whole deferred queue
  instead. Retrying a message early does no harm.
- If Postfix reports a queued message the panel cannot read, a notice above the table gives
  the count. Those messages are not included in any of the numbers.

The queue keeps no history: once a message has been delivered, bounced or deleted, it is
no longer listed on this tab. **Track delivery** finds it in the mail log. Each row's **⋯**
menu has a **Track delivery** item that opens that tab already searching for the message's
queue ID.

## Track delivery

The **Track delivery** tab reads the mail log (`/var/log/maillog` and its weekly rotations)
and rebuilds every message from the lines Postfix wrote about it. Each line is matched to
its message by queue ID. Nothing is stored: every search reads the log again. The answer
reaches back as far as the server keeps its logs, which is four weeks on a default install.

![The Track delivery tab. A search box for address, queue ID, Message-ID, user or IP sits next to a range picker set to 24 hours. Tiles count the messages found: 98 in all, 29 delivered, 47 deferred, 1 bounced, 17 rejected, 1 held and 3 in the queue. A line under the tiles says how far back the logs go and how much was read. The table lists each message with when it was received and a status badge; the sender, the first recipient, the queue ID and how it arrived; and the outcome. A relay attempt from send@your-server.de to a Yahoo address is Rejected with "554 5.7.1 … Relay access denied" and marked "not queued" with the client IP. Messages from wordpress@vantalabs.dev, submitted by uid 1003, are In the queue. A message from billing@stripe.com is Delivered with "250 2.0.0 <info@corepanel.io> Saved", and one sent via the authenticated mailbox office@east-region.cloud is Delivered with "250 2.0.0 Ok: queued as …".](https://www.corepanel.net/_astro/mail-queue-track-dark.B2gT9wDf.png)

### Searching

Type any of these in the search box:

- **An address.** Any part of it matches: the sender, any recipient, or the address a
  message was originally sent to before an alias or forward rewrote it.
- **A mailbox user or an IP address.** Mail sent through a mail client is listed under the
  mailbox that authenticated. Mail received from another server is listed under that
  server's name and IP.
- **A queue ID or a Message-ID.** These must match exactly. A Message-ID can be pasted with
  or without its angle brackets. It is what to ask a customer for: their mail client shows
  it in the message source.

The range picker limits the search to the **last hour**, **24 hours**, **7 days**, or **all
logs**. A message is included when anything happened to it inside the range. A message
received three days ago and delivered an hour ago therefore appears under "last hour".

The tiles count the messages found by status, and clicking one shows only that status.
The line under the tiles says how far back this server's logs go. Nothing older can be
found, and an empty result for an older date means the log is gone, not that the mail was
never sent.

### What each status means

| Status | What happened |
|---|---|
| **Delivered** | The receiving server or the local mailbox accepted it. The response shows what it answered, often with its own queue ID. |
| **Deferred** | The last attempt failed temporarily. Postfix keeps trying, and the message is still in the queue. |
| **Bounced** | It was refused for good and the sender was told. **Bounce sent** in the details links to that notification. |
| **Expired** | It was still deferred when Postfix gave up after five days, and was returned to the sender. |
| **Rejected** | It was refused while it was being received: a relay attempt, a spam filter (rspamd greylisting answers `4.7.1 Try again later`), or a header check. It was never queued, and a message refused at the first recipient has no queue ID at all. |
| **Discarded** | A rule accepted it and dropped it silently. |
| **Held** | It is in the hold queue. |
| **Deleted** | An administrator deleted it from the queue. |
| **In the queue** | It was received and nothing has been logged about it since. |

A message with several recipients takes the status of the one that needs attention most:
a bounce comes before a deferral, and a deferral before a delivery. Each recipient's own
status is in the details.

### A message's details

Click a row to open it. The dialog shows:

- **Origin**: how the message reached the server. It may have come from a mail client
  ("authenticated as" the mailbox, with its IP), or from another server ("received by
  SMTP from" its name and IP). Or it may have been **submitted on this server by uid N**.
  That means a PHP script, a cron job or `sendmail`, run as the Linux user of the account
  with that ID.
- **Recipients**: each one with its status and DSN code (`2.0.0` delivered, `4.x.x`
  temporary, `5.x.x` permanent). It also shows where the last attempt went, what the other
  side said word for word, and how many attempts were made.
- **Log lines**: the Postfix lines about the message, oldest first. When a message has more
  than 40, the first and last 20 are kept.

When the message may still be queued (deferred, held or in the queue), **Find in the
queue** switches to the Queue tab with its queue ID in the search box.

### Answering "my mail never arrived"

1. Search for the recipient's address and pick a range that covers when it was sent.
2. **Delivered** with a response such as `250 2.0.0 Ok: queued as …` means the receiving
   server took it. From there it is that server's responsibility: ask the recipient to look
   in their spam folder, and quote the response, which names the message on their side.
3. **Deferred** or **Bounced**: the response says why. Read it as described in
   [Reading a message](#reading-a-message).
4. **Rejected** on incoming mail: this server refused it, and the reason says which check
   did.
5. Nothing found: the message never reached this server. Check the address the sender
   used, or ask for the Message-ID and search for that.

### Limits

- One search reads at most **1 GiB** of log, newest first. When the range reaches back
  further than that, a notice says older messages were left out. Searching for an address
  over a shorter range avoids it.
- Each search returns the **newest 200** messages that match. A note under the table says
  when more matched.
- Each message lists its first 50 recipients, with the real count beside them.
- A message received before the oldest line read shows a notice that how it arrived is
  not known.
- A search has 50 seconds. On a very busy server, a range of all logs may not finish in
  that time. Pick a shorter range or search for an address.
- The mail log is written through syslog, and any program on the server can write a line
  to it that looks like Postfix's, including a script run by an account. Track delivery
  reads what is in the log. When an answer matters, for example before acting against an
  account, check it against the queue and the message headers.
