Tracing Dovecot IMAP/POP Failures on DirectAdmin and Keeping 90-Day Logs
In Part 1, I traced exim mainlog to find devices with incorrect passwords on the LAN. After publishing it, more questions came in — where to check IMAP/POP failures, why DirectAdmin logs disappear within days, and how to keep a full 90 days. I wrote this follow-up to cover the whole process.
In Part 1, I described tracing exim mainlog to find a machine on the LAN that kept using an incorrect password, causing LFD to ban the entire subnet. After the article went up, several questions followed, mostly around three things — which log to check for IMAP/POP when "fetching mail," why DirectAdmin logs disappear before there is time to investigate, and where to make changes to keep them for 90 days.
I am covering the rest in this installment, focusing on the stack DirectAdmin actually uses: exim for SMTP, dovecot for IMAP/POP, and LFD/CSF for intrusion protection. If your machine uses postfix instead of DA's stack, the path differs (it is /var/log/maillog instead), but the overall patterns are similar and easy enough to adapt. I have included the adjustments at the end.
Placeholders used in this article
I am using the same placeholders as in Part 1 to avoid exposing real data. Replace them with your own machine's values when using the commands.
example.comis the example customer domain203.0.113.xand<server-ip>are public IPs (remote and server sides)192.168.1.xis an internal LAN IP (RFC1918)[email protected]is the example mail account
Mail log paths on DirectAdmin
The most common mistake is looking for logs in the wrong place. General tutorials usually point to /var/log/exim4/mainlog or /var/log/maillog, but DirectAdmin uses a different layout (I checked this on an actual DA-Debian machine). Here is the actual layout.
More detail on each file
/var/log/exim/mainlog— exim SMTP logs (the ones I covered in Part 1)/var/log/exim/rejectlog— connections rejected before the data phase/var/log/mail.log— dovecot IMAP/POP logs written through rsyslog; this is the main focus of this installment/var/log/dovecot-lmtp.log— LMTP delivery when exim delivers mail to dovecot mailboxes/var/log/lfd.log— CSF/LFD events
These files normally have root:root or root:adm permissions, meaning only root can read them.
Every command in this article must run as root or with sudo. Running as a regular user will give you Permission denied as soon as you try to grep the log files.
Start by checking that all the logs I will use are present.
ls -la /var/log/exim/mainlog \
/var/log/mail.log \
/var/log/dovecot-lmtp.log \
/var/log/lfd.log
Dovecot IMAP / POP failure patterns
An office machine that keeps using an incorrect password normally fails on both sides — SMTP when sending mail (covered in Part 1) and IMAP/POP when fetching mail (covered here) — because the mail client uses the same password to send and receive. Checking both sides together makes the picture much clearer.
What many people do not realize is that POP3 failures often outnumber SMTP failures several times over. The reason is simple — mail clients already poll the inbox every 1 to 5 minutes, and each poll with an incorrect password counts as one failure. SMTP failures happen only when the user clicks Send, so their frequency is very different. This becomes an important clue in the next section.
What a successful login looks like in the log (IMAP)
May 25 10:05:38 mail dovecot: imap-login: Login: user=<[email protected]>, method=PLAIN, rip=203.0.113.x, lip=<server-ip>, mpid=12345, TLS, session=<aBcDefGhIj>
What a failed login looks like in the log (IMAP)
May 25 08:07:19 mail dovecot: imap-login: Disconnected (auth failed, 1 attempts in 5 secs): user=<[email protected]>, method=PLAIN, rip=203.0.113.x, lip=<server-ip>, TLS, session=<aBcDefGhIj>
POP3 uses exactly the same pattern; only imap-login changes to pop3-login.
Find the accounts with the most IMAP failures today.
TODAY=$(date "+%b %e" | sed 's/ / /') # syslog format "May 25" (ระวัง double-space ถ้าวันที่ < 10)
LOG=/var/log/mail.log
grep "^$TODAY " $LOG \
| grep 'imap-login: Disconnected (auth failed' \
| grep -oE 'user=<[^>]+>' | sort | uniq -c | sort -rn | head
syslog writes the date as "May 5" (with two spaces) when the day is a single digit. The sed command above therefore needs to collapse double spaces into a single space. Skip this step and grep will find no matches on days 1 to 9 of the month.
Find the IPs with the most IMAP failures today.
grep "^$TODAY " $LOG \
| grep 'imap-login: Disconnected (auth failed' \
| grep -oE 'rip=[0-9.]+' | sed 's/rip=//' | sort | uniq -c | sort -rn | head
Count today's combined IMAP and POP3 failures for one account.
[email protected]
grep "^$TODAY " /var/log/mail.log \
| grep -E '(imap-login|pop3-login): Disconnected \(auth failed' \
| grep -c "user=<$ACCT>"
Cross-protocol check — distinguish a stuck client from an attacker
This is the check I use most often in practice, because it determines whether a case involves "an office machine with an incorrect saved password" or "an external bot trying to guess passwords." These require completely different responses.
The principle is to compare failure counts across protocols for the same account.
[email protected]
echo "-- SMTP (exim) fail --"
grep "set_id=$ACCT" /var/log/exim/mainlog | grep -c 'authenticator failed'
echo "-- IMAP fail --"
grep "user=<$ACCT>" /var/log/mail.log | grep -c 'imap-login: Disconnected (auth failed'
echo "-- POP3 fail --"
grep "user=<$ACCT>" /var/log/mail.log | grep -c 'pop3-login: Disconnected (auth failed'
Here is how I have always interpreted the results.
High POP3 : SMTP ratio (10x or more)
- POP3/IMAP failures outnumber SMTP failures several times over
- Repeated attempts from the same IP, on the LAN or from the office
- A desktop client with an incorrect saved password (Outlook / Thunderbird) polling the inbox frequently
- Fix it at the source — update the password in the application
Ratio close to 1:1
- Similar numbers of SMTP and IMAP/POP failures
- Attempts from multiple scattered IPs or foreign IPs
- A password-guessing bot, or someone entering an incorrect password in webmail
- Address it at the perimeter — block IPs, enable brute-force protection, change the password
The key observation is that a stuck client automatically polls the inbox every few minutes, so POP3/IMAP failures climb rapidly while SMTP failures barely move because the user does not send mail very often. An attacker guessing passwords tries each protocol at roughly the same rate, so the counts are similar.
Keep logs for 90 days — adjust DirectAdmin logrotate
This is why so many people find that "I need to look back, but the logs are already gone" — DirectAdmin's default retention is very short. I opened every config and checked: exim and dovecot use weekly + rotate 4, which keeps roughly 28 days, while LFD is worse at rotate 1, keeping only 7 days.
The problem is that in actual investigations, I have had to look back 60 to 80 days to find when the password first became incorrect, because some customers take a month to notice that something is not working. In practice, I therefore aim for at least 90 days to make the logs useful.
Check the current configuration first.
cat /etc/logrotate.d/exim
cat /etc/logrotate.d/dovecot
cat /etc/logrotate.d/lfd
cat /etc/logrotate.d/rsyslog # มี /var/log/mail.log อยู่ในนี้
cat /etc/logrotate.conf | grep -E 'rotate|weekly|daily|compress'
The default exim configuration I found on DA-Debian looks roughly like this.
/var/log/exim/mainlog /var/log/exim/processlog /var/log/exim/rejectlog /var/log/exim/paniclog {
missingok
sharedscripts
}
There is no rotate N, no compress, and no daily, meaning it uses the defaults from /etc/logrotate.conf: weekly + rotate 4, or 28 days, without compression.
Override exim to 90 days + compress
Edit /etc/logrotate.d/exim.
/var/log/exim/mainlog /var/log/exim/processlog /var/log/exim/rejectlog /var/log/exim/paniclog {
daily
rotate 90
compress
delaycompress
missingok
notifempty
sharedscripts
}
Override dovecot
Edit /etc/logrotate.d/dovecot.
/var/log/dovecot*.log {
daily
rotate 90
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
kill -s 0 `cat /var/run/dovecot/master.pid` || kill -s USR1 `cat /var/run/dovecot/master.pid`
endscript
}
Override mail.log (managed by rsyslog)
The /var/log/mail.log file containing dovecot IMAP/POP logs is normally managed in /etc/logrotate.d/rsyslog.
/var/log/mail.log
{
daily
rotate 90
missingok
notifempty
compress
delaycompress
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
Override LFD — the one with a default of just 7 days
This one matters a lot, because DA's default keeps only 7 days, which is too short to investigate any case in time. Edit /etc/logrotate.d/lfd.
/var/log/lfd.log {
daily
rotate 90
compress
delaycompress
missingok
notifempty
}
/var/log/lfd_messenger.log {
daily
rotate 90
compress
delaycompress
missingok
notifempty
}
Dry-run before applying
Do not force a rotation yet; always test with a dry-run first.
logrotate -d /etc/logrotate.d/exim # dry-run ดู debug output ว่าจะทำอะไรบ้าง
logrotate -d /etc/logrotate.d/dovecot
logrotate -d /etc/logrotate.d/lfd
logrotate -d /etc/logrotate.d/rsyslog
If the dry-run reports no errors, the configuration will apply automatically tonight when the daily cron job runs (/etc/cron.daily/logrotate).
There is no need to run logrotate with force immediately, because it will simply rotate over today's cycle. Let the daily cron job handle it tonight. The new configuration will take effect from the next cycle.
Check disk impact before increasing retention
Increasing retention to 90 days means using more disk space, so check that there is enough first.
ls -lh /var/log/exim/mainlog* /var/log/mail.log* /var/log/dovecot* /var/log/lfd* 2>/dev/null
du -sh /var/log
df -h /var
My medium-sized mail server (around 50 domains and 200 mailboxes) uses roughly 3 to 5 GB for 90 days of logs after gzip compression. If your machine has a separate /var partition, check it carefully, because logs filling the partition and causing rsyslog to crash are difficult to recover from.
Set up a postrotate script to copy rotated logs to another disk, such as /backup/maillogs/, and keep only 30 days in /var. This splits retention across disks without losing history.
Query historical rotated logs compressed with gzip
After enabling compress in the previous section, all older files will become .gz files. You can use zgrep directly in place of grep here; it reads both regular and gzip files in a single command.
View an account's IMAP failures across 90 days.
[email protected]
zgrep -h "user=<$ACCT>" /var/log/mail.log* \
| grep -c 'imap-login: Disconnected (auth failed'
View the IPs from which that account successfully logged in over the past 90 days.
zgrep -h "user=<$ACCT>" /var/log/mail.log* \
| grep 'imap-login: Login' \
| grep -oE 'rip=[0-9.]+' | sed 's/rip=//' \
| sort | uniq -c | sort -rn | head -20
A case I encounter very often is a customer insisting, "My device used to work." Looking back through 60 days of logs shows that it really did log in successfully all along, then suddenly started failing on day X. This confirms that the password was changed (often by someone in the office logging into webmail and changing it themselves), rather than the device breaking.
For SMTP (exim), use zgrep in the same way.
zgrep -h "set_id=$ACCT" /var/log/exim/mainlog* | grep -c 'authenticator failed'
More one-liners
This set builds on the commands in Part 1. Keep them handy to paste in when you need to investigate an urgent case.
Top 10 accounts with IMAP failures today
TODAY=$(date "+%b %e" | sed 's/ / /')
grep "^$TODAY " /var/log/mail.log \
| grep 'imap-login: Disconnected (auth failed' \
| grep -oE 'user=<[^>]+>' | sort | uniq -c | sort -rn | head
Top 10 IPs with IMAP failures today
grep "^$TODAY " /var/log/mail.log \
| grep 'imap-login: Disconnected (auth failed' \
| grep -oE 'rip=[0-9.]+' | sed 's/rip=//' | sort | uniq -c | sort -rn | head
Find accounts that logged in successfully within 60 days but have been silent for the last 7 days (possibly no longer in use, or the device is missing).
# success ใน 60 วัน (mainlog + rotated)
zgrep -h 'A=[a-z_]*:' /var/log/exim/mainlog* \
| grep -oE 'A=[a-z_]*:[^ ]+' | sort -u > /home/<user>/all60
# success ใน 7 วันล่าสุด
zgrep -h 'A=[a-z_]*:' /var/log/exim/mainlog{,.[1-7]}* 2>/dev/null \
| grep -oE 'A=[a-z_]*:[^ ]+' | sort -u > /home/<user>/last7
comm -23 /home/<user>/all60 /home/<user>/last7
Count failures across all protocols for 1 account over 90 days.
[email protected]
echo "-- SMTP (exim) --"
zgrep -h "set_id=$ACCT" /var/log/exim/mainlog* | grep -c 'authenticator failed'
echo "-- IMAP+POP (dovecot) --"
zgrep -h "user=<$ACCT>" /var/log/mail.log* | grep -c 'Disconnected (auth failed'
Extended workflow summary
Everything fits together into one sequence as follows.
- Many IMAP/POP failures: check the dovecot pattern in §2
- Unsure whether it is really a stuck client: compare cross-protocol ratios in §3
- Need to look back more than 60 days: configure logrotate for 90 in §4, then use zgrep in §5
- Find inactive or silent accounts: use the last one-liner in §6
For those using postfix instead of exim
If your machine uses postfix instead of DA's exim, the path differs. On CentOS it is /var/log/maillog, while on some Debian setups the entries are mixed into /var/log/mail.log. The format is still syslog, but the messages differ; for example, an authentication failure appears as SASL PLAIN authentication failed. A small regex adjustment to the commands above is enough to use them.
I have been running this setup for almost a year, and it has helped me investigate cases faster, so I wrote this follow-up. If you have better tricks, whether a shorter regex, a script that automatically correlates exim and dovecot, or a dashboard summarizing the results, feel free to share them.
Use whatever suits you — exim or postfix, 30 days or 90 days of retention. The principle is the same: check both sides and keep logs long enough to trace the problem back to where it started.
Want us to set this up?
Get help with server setup, configuration, migration, or troubleshooting. Save time for the work that matters.
Hit something like this? Stuck somewhere?
Come trade notes on the LinuxThai board



Comments 0
No comments yet — be the first