--- title: "How to Analyze Postfix and Dovecot Mail Logs on Ubuntu" description: "Read and search Postfix and Dovecot logs on Ubuntu 24.04: trace a message by queue ID, find bounces and login failures, and get a daily report with pflogsumm." category: "Email Server" language: en source: https://cubepath.com/docs/email-server/email-logs-analysis-and-diagnostics updated: 2026-09-25 --- # How to Analyze Postfix and Dovecot Mail Logs on Ubuntu The mail log is the first place to look when a message goes missing, a user cannot log in or someone is abusing your server. Postfix and Dovecot record every connection, delivery attempt and login, and with a few `grep` patterns you can answer most questions in seconds. In this tutorial you will learn where the logs live on Ubuntu 24.04, how to read a Postfix log line, how to trace a single message, how to find bounces, deferrals and authentication failures, and how to get a daily summary with `pflogsumm`. ## Prerequisites To follow this guide you need: - A mail server running Postfix and Dovecot on Ubuntu 24.04 (Debian 12 works the same), for example a CubePath VPS. - A non-root user with `sudo` privileges. The mail log is readable only by root and the `adm` group. - Some mail traffic in the logs, so the commands return results. ## Step 1 - Finding the log files On Ubuntu, Postfix and Dovecot send their messages to syslog with the `mail` facility, and rsyslog writes them to `/var/log/mail.log`. List the current and rotated files: ```bash ls -lh /var/log/mail.log* ``` ```output -rw-r----- 1 syslog adm 2.1M Sep 25 10:02 /var/log/mail.log -rw-r----- 1 syslog adm 5.8M Sep 21 00:00 /var/log/mail.log.1 -rw-r----- 1 syslog adm 612K Sep 14 00:00 /var/log/mail.log.2.gz -rw-r----- 1 syslog adm 598K Sep 7 00:00 /var/log/mail.log.3.gz ``` The most recent rotated file stays uncompressed and older ones are gzipped. To read the logs without `sudo`, add your user to the `adm` group and open a new session: ```bash sudo usermod -aG adm $USER ``` The same messages are also in the systemd journal. That is useful for time ranges, because `journalctl` understands dates directly. Postfix processes run under the `postfix@-` unit on Ubuntu: ```bash sudo journalctl -u postfix@- --since "1 hour ago" sudo journalctl -u dovecot --since today ``` If `/var/log/mail.log` does not exist, rsyslog is not installed. Install it with `sudo apt install rsyslog` or work only with `journalctl`. ## Step 2 - Understanding a Postfix log line Every message Postfix handles receives a queue ID, and each Postfix process that touches the message logs a line with that ID. A normal outbound delivery looks like this: ```output 2026-09-25T09:41:12.318201+00:00 mail postfix/submission/smtpd[20114]: 9A1F2B3C4D: client=unknown[198.51.100.7], sasl_method=LOGIN, sasl_username=user@example.com 2026-09-25T09:41:12.360044+00:00 mail postfix/cleanup[20118]: 9A1F2B3C4D: message-id=<20260925094112.1234@example.com> 2026-09-25T09:41:12.402117+00:00 mail postfix/qmgr[1402]: 9A1F2B3C4D: from=, size=1523, nrcpt=1 (queue active) 2026-09-25T09:41:13.771954+00:00 mail postfix/smtp[20120]: 9A1F2B3C4D: to=, relay=gmail-smtp-in.l.google.com[142.250.27.26]:25, delay=1.5, delays=0.08/0.01/0.62/0.78, dsn=2.0.0, status=sent (250 2.0.0 OK) 2026-09-25T09:41:13.772512+00:00 mail postfix/qmgr[1402]: 9A1F2B3C4D: removed ``` Each line contains a timestamp, the hostname, the Postfix process with its PID, the queue ID and the details. Ubuntu 24.04 uses RFC 3339 timestamps; older releases use the `Sep 25 09:41:12` format, so the commands in this guide avoid relying on field positions. The processes tell the story of the message: | Process | What it logs | |---|---| | `smtpd` | Incoming SMTP connection, client IP, SASL user, rejections (`NOQUEUE: reject`) | | `cleanup` | Message-ID of the accepted message | | `qmgr` | Sender, size and number of recipients; `removed` when finished | | `smtp` | Delivery to a remote server | | `lmtp` or `local` / `virtual` | Delivery to a local mailbox | The important fields in the delivery line are: - `status`: `sent` (accepted by the next server), `deferred` (temporary failure, Postfix will retry), `bounced` (permanent failure, a bounce was sent to the sender). - `dsn`: the delivery status code. `2.x.x` is success, `4.x.x` temporary, `5.x.x` permanent. - `delays=a/b/c/d`: seconds spent before the queue manager, in the queue manager, setting up the connection, and transmitting. A large third value points to DNS or network problems at the receiving side. - The text in parentheses at the end: the exact reply from the remote server, which usually explains a failure. ## Step 3 - Tracing a single message Users typically report "my message to X never arrived". Start by finding the queue IDs of messages to that recipient. This prints the ID of every delivery attempt to `alice@example.net`: ```bash sudo grep -oP '[0-9A-F]{6,}(?=: to=)' /var/log/mail.log | sort -u ``` ```output 3B7C90A1E2 9A1F2B3C4D ``` Then print every line for one of those IDs to see the full life of the message: ```bash sudo grep 9A1F2B3C4D /var/log/mail.log ``` If the message is older, search the rotated files as well. `zgrep` reads plain and gzipped files alike: ```bash sudo zgrep 9A1F2B3C4D /var/log/mail.log* ``` When the sender gives you the Message-ID from their mail client, search for it instead. It is logged by `cleanup` together with the queue ID: ```bash sudo grep 'message-id=<20260925094112.1234@example.com>' /var/log/mail.log ``` Note that a message passing through a content filter (such as Amavis or rspamd in proxy mode) gets a new queue ID when it is re-injected. Follow the `queued as` text in the delivery line to the next ID. ## Step 4 - Finding bounced and deferred mail List permanent failures with the remote server's explanation: ```bash sudo grep 'status=bounced' /var/log/mail.log | tail -n 20 ``` ```output 2026-09-25T08:12:40.118822+00:00 mail postfix/smtp[18833]: 5D2E71A0C4: to=, relay=mx.example.org[192.0.2.25]:25, delay=0.9, delays=0.05/0/0.4/0.45, dsn=5.1.1, status=bounced (host mx.example.org[192.0.2.25] said: 550 5.1.1 : Recipient address rejected: User unknown (in reply to RCPT TO command)) ``` Count bounces by status code to see which kind of failure dominates: ```bash sudo grep 'status=bounced' /var/log/mail.log | grep -oP 'dsn=\K[0-9.]+' | sort | uniq -c | sort -rn ``` ```output 14 5.1.1 3 5.7.1 1 5.4.4 ``` `5.1.1` means the mailbox does not exist, `5.7.1` is a policy rejection (often SPF, DKIM, reputation or a blocklist) and `5.4.4` means the domain has no valid MX. Deferred messages are the ones currently stuck. Group them by recipient domain to see whether one provider is the problem: ```bash sudo grep 'status=deferred' /var/log/mail.log | grep -oP 'to=<[^@]+@\K[^>]+' | sort | uniq -c | sort -rn | head ``` ```output 42 outlook.com 3 example.org ``` Then read the reason for that domain: ```bash sudo grep 'status=deferred' /var/log/mail.log | grep 'outlook.com' | tail -n 3 ``` A reason like `Connection timed out` to every domain means outbound port 25 is blocked; a reply like `451 4.7.650 ... temporarily rate limited due to IP reputation` means the receiving provider is throttling your IP. ## Step 5 - Finding rejected connections When Postfix refuses a message during the SMTP conversation, it logs a `NOQUEUE: reject` line; no queue ID is assigned because the message was never accepted: ```bash sudo grep 'NOQUEUE: reject' /var/log/mail.log | tail -n 5 ``` ```output 2026-09-25T09:58:02.556180+00:00 mail postfix/smtpd[20511]: NOQUEUE: reject: RCPT from unknown[192.0.2.77]: 554 5.7.1 : Relay access denied; from= to= proto=ESMTP helo= ``` Summarize rejections by SMTP code: ```bash sudo grep -oP 'NOQUEUE: reject: RCPT from \S+ \K[45]\d\d [45]\.\d+\.\d+' /var/log/mail.log | sort | uniq -c | sort -rn ``` ```output 118 554 5.7.1 37 450 4.7.1 9 550 5.1.1 ``` Relay denials from random IPs are normal internet noise. If a legitimate sender reports being rejected, search for their IP or address to read the exact reason. ## Step 6 - Finding authentication failures Failed SMTP logins are logged by Postfix as SASL warnings: ```bash sudo grep 'SASL .* authentication failed' /var/log/mail.log | tail -n 3 ``` ```output 2026-09-25T10:01:44.902113+00:00 mail postfix/submission/smtpd[20702]: warning: unknown[198.51.100.200]: SASL LOGIN authentication failed: UGFzc3dvcmQ6 ``` The base64 string at the end is not the password; it decodes to `Password:`, the server's prompt. Count failures per source IP to spot brute force attempts: ```bash sudo grep 'SASL .* authentication failed' /var/log/mail.log | grep -oP 'warning: \S+\[\K[0-9a-f.:]+' | sort | uniq -c | sort -rn | head ``` ```output 512 198.51.100.200 37 203.0.113.99 2 192.0.2.14 ``` Hundreds of failures from a single IP is a password-guessing attack. Block it with a firewall rule or, better, set up Fail2ban with the `postfix-sasl` jail. Dovecot logs failed IMAP and POP3 logins when the client disconnects. The exact wording differs slightly between Dovecot versions, but it always contains `auth failed`: ```bash sudo grep 'auth failed' /var/log/mail.log | grep dovecot | tail -n 3 ``` ```output 2026-09-25T10:03:10.004511+00:00 mail dovecot: imap-login: Login aborted: Connection closed (auth failed, 1 attempts in 2 secs) (auth_failed): user=, method=PLAIN, rip=203.0.113.99, lip=203.0.113.10, TLS, session= ``` And successful logins, which are useful to confirm when a user last connected and from where: ```bash sudo grep 'Login: user=' /var/log/mail.log | tail -n 5 ``` A single user failing repeatedly from their usual IP usually has an old password saved on a phone or a second device. ## Step 7 - Measuring volume and delays Count deliveries by status in the current log file: ```bash sudo grep -oP 'status=\K\w+' /var/log/mail.log | sort | uniq -c ``` ```output 1893 sent 42 deferred 18 bounced ``` This includes local deliveries to mailboxes, not only outbound mail. To see who sends the most messages through the server, which quickly reveals a compromised account sending spam: ```bash sudo grep -oP 'qmgr\[\d+\]: [0-9A-F]+: from=<\K[^>]+' /var/log/mail.log | sort | uniq -c | sort -rn | head ``` Calculate the average and maximum delivery delay of successful deliveries: ```bash sudo grep 'status=sent' /var/log/mail.log | grep -oP ', delay=\K[0-9.]+' | awk '{ s += $1; if ($1 > m) m = $1 } END { if (NR) printf "messages=%d avg=%.2fs max=%.2fs\n", NR, s/NR, m }' ``` ```output messages=1893 avg=0.84s max=312.40s ``` A high maximum on its own is normal (a message that was deferred and retried). A high average points to slow DNS or a slow content filter. ## Step 8 - Getting a daily report with pflogsumm Rather than writing your own reporting script, use `pflogsumm`, which is packaged in Ubuntu and summarizes volume, bounces, rejections, top senders and recipients: ```bash sudo apt install pflogsumm ``` `pflogsumm` expects classic syslog timestamps (`Sep 25 09:41:12`), while Ubuntu 24.04 writes RFC 3339 timestamps to `/var/log/mail.log`. The reliable way to feed it is the journal, whose default `short` output uses the classic format. Generate a report for today: ```bash sudo journalctl -u postfix@- --since today -o short --no-pager | pflogsumm ``` ```output Grand Totals ------------ messages 1204 received 1893 delivered 42 deferred (118 deferrals) 18 bounced 164 rejected (8%) ... ``` To receive yesterday's summary by email every morning, create a cron file: ```bash sudo nano /etc/cron.d/pflogsumm ``` ```text 15 6 * * * root { echo 'Subject: Postfix daily report'; echo; journalctl -u postfix@- --since yesterday --until today -o short --no-pager | /usr/sbin/pflogsumm; } | /usr/sbin/sendmail postmaster@example.com ``` Replace `postmaster@example.com` with your address. The first `echo` adds a subject header, and `sendmail` here is Postfix's compatible command, so no extra mail client is needed. Because the journal is queried by date, log rotation does not cut the report in half. Test the pipeline once by hand before relying on it: ```bash sudo sh -c '{ echo "Subject: Postfix report test"; echo; journalctl -u postfix@- --since today -o short --no-pager | /usr/sbin/pflogsumm; } | /usr/sbin/sendmail postmaster@example.com' ``` The report should arrive in your mailbox within a minute. If the totals are all zero, check that `journalctl -u postfix@- --since today` prints Postfix lines at all. ## Step 9 - Getting more detail when you need it When the normal logs do not explain a problem, raise verbosity temporarily. For Dovecot authentication issues, edit the logging configuration: ```bash sudo nano /etc/dovecot/conf.d/10-logging.conf ``` ```ini auth_verbose = yes auth_debug = yes ``` Reload Dovecot and repeat the failing login: ```bash sudo systemctl reload dovecot ``` For Postfix, enable debug logging only for the client IP you are investigating, so the log does not explode: ```bash sudo postconf -e 'debug_peer_list = 198.51.100.7' sudo systemctl reload postfix ``` > Important: Turn debugging off as soon as you are done (`sudo postconf -e 'debug_peer_list ='` and set the Dovecot options back to `no`). `auth_debug` logs details of every login attempt and debug output grows very fast. ## Step 10 - Adjusting log retention On Ubuntu, `/var/log/mail.log` is rotated by the rsyslog logrotate policy in `/etc/logrotate.d/rsyslog`: weekly, keeping four old files. If you need a longer history, for example for abuse investigations, change `rotate` for the mail files. Open the file: ```bash sudo nano /etc/logrotate.d/rsyslog ``` The mail logs share a block with other files. Increasing `rotate 4` to `rotate 12` keeps about three months of history. Check the result without rotating anything: ```bash sudo logrotate -d /etc/logrotate.d/rsyslog ``` Mail logs contain email addresses and IP addresses, which are personal data under the GDPR. Keep them only as long as you actually need them and do not make them readable to more users than necessary. ## Conclusion You now know where Postfix and Dovecot log on Ubuntu 24.04, how to read a delivery line, how to trace a message by queue ID and how to find bounces, deferrals, rejections and login attacks with a handful of `grep` patterns. `pflogsumm` gives you a daily overview without maintaining your own scripts. As next steps, you can: - Protect SMTP and IMAP logins with Fail2ban using the `postfix-sasl` and `dovecot` jails. - Ship the logs to a central system such as Loki or Graylog if you run more than one mail server. - Review the testing and troubleshooting guide to check DNS, TLS and authentication when the logs point to a configuration problem.