When a mail server stops delivering, the answer is almost always written in its log: every message Postfix handles leaves a trail with a queue ID, the remote server it talked to, and the exact SMTP reply it got back. In this tutorial you will read those logs on Ubuntu 24.04 to find out why outgoing mail is deferred or bounced, why incoming mail never arrives, and how to fix the most common causes.

Prerequisites

To follow this tutorial you need:

  • A server running Ubuntu 24.04 LTS with Postfix installed and configured, for example a CubePath VPS.
  • A non-root user with sudo privileges.
  • A domain whose MX record points to the server. This guide uses your_domain, the hostname mail.your_domain and the IP 203.0.113.10; replace them with your own values.
  • An external mailbox (Gmail, Outlook or similar) to send test messages to and from.

The commands target Postfix, the default MTA on Ubuntu and Debian. Exim and Sendmail log similar information in different formats.

Step 1 - Checking that Postfix is running and listening

Start by ruling out the obvious. On Ubuntu, Postfix runs as the postfix@- systemd instance:

sudo systemctl status postfix@-
● [email protected] - Postfix Mail Transport Agent (instance -)
     Loaded: loaded (/usr/lib/systemd/system/[email protected]; enabled-runtime; preset: enabled)
     Active: active (running) since Fri 2026-09-25 09:58:12 UTC; 2h ago

Run Postfix's own consistency check. It prints nothing when the configuration and file permissions are correct:

sudo postfix check

Then confirm that Postfix listens on port 25 on all interfaces, not only on localhost:

sudo ss -ltnp | grep ':25 '
LISTEN 0      100          0.0.0.0:25        0.0.0.0:*    users:(("master",pid=1234,fd=13))
LISTEN 0      100             [::]:25           [::]:*    users:(("master",pid=1234,fd=14))

If you only see 127.0.0.1:25, the server cannot receive mail from the Internet. Check inet_interfaces, which should be all on a server that receives mail:

postconf inet_interfaces
inet_interfaces = all

Step 2 - Finding the mail logs

On Ubuntu 24.04, rsyslog writes all mail activity to /var/log/mail.log. Follow it live while you reproduce the problem:

sudo tail -f /var/log/mail.log

The same entries are also in the systemd journal, which is useful if rsyslog is not installed:

sudo journalctl -u postfix@- --since "1 hour ago"

On RHEL-family systems the file is /var/log/maillog.

Step 3 - Following one message through the log

Postfix assigns every message a queue ID and prints it on each line that concerns that message. Once you have the ID, you can reconstruct the whole delivery. Send a test message from the server to your external mailbox:

printf 'Subject: Postfix test\n\nTest message from mail.your_domain\n' | sendmail -f admin@your_domain [email protected]

Find the most recent delivery attempt for that recipient:

sudo grep 'to=<[email protected]>' /var/log/mail.log | tail -n 1
2026-09-25T10:12:02.418305+00:00 mail postfix/smtp[23145]: 4B7F21A0C3: to=<[email protected]>, relay=mx.example.net[198.51.100.20]:25, delay=1.2, delays=0.05/0.01/0.62/0.52, dsn=2.0.0, status=sent (250 2.0.0 OK 1727259122 queued)

Then pull every line for that queue ID:

sudo grep 4B7F21A0C3 /var/log/mail.log
... postfix/pickup[22901]: 4B7F21A0C3: uid=1000 from=<admin@your_domain>
... postfix/cleanup[23140]: 4B7F21A0C3: message-id=<[email protected]_domain>
... postfix/qmgr[1240]: 4B7F21A0C3: from=<admin@your_domain>, size=412, nrcpt=1 (queue active)
... postfix/smtp[23145]: 4B7F21A0C3: to=<[email protected]>, relay=mx.example.net[198.51.100.20]:25, ... status=sent (250 2.0.0 OK)
... postfix/qmgr[1240]: 4B7F21A0C3: removed

The fields on the delivery line tell you what happened:

  • relay: the server Postfix delivered to. relay=none means it never managed to connect.
  • status: sent (accepted by the next server), deferred (temporary failure, Postfix will retry), or bounced (permanent failure, a bounce was sent to the sender).
  • dsn: the enhanced status code. 2.x.x is success, 4.x.x temporary, 5.x.x permanent.
  • delays: four numbers in seconds: time before the queue manager, time in the queue manager, connection setup (DNS, TCP, TLS, HELO), and message transmission. A large third value points to network or DNS trouble, not to Postfix.
  • The text in parentheses: the remote server's reply or Postfix's own error. This is the most important part.

For incoming mail the same technique works: grep for to=<user@your_domain> and look for postfix/lmtp, postfix/local or postfix/virtual lines with status=sent.

Step 4 - Getting an overview of failures

When many messages are affected, count the outcomes to see the scale of the problem:

sudo grep -oP 'status=\K\w+' /var/log/mail.log | sort | uniq -c
    812 bounced
   1903 deferred
   4521 sent

Group the deferral reasons to find the dominant one:

sudo grep 'status=deferred' /var/log/mail.log | grep -oP 'status=deferred \(\K.*(?=\)$)' | sort | uniq -c | sort -rn | head
   1650 connect to mx.example.net[198.51.100.20]:25: Connection timed out
    190 host mx.example.org[192.0.2.44] said: 451 4.7.1 Greylisted, please try again later (in reply to RCPT TO command)

Messages that were rejected before they even got a queue ID are logged with NOQUEUE. These are usually incoming connections that Postfix refused:

sudo grep 'NOQUEUE: reject' /var/log/mail.log | tail -n 5

For daily summaries, install pflogsumm, which parses the log into totals, top senders and recipients, and lists of deferrals and bounces:

sudo apt install pflogsumm
sudo pflogsumm -d today /var/log/mail.log | less

Step 5 - Working with the mail queue

Deferred messages wait in the queue and Postfix retries them automatically with increasing intervals. List the queue with the reason for each deferral:

sudo postqueue -p
-Queue ID-  --Size-- ----Arrival Time---- -Sender/Recipient-------
9C2D41A0F7      1204 Fri Sep 25 10:40:11  admin@your_domain
(connect to mx.example.net[198.51.100.20]:25: Connection timed out)
                                         [email protected]

-- 1 Kbytes in 1 Request.

Inspect a queued message, including headers, with postcat:

sudo postcat -vq 9C2D41A0F7 | less

After you fix the cause, ask Postfix to retry everything immediately instead of waiting for the next scheduled attempt:

sudo postqueue -f

To retry a single message, use sudo postqueue -i 9C2D41A0F7. To delete one message, use sudo postsuper -d 9C2D41A0F7. If the queue is full of spam from a compromised account, delete the whole deferred queue only after you have found and stopped the source:

sudo postsuper -d ALL deferred

Step 6 - Diagnosing outgoing mail failures

Match the reason in the log with these common causes.

Connection timed out to port 25

connect to mx.example.net[198.51.100.20]:25: Connection timed out

If every destination times out, outbound port 25 is blocked, either by a local firewall or by your provider. Many cloud providers block outbound SMTP on new accounts to prevent spam. Test a known mail server directly:

nc -vz -w 5 gmail-smtp-in.l.google.com 25
Connection to gmail-smtp-in.l.google.com (142.250.27.26) 25 port [tcp/smtp] succeeded!

If this times out, contact your provider to have outbound port 25 enabled, or send through an authenticated relay (smarthost) on port 587 by setting relayhost in /etc/postfix/main.cf.

Rejected for authentication or reputation

Large providers explain their rejections in the reply text. Typical examples:

550-5.7.26 This mail has been blocked because the sender is unauthenticated.
550-5.7.25 The IP address sending this message does not have a PTR record setup

Check your SPF, DKIM and DMARC records and the server's reverse DNS:

dig your_domain TXT +short | grep spf1
dig _dmarc.your_domain TXT +short
dig -x 203.0.113.10 +short

The PTR should return mail.your_domain., and that name should resolve back to 203.0.113.10. The hostname Postfix announces in HELO should match it:

postconf myhostname
myhostname = mail.your_domain

If your IP is on a blocklist, the rejection usually names it (for example blocked using zen.spamhaus.org). Follow the delisting link in the message after fixing the cause, such as an open relay or a compromised account.

Relay access denied

NOQUEUE: reject: RCPT from unknown[198.51.100.50]: 554 5.7.1 <[email protected]>: Relay access denied

A client tried to send to an external domain without authenticating, and its IP is not in mynetworks. This is Postfix working correctly. If the client is a legitimate application or mail client, configure it to authenticate with SMTP AUTH on the submission port (587) instead of adding its IP to mynetworks.

Authentication failures

warning: unknown[198.51.100.50]: SASL LOGIN authentication failed: UGFzc3dvcmQ6

Occasional failures from random IPs are password-guessing bots. A burst for one of your users means a wrong password in their client. If failures continue from the same IPs, a tool such as Fail2ban with its postfix-sasl jail can block them.

Step 7 - Diagnosing incoming mail failures

If external senders get bounces or their messages never show up in the log at all, the connection never reached Postfix. Check the MX record first:

dig your_domain MX +short
dig mail.your_domain A +short
10 mail.your_domain.
203.0.113.10

The MX must point to a hostname (never directly to an IP) that resolves to your server. Next, make sure the firewall allows SMTP. Ubuntu's Postfix package ships a UFW application profile:

sudo ufw allow Postfix
sudo ufw status

From a different machine, confirm that port 25 answers with your server's banner:

nc -v mail.your_domain 25
Connection to mail.your_domain (203.0.113.10) 25 port [tcp/smtp] succeeded!
220 mail.your_domain ESMTP Postfix (Ubuntu)

Type QUIT to close the session. If you have swaks installed on that machine, it runs a full SMTP transaction and shows each step:

swaks --to user@your_domain --server mail.your_domain

If the connection works but the message is rejected, look for NOQUEUE: reject lines with the sender's address. Two frequent causes:

  • 550 5.1.1 <user@your_domain>: Recipient address rejected: User unknown means the mailbox does not exist in the local or virtual mailbox maps.
  • mail for your_domain loops back to myself means the domain is missing from mydestination (for local users) or from your virtual domains, so Postfix tries to relay the mail to itself.

Step 8 - Checking resources

A full disk stops mail flow completely. Postfix then rejects new mail with a temporary error:

NOQUEUE: reject: MAIL from unknown[198.51.100.50]: 452 4.3.1 Insufficient system storage

Check free space and inodes on the partition that holds /var/spool/postfix, and the size of the queue itself:

df -h /var/spool/postfix
df -i /var/spool/postfix
sudo du -sh /var/spool/postfix/deferred

A deferred queue with thousands of messages is usually outgoing spam. Find the top senders in the queue before deleting anything:

sudo postqueue -j | grep -oP '"sender": *"\K[^"]*' | sort | uniq -c | sort -rn | head

Troubleshooting

  • fatal: open database /etc/postfix/sasl_passwd.db: No such file or directory: a lookup table was edited but not compiled. Run sudo postmap /etc/postfix/sasl_passwd (use the path from the error) and sudo systemctl reload postfix.
  • Changes to main.cf have no effect: run sudo postfix check, then sudo systemctl reload postfix, and confirm the value with postconf parameter_name. Use postconf -n to list only the settings you changed from the defaults.
  • You need more detail for one remote host: add debug_peer_list = example.net to /etc/postfix/main.cf and reload. Postfix logs the full SMTP conversation for that host. Remove the setting when you are done, because it is very verbose.

Conclusion

You traced messages by queue ID, grouped failures by their SMTP reply, managed the queue, and checked the network, DNS and resource issues behind most delivery problems. The reply text in parentheses on each status= line is almost always the key to the fix. As next steps, set up SPF, DKIM and DMARC if any are missing, and schedule a daily pflogsumm report so you notice rising deferrals before users do.