EXIM CHEAT SHEET

The following EXIM Cheat Sheet will help you manage your EXIM 4 server. To complete these steps, it is helpful if you already are familiar with SMTP, MTA, and UNIX shell prompt. If you are having any issues with email delivery, please check out my post on DKIM, SPF and DMARC records. That post will save you a lot of frustration.

Managing Message-IDs & Spool Files

Message-IDs are messages that are in the EXIM queue. These will be mixed case alpha numeric and will appear like this YUC3-UIIOS-DOLKS using hyphens and not spaces. These Message-IDs are used when managing the queue and for logging use.

The Spool directory contains three files for every message. When doing this manually, instead of utilizing the EXIM commands, be sure to get all three files for the message so that you do not leave any partial files in the queue. It is more effective if you use the EXIM commands to prevent any errors or broken files.

The logging information for the messages is in /var/spool/exim/msglog . We identify them with the same name as the Message-IDs besides containing a suffix that shows if it is the envelope header (-H) or the message data (-D).

Only cool people share!

The directories may also show hashed subdirectories when working with larger mail queues. Because of this, all the files may not always show in the top /var/spool/exim/input or in the /var/spool/exim/mslog directories. So any searches or greps should be recursive. You should always double check if there is a more direct and simple route to accomplish this before you work directly on your spool files.

Display EXIM Settings

exim -bP

Basic Commands For EXIM Management

Print a count of the messages in the queue:

root@localhost# exim -bpc

Print a listing of the messages in the queue (time queued, size, message-id, sender, recipient):

root@localhost# exim -bp

Print a summary of messages in the queue (count, volume, oldest, newest, domain, and totals):

root@localhost# exim -bp | exiqsumm

Print what Exim is doing right now:

root@localhost# exiwhat

Test how exim will route a given address:

root@localhost# exim -bt alias@localdomain.com
user@thishost.com
    <-- alias@localdomain.com
  router = localuser, transport = local_delivery
root@localhost# exim -bt user@thishost.com
user@thishost.com
  router = localuser, transport = local_delivery
root@localhost# exim -bt user@remotehost.com
  router = lookuphost, transport = remote_smtp
  host mail.remotehost.com [1.2.3.4] MX=0

Run a pretend SMTP transaction from the command line, as if it were coming from the IP address. This will display Exim’s checks, ACLs, and filters as they are applied. It will NOT actually deliver the message.

root@localhost# exim -bh 192.168.11.22

Display all of Exim’s configuration settings:

root@localhost# exim -bP

How To Search Queue Using exiqgrep

There is a utility already in EXIM that does grepping through the queue known as exiqgrep.

Exim includes a utility that is quite nice for grepping through the queue, called exiqgrep. If you are unaware of the various flags used in this utility then you may be making your work harder than it has to be.

The flags control which messages are matched together. Combining these flags can give you a more specific search.

Use -f to search the queue for messages from a specific sender:

root@localhost# exiqgrep -f [luser]@domain

Use -r to search the queue for messages for a specific recipient/domain:

root@localhost# exiqgrep -r [luser]@domain

Use -o to print messages older than the specified number of seconds. For example, messages older than 1 day:

root@localhost# exiqgrep -o 86400 [...]

Use -y to print messages that are younger than the specified number of seconds. For example, messages less than an hour old:

root@localhost# exiqgrep -y 3600 [...]

Use -s to match the size of a message with a regex. For example, 700-799 bytes:

root@localhost# exiqgrep -s '^7..$' [...]

Use -z to match only frozen messages, or -x to match only unfrozen messages.

These flags control the display of the output.

Use -i to print just the message-id as a result of one of the above two searches:

root@localhost# exiqgrep -i [ -r | -f ] ...

Use -c to print a count of messages matching one of the above searches:

root@localhost# exiqgrep -c ...

Print just the message-id of the entire queue:

root@localhost# exiqgrep -i

How To Manage The Queue

You will use the main EXIM binary of /usr/sbin/exim  with the flags to work functions for the messages in the queue. Most them require one or more Message-IDs to be named in the command line. This is where you will use “exiqgrep -i” to make the process easier.

Start a queue run:

root@localhost# exim -q -v

Start a queue run for just local deliveries:

root@localhost# exim -ql -v

Remove a message from the queue:

root@localhost# exim -Mrm <message-id> [ <message-id> ... ]

Freeze a message:

root@localhost# exim -Mf <message-id> [ <message-id> ... ]

Thaw a message:

root@localhost# exim -Mt <message-id> [ <message-id> ... ]

Deliver a message, whether it’s frozen or not, whether the retry time has been reached or not:

root@localhost# exim -M <message-id> [ <message-id> ... ]

Deliver a message, but only if the retry time has been reached:

root@localhost# exim -Mc <message-id> [ <message-id> ... ]

Force a message to fail and bounce as “cancelled by administrator”:

root@localhost# exim -Mg <message-id> [ <message-id> ... ]

Remove all frozen messages:

root@localhost# exiqgrep -z -i | xargs exim -Mrm

Remove all messages older than five days (86400 * 5 = 432000 seconds):

root@localhost# exiqgrep -o 432000 -i | xargs exim -Mrm

Freeze all queued mail from a given sender:

root@localhost# exiqgrep -i -f luser@example.tld | xargs exim -Mf

View a message’s headers:

root@localhost# exim -Mvh <message-id>

View a message’s body:

root@localhost# exim -Mvb <message-id>

View a message’s logs:

root@localhost# exim -Mvl <message-id>

Add a recipient to a message:

root@localhost# exim -Mar <message-id> <address> [ <address> ... ]

Edit the sender of a message:

root@localhost# exim -Mes <message-id> <address>

How To Use Access Control

You can use Access Control lists in different parts of your SMTP transaction by specifying which Access Control List you want to use and defining the conditions of that list in the exim.conf by starting with the HELO string.

# Specify the ACL to use after HELO
acl_smtp_helo = check_helo

# Conditions for the check_helo ACL:
check_helo:

    deny message = Gave HELO/EHLO as "friend"
    log_message = HELO/EHLO friend
    condition = ${if eq {$sender_helo_name}{friend} {yes}{no}}

    deny message = Gave HELO/EHLO as our IP address
    log_message = HELO/EHLO our IP address
    condition = ${if eq {$sender_helo_name}{$interface_address} {yes}{no}}

    accept

NOTE: Pursue HELO checking at your own peril. The HELO is fairly unimportant in the grand scheme of SMTP these days, so don’t put too much faith in whatever it contains. Some spam might seem to use a telltale HELO string, but you might be surprised at how many legitimate messages start off with a questionable HELO as well. Anyway, it’s just as easy for a spammer to send a proper HELO than it is to send HELO im.a.spammer, so consider yourself lucky if you’re able to stop much spam this way.

After this, you will be able to perform a check on the sender address or the remote host by using the following after the RCPT TO command. If you reject here instead of rejecting after the MAIL FROM then you will have more appropriate data to log like who the message was meant for.

# Specify the ACL to use after RCPT TO
acl_smtp_rcpt = check_recipient

# Conditions for the check_recipient ACL
check_recipient:

    # [...]

    drop hosts = /etc/exim_reject_hosts
    drop senders = /etc/exim_reject_senders

    # [ Probably a whole lot more... ]

This example uses two plain text files as blacklists. Add the appropriate entries to the files hostnames/IP addresses to /etc/exim_reject_hosts, addresses to /etc/exim_reject_senders, type only one entry on each line.

You will also be able to do content scanning by using regex against the message body. However, this can cause EXIM to use more CPU than it needs to use. This is especially true if the message is larger.

# Specify the ACL to use after DATA
acl_smtp_data = check_message

# Conditions for the check_messages ACL
check_message:

    deny message = "Sorry, Charlie: $regex_match_string"
    regex = ^Subject:: .*Lower your self-esteem by becoming a sysadmin

    accept

How To Fix SMTP-Auth For Pine

Pine may not be able to use SMTP authentication on your EXIM host. If so, it will return a message stating “unable to authenticate” and won’t ask for a password. When this happens, add the folling line to your exim.conf:

  begin authenticators

  fixed_plain:
  driver = plaintext
  public_name = PLAIN
  server_condition = "${perl{checkuserpass}{$1}{$2}{$3}}"
  server_set_id = $2
>  server_prompts = :

This used to be a problem on the cPanel EXIM builds, but more recent stock configurations may already have this line added.

How To Log The Subject Line With EXIM

To log the subject line with EXIM, add the following to exim.conf and you will be able to log the subject lines of the messages that pass through your server. This is helpful when troubleshooting to give you a rough estimate of which messages may contain spam.

log_selector = +subject

Reducing or increasing what is logged.

Disable identd Lookups

Identd is not as useful as it used to be because it depends on using the connecting host to confirm the identity or system UID of the remote user whose process is connecting the network. This could be useful with some shell accounts and IRC users but is not really used for high-volume SMTP servers where the UID is usually “mail” or what the MTA runs as and has no use for most managers. It creates overhead and often only results in causing delays while waiting the identd query to be refused or time out. You can prevent these queries from being used by your EXIM server by setting the timeout to zero seconds in exim.conf using this line:

rfc1413_query_timeout = 0s

How To Disable Attachment Blocking

If you wish to disable executable-attachment blocking used by many cPanel servers, you can set a default. When setting a default, you should not provide any controls for a per-domain basis. To do this, add the following block to the beginning of /etc/antivirus.exim :

if $header_to: matches "example\.com|example2\.com"
then
  finish
endif

It may be possible to use a different file to list these domains, but it is often not warranted to do so.

How To Search Logs Using exigrep

You can use the exigrep utility to search an EXIM log for a string or pattern. Do not confuse this with exiqgrep as that is a different utility. This will print all log entries that have the same internal Message_IDs as the pattern you are searching. The benefit is that it will take up at least three lines in the log. The entire content of a log entry is searched when using exigrep, not just certain fields.

This is how you search for messages sent from a particular IP address:

root@localhost# exigrep '<= .* \[12.34.56.78\] ' /path/to/exim_log

Or search for messages sent to a particular IP address:

root@localhost# exigrep '=> .* \[12.34.56.78\]' /path/to/exim_log

This is how you search for outgoing messages with the “=>” symbol that are sent to “user@domain.tld”. The pipe to grep for the “<=” symbol will only match lines containing information on the sender, the From address, the sender’s IP address, the message size, the message ID, and the subject line if you have enabled logging the subject. The reason for performing this search is so the desired information is not on the same log line as the string being searched for.

root@localhost# exigrep '=> .*user@domain.tld' /path/to/exim_log | fgrep '<='

Generate and display Exim stats from a logfile:

root@localhost# eximstats /path/to/exim_mainlog

Same as above, with less verbose output:

root@localhost# eximstats -ne -nr -nt /path/to/exim_mainlog

Same as above, for one particular day:

root@localhost# fgrep YYYY-MM-DD /path/to/exim_mainlog | eximstats

Extra Tips

To delete all queued messages containing a certain string in the body:

root@localhost# grep -lr 'a certain string' /var/spool/exim/input/ | \
                sed -e 's/^.*\/\([a-zA-Z0-9-]*\)-[DH]$/\1/g' | xargs exim -Mrm

Notice that this command only delves into /var/spool/exim to grep for queue files with the string. This is because exiqgrep does not have a feature to grep the actual bodies of messages. It is wrong to delete these files directly. You should only use the proper EXIM command to deal with the queue appropriately.

If it is necessary to feed a lot of Message-IDs (for instance where the output of an `exiqgrep -i` command shows a large number of matches) to an EXIM command, then this could exhaust the limit of your shell’s command line arguments. If so, pipe the listing of Message-IDs into xargs to run only a few them at one time. As an example, to remove thousands of messages sent from joe@example.com perform:

root@localhost# exiqgrep -i -f '<joe@example.com>' | xargs exim -Mrm

Attention, CPanel Forum Readers – Are You Doing It Wrong

Many individuals seeking this information come from CPanel forums. The question is:

Because of spamming, spoofing from fields, etc., etc., etc., I am finding it necessary to spend more time to clear the exim queue from time to time. […] what command would I used to delete the queue?

The answer is: Just turn EXIM off. Your customers are better off knowing that email simply isn’t running on your server, than having their queued messages deleted without notice.

An option is to figure out what is going on. The examples given often pay no mind to the legitimacy of any message. They simply delete everything, assuming that if a message is in the queue, then it must be junk. THIS IS A WRONG APPROACH. There are many reasons legitimate mail can end up in the queue. Maybe your backups or CPanel’s “upcp” process are still running and your load average is high. EXIM goes into a queue-only mode at a certain threshold when it stops trying to deliver messages as they come in and just queues them until the load goes back down. It is also possible that an outgoing message and the DNS lookup failed or that the connection to the domain’s MX failed, or the remote MX is busy or greylisting you with a 4xx deferral. These are all temporary failures, not permanent ones. You may have temporary failures in your SMTP and the mail queue in your MTA allows it to try again later.

Exim will purge messages from the queue after the period specified in exim.conf.

If you have this value set correctly, then there is no point in removing everything from your queue every day with a cron job. You will lose legitimate mail, and the sender and recipient will never know if or why it happened. Do not do this!

You may have many messages in your queue regularly, then you should figure out why it is happening. If these regular instances are outbound messages, check who is sending them, where they’re addressed to, and why they are not going there. Instead, if you find them as inbound messages, you need to know why they are not being delivered to your user’s account. If you should have to delete some, I recommend using exiqgrep to select only the messages that need to be deleted.

How To Reload Your Configuration

Now that you have changed your exim.conf you should give the main exim pid a SIGHUP  to re-exec it so that your configuration is re-read. It is overkill to stop and restart the service, which also causes some seconds of downtime. Instead, perform:

root@localhost# kill -HUP `cat /var/spool/exim/exim-daemon.pid`

Next, you should see something similar to the following in your exim_mainlog:

pid 1079: SIGHUP received: re-exec daemon
exim 4.52 daemon started: pid=1079, -q1h, listening for SMTP on port 25 (IPv4)

The command below will delete all emails TO domain.com:

# exiqgrep -i -t domain.com | xargs exim -Mrm

The command below will delete all emails FROM domain.com:

# exiqgrep -i -f domain.com | xargs exim -Mrm

Quick Commands

# Get queue count

exim -bpc

# Display messages

exim -bp

# Display message headers

exim -Mvh

# Display message body

exim -Mvb

# Delete all messages in queue by domain

exim -bp|grep ""| awk {'print $3'}| xargs exim -Mrm

# Delete all messages in queue

exim -bp | exiqgrep -i | xargs exim -Mrm

Frozen Emails

This will produce a number of frozen emails in the exim

exim -bp | grep -c frozen

To remove these frozen emails use command:

exim -bpr | grep frozen | awk {'print $3'} | xargs exim -Mrm

You should see your emails delete one by one.

OK…now re-issue the command

exim -bp | grep -c frozen

You should see that the number listed is smaller. SUCCESS.

Delete all messages that are from sender@example.com.

You can add -v to the exim command in order to get more verbose output.

exiqgrep -i -f sender@example.com | exim -Mrm

You can do it a slightly different way where you generate a bounce message for each item. This emphasizes to the end user how much harm their compromised mailbox has been causing:

exiqgrep -i -f sender@example.com | exim -Mg

WHM Suspend Outgoing Mail

whmapi1 suspend_outgoing_email user=example

EXIM CHEAT SHEET was last modified: July 21st, 2022 by Maximus Mccullough

2 Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.