What are some tools that I can use to troubleshoot mail delivery issues with Exim on my linux / BSD / unix server?
This article will highlight some of the utilities included with the standard exim installation that assist in troubleshooting mail delivery issues.
Exigrep
Exigrep is very useful when you need to search for specific strings in the exim logfile. The reason for this is that it will look for the search string you specify, match that to a message-ID, and then display all the lines pertaining to that message.
Usage: exigrep /path/to/exim/logfile
Examples:
root@cpdemo [~]# exigrep 1BbLM3-0007fA-0v /var/log/exim_mainlog
2004-06-18 10:32:35 1BbLM3-0007fA-0v <= root@cpdemo.example.com U=root P=local S=1037
2004-06-18 10:32:37 1BbLM3-0007fA-0v => /dev/null <devnull@cpdemo.example.com> R=system_aliases T=**bypassed**
2004-06-18 10:32:37 1BbLM3-0007fA-0v Completed
-OR-
root@cpdemo [~]# exigrep inspirem@cpdemo.example.com /var/log/exim_mainlog
2004-06-14 00:00:00 1BZjZg-000750-Ch <= inspirem@cpdemo.example.com U=inspirem P=local S=597
2004-06-14 00:00:00 1BZjZg-000750-Ch == example@yahoo.com R=defer_router defer (-1): All deliveries are handled by MailScanner
2004-06-14 00:00:03 1BZjZg-000750-Ch => example@yahoo.com R=lookuphost T=remote_smtp H=mx1.mail.yahoo.com [64.157.4.78]
2004-06-14 00:00:03 1BZjZg-000750-Ch Completed
2004-06-15 00:00:01 1Ba63E-0004gD-US <= inspirem@cpdemo.example.com U=inspirem P=local S=597
2004-06-15 00:00:01 1Ba63E-0004gD-US == example@yahoo.com R=defer_router defer (-1): All deliveries are handled by MailScanner
2004-06-15 00:00:04 1Ba63E-0004gD-US => example@yahoo.com R=lookuphost T=remote_smtp H=mx1.mail.yahoo.com [64.156.215.19]
2004-06-15 00:00:04 1Ba63E-0004gD-US Completed
Also notice that if you are looking for information that is listed in multple email transactions(ie. email addresses, sending hosts, etc …), exigrep will provide a space in between each email transaction.
Exiwhat
The ‘exiwhat’ command displays what each running exim process is doing at that given moment. This can be helpful in tracking down the cause for hanging exim processes or monitoring exim processes while they perform certain functions during testing.
Example:
root@cpdemo [~]# exiwhat
2118 daemon: -q1h, listening for SMTP on port 25 (IPv4)
2130 daemon: no queue runs, listening for SMTPS on port 465 (IPv4)
31640 handling incoming connection from [67.19.0.37]
Exim -bh
This section describes another usage of the exim mail server binary with special arguments that allow you to simulate a mail delivery from an external IP as the sender from the local server with the exim installation. This can be very useful when you need to recreate the mail delivery issue and you don’t have access to the sender’s machine to do so(ex. mail relaying, blacklists, etc.).
Usage: exim -bh
This will create a fake SMTP session which appears to be from . Not only that, but it also displays what exim is doing behind the scenes, and also what it would normally log. Now, bear in mind that this will not actually inject a message into the queue, nor will it actually log anything. This does however require knowledge of SMTP commands, but they are fairly easy. I have highlighted them in bold below for easier reading. Example:
root@cpdemo [/var/spool/exim/input]# exim -bh 216.87.129.155
**** SMTP testing session as if from host 216.87.129.155
**** but without any ident (RFC 1413) callback.
**** This is not for real!
>>> host in host_lookup? no (option unset)
>>> host in host_reject_connection? no (option unset)
>>> host in sender_unqualified_hosts? no (option unset)
>>> host in recipient_unqualified_hosts? no (option unset)
>>> host in helo_verify_hosts? no (option unset)
>>> host in helo_try_verify_hosts? no (option unset)
>>> host in helo_accept_junk_hosts? yes (matched “*”)
220-cpdemo.domain.com ESMTP Exim 4.34 #1 Fri, 18 Jun 2004 16:05:31 -0500
220-We do not authorize the use of this system to transport unsolicited,
220 and/or bulk e-mail.
helo bbozo-2.example.com
>>> bbozo-2.example.com in helo_lookup_domains? no (end of list)
250 cpdemo.domain.com Hello bbozo-2.example.com [216.87.129.155]
mail from: ken@bbozo-2.example.com
250 OK
rcpt to: inspirem@cpdemo.domain.com
>>> using ACL “check_recipient”
>>> processing “accept”
>>> check hosts = :
>>> host in “:”? no (end of list)
>>> accept: condition test failed
>>> processing “warn”
>>> check condition = ${if and {{match{$local_part}{(.*)-bounces+.*}} {exists {/usr/local/cpanel/3rdparty/mailman/lists/${lc:$1}/config.pck}}} {yes}{no}}
>>> = no
>>> warn: condition test failed
>>> processing “accept”
>>> check condition = ${if and {{match{$local_part}{(.*)-bounces+.*}} {exists {/usr/local/cpanel/3rdparty/mailman/lists/${lc:$1}/config.pck}}} {yes}{no}}
>>> = no
>>> accept: condition test failed
>>> processing “warn”
>>> check condition = ${if and {{match{$local_part}{(.*)-bounces+.*}} {exists {/usr/local/cpanel/3rdparty/mailman/lists/${lc:$1}_${lc:$domain}/config.pck}}} {yes}{no}}
>>> = no
>>> warn: condition test failed
>>> processing “accept”
>>> check condition = ${if and {{match{$local_part}{(.*)-bounces+.*}} {exists {/usr/local/cpanel/3rdparty/mailman/lists/${lc:$1}_${lc:$domain}/config.pck}}} {yes}{no}}
>>> = no
>>> accept: condition test failed
>>> processing “require”
>>> check verify = sender
>>> ken@bbozo-2.example.com in “nobody@lsearch;/etc/localdomains“? no (end of list)
>>> ken@bbozo-2.example.com in “cpanel@lsearch;/etc/localdomains“? no (end of list)
>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>> routing ken@bbozo-2.example.com
>>> bbozo-2.example.com in “lsearch;/etc/localdomains”? no (end of list)
>>> bbozo-2.example.com in “! +local_domains”? yes (end of list)
>>> calling lookuphost router
>>> 216.87.129.155 in “0.0.0.0 : 127.0.0.0/8 : 64.94.110.0/24”? no (end of list)
>>> routed by lookuphost router
>>> ———– end verify ————
>>> require: condition test succeeded
>>> processing “accept”
>>> check domains = +local_domains
>>> cpdemo.domain.com in “lsearch;/etc/localdomains”? yes (matched “lsearch;/etc/localdomains”)
>>> cpdemo.domain.com in “+local_domains”? yes (matched “+local_domains”)
>>> check verify = recipient
>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>> routing inspirem@cpdemo.domain.com
>>> cpdemo.domain.com in “! +local_domains”? no (matched “! +local_domains” – cached)
>>> cpdemo.domain.com in “! +local_domains”? no (matched “! +local_domains” – cached)
>>> cpdemo.domain.com in “! +local_domains”? no (matched “! +local_domains” – cached)
>>> cpdemo.domain.com in “lsearch;/etc/userdomains”? no (end of list)
>>> cpdemo.domain.com in “! lsearch;/etc/userdomains”? yes (end of list)
>>> cpdemo.domain.com in “lsearch;/etc/localdomains”? yes (matched “lsearch;/etc/localdomains”)
>>> calling virtual_aliases_nostar router
>>> virtual_aliases_nostar router declined for inspirem@cpdemo.domain.com
>>> cpdemo.domain.com in “lsearch;/etc/userdomains”? no (end of list)
>>> cpdemo.domain.com in “lsearch;/etc/userdomains”? no (end of list)
>>> cpdemo.domain.com in “lsearch;/etc/localdomains”? yes (matched “lsearch;/etc/localdomains”)
>>> cpdemo.domain.com in “lsearch;/etc/localdomains”? yes (matched “lsearch;/etc/localdomains”)
>>> calling virtual_aliases router
>>> virtual_aliases router declined for inspirem@cpdemo.domain.com
>>> calling system_aliases router
>>> system_aliases router declined for inspirem@cpdemo.domain.com
>>> calling local_aliases router
>>> local_aliases router declined for inspirem@cpdemo.domain.com
>>> cpdemo.domain.com in “! lsearch;/etc/userdomains”? yes (end of list)
>>> cpdemo.domain.com in “! lsearch;/etc/userdomains”? yes (end of list)
>>> calling localuser router
>>> routed by localuser router
>>> ———– end verify ————
>>> accept: condition test succeeded
250 Accepted
Data
354 Enter message, ending with “.” on a line by itself
From: Ben bozo <ken@bbozo-2.example.com>
Subject: Test
>>> host in ignore_fromline_hosts? no (option unset)
Test.
.
>>> using ACL “check_message”
>>> processing “require”
>>> check verify = header_sender
>>> verifying From: header address Ben bozo <ken@bbozo-2.example.com>
>>> ken@bbozo-2.example.com in “nobody@lsearch;/etc/localdomains“? no (end of list)
>>> ken@bbozo-2.example.com in “cpanel@lsearch;/etc/localdomains“? no (end of list)
>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>> routing ken@bbozo-2.example.com
>>> bbozo-2.example.com in “lsearch;/etc/localdomains”? no (end of list)
>>> bbozo-2.example.com in “! +local_domains”? yes (end of list)
>>> calling lookuphost router
>>> 216.87.129.155 in “0.0.0.0 : 127.0.0.0/8 : 64.94.110.0/24”? no (end of list)
>>> routed by lookuphost router
>>> require: condition test succeeded
>>> processing “accept”
>>> accept: condition test succeeded
LOG: 1BbQZP-00005P-Gg <= ken@bbozo-2.example.com H=(bbozo-2.example.com) [216.87.129.155] P=smtp S=264
250 OK id=1BbQZP-00005P-Gg
**** SMTP testing: that is not a real message id!