Configuring and customizing Exim

How to update your exim.conf

You can update your SpamBlocker exim.conf with:

cd /usr/local/directadmin/custombuild
./build set exim yes
./build set eximconf yes
./build set spamassassin yes
./build exim
./build exim_conf

How to customize exim.conf

The exim.conf is special, handled separately from CustomBuild, but only if it is set to yes in options.conf:

# grep eximconf /usr/local/directadmin/custombuild/options.conf
eximconf=yes

The proper way is to use /etc/exim.strings.conf.custom and /etc/exim.variables.conf.custom files to customize the exim.conf.

If direct modification of /etc/exim.conf is required and you want to preserve the changes, there are two options:

  • set eximconf to no in options.conf file
    or
  • set immutable bit on /etc/exim.conf with:
chattr +i /etc/exim.conf

How to compile exim from source

The simplest method is to use custombuild:

cd /usr/local/directadmin/custombuild
./build set exim yes
./build exim

Restart exim, and you're done.

If you need to customize the Makefile, type:

cd /usr/local/directadmin/custombuild
mkdir -p custom/exim/
cp configure/exim/Makefile custom/exim/Makefile

Edit the custom/exim/Makefile , and use #1, above, to compile it.

DKIM installation guide

Relating to this featureopen in new window, this guide will outline how to install DKIM on your DirectAdmin server.

DKIM will sign outbound message, and receiving servers will check that signature against DNS records added to the sending domain's zone file to verify the signature and lower the spam score if it passes.

The following assumes you've got /etc/exim.conf 4.5.x or newer.

  1. Turn it on in DirectAdmin:
cd /usr/local/directadmin
./directadmin set dkim 2 restart
  1. Enable it in the exim configs and Exim:
cd /usr/local/directadmin/custombuild
./build exim
./build eximconf
  1. Turn it on for required domains from panel:
    User Level -> Email Accounts -> Enable DKIM

Note about DNS scenarios

The dkim=2 setting, above, will not turn on DKIM for a domain when it's created. It simply makes the feature available to Users, so they can turn it on if they use local DNS for their domain.

Using dkim=1 means that it will be activated immediately when a domain is created on the system. Only use dkim=1 if all domains use local DNS.

If external DNS is used, the DKIM TXT records must be copied over to the remote DNS, else the outbound emails will be signed but will fail since the DNS checks will fail, which is actually far worse than having no DKIM at all.

Alternate way is to use a script from console:

cd /usr/local/directadmin/scripts
./dkim_create.sh domain (nodns) (force)

Options:

  • domain : Required. Name of the domain to enable dkim for.
  • nodns : Optional. Prevents adding the keys to the zone.
  • force : Optional. Force overwrite of the keys with new values.

How to get Exim to listen on another port on top of port 25

Some ISPs are now blocking outgoing port 25 which prevents users from using SMTP via their server. The workaround is to get Exim to listen on another port other than 25 to bypass the ISP's block.

For example, to get Exim to listen on** both port 25 and port 587**, you'd add the following code to /etc/exim.variables.conf.custom file:

daemon_smtp_ports = 25 : 587

Once saved, re-write the Exim configuration:

cd /usr/local/directadmin/custombuild
./build exim_conf

More info: http://www.exim.org/exim-html-4.40/doc/html/spec_13.html#SECT13.5open in new window

How to force Exim to send email from a particular IP

Nowadays, DirectAdmin has the ability to do this automatically based on the owned IP: http://www.directadmin.com/features.php?id=1692open in new window.

If you do this, be sure to update the affected domains' SPF records.

Old Method

The old method to accomplish this is outlined below for the purposes of troubleshooting and for older DirectAdmin systems.

If you need to change the IP that is used to send email out of your system, you can do so by editing your /etc/exim.conf and changing:

remote_smtp:
  driver = smtp

to:

remote_smtp:
  driver = smtp
  interface = 1.2.3.4

Where 1.2.3.4 is the IP you want Exim to use.

You'll also need to update the SPF values in all TXT records in the DNS zone for all domains that send from your server. The SPF value must match the sending IP, which will be the new value you set.

How to get Exim to send email faster

Here are some settings which can be used to get Exim to deliver mail in a quicker fashion. Unless otherwise stated, they are options which can be added to the top section of the /etc/exim.conf, followed by an Exim restart.

  1. Tell Exim not to queue messages which have a lot of destination emails in them. The default is 10. Setting this to 0 will get Exim to try and deliver all of them without saving them to the spool/queue. A value of 0 can be dangerous, as it may bog down your server. If 0 (unlimited) isn't for you, then try something like 100.
smtp_accept_queue_per_connection=0
  1. Ensure your spool directory is split into sub-folders. The default exim.conf should already have this enabled.
split_spool_directory = true
  1. Tell Exim to run more sending processes at the same time:
queue_run_max = 15
remote_max_parallel = 15

Note, you can set queue_run_max = 0 to set it to be unlimited, but again, this runs the risk of bogging down your system. Adjust these values to meet your needs.

  1. Exim provides a guide on how to use a RAM Disk, if you happen to have one available: http://wiki.exim.org/MakeEximFastopen in new window

How to allow messages larger than 20 MB

Use the /etc/exim.variables.conf.custom file and set message_size_limit to the desired value:

message_size_limit=500M

Then run a command to rebuild the exim.variables.conf file:

cd /usr/local/directadmin/custombuild
./build exim_conf

Note that if you're using ClamAV, you'd also need to match the StreamMaxLength setting in /etc/clamd.conf to the message_size_limit.

How to hide the Exim version in the banner

By default, Exim will show its version in the SMTP connection, e.g.,

220 jbmc-software.com ESMTP Exim 4.92.2 Tue, 10 Sep 2019 16:32:25 -0600

If you wish to hide this, you can do so with the smtp_banner option. To do this for exim.conf version 4.5.x+, you'd add the following code to the file /etc/exim.variables.conf.custom:

smtp_banner="${primary_hostname} mail server"

and rebuild the /etc/exim.variables.conf with:

cd /usr/local/directadmin/custombuild
./build exim_conf

How to show different banner in Exim welcome headers depending on the IP

Use /etc/virtual/helo_dataopen in new window to customize the banner depending on the IP connected.

I don't wish to see the hostname in my emails "on behalf of"

Exim by default will not trust any sending Users on your system (doesn't apply to mail sent via SMTP). This means that any email sent as a User from a script will have the from address set to user@server.hostname.com. If you wish to allow your Users to set the From address, and not have Exim rewrite it, you can do so by setting this option:

untrusted_set_sender = *
no_local_from_check

in the top section of your exim.conf (possibly "local_from_check = false"). This option is similar to the trusted_users option, except it doesn't give complete trust in the User. It simply allows the User to set the sender as they desire.

Related Exim documentation on this hereopen in new window.


This can only be overwritten with the use of a per-user php.ini file.

In that User's php.ini file, add the following code:

[mail function]
sendmail_path = /usr/sbin/sendmail -t -i -f user@domain.com

Add this to the acl_script ACL:

  warn         condition = ${if !eq {$acl_m_uid}{${extract{2}{:}{${lookup{majordomo}lsearch{/etc/passwd}{$value}}}}}{yes}{no}}
               remove_header = From
               add_header = "Sender: $h_from"
               add_header = "From: $h_from"

just below the "acl_script:" line. If you have exim.conf 4.5.x, you can instead add this code to /etc/exim.acl_script.pre.conf.

SSL Certificates with Exim

By default, the /etc/exim.conf will use the cert/key files:

/etc/exim.cert
/etc/exim.key

So if you're wondering where to set your files, that's where.

They're controlled by the exim.conf's options:

tls_certificate = /etc/exim.cert
tls_privatekey = /etc/exim.key

Intermediate Certificates

If you have a CA Root certificate (ca bundle, chain, etc.), you'll add the contents of your CA into the exim.cert, after your actual certificate.

It's probably a good idea to make sure you have a copy of everything elsewhere just in case you make an error.

Dovecot and ProFtpd should also read it correctly, so Dovecot no longer needs the ssl_ca option.

So, for both cases, there is no need to make any changes to either the exim.conf or dovecot.conf ( /etc/dovecot/conf/ssl.conf )

How to create a new self-signed certificate for Exim

If you need to generate a new exim.cert and exim.key, run:

openssl req -x509 -sha256 -days 9000 -nodes -newkey rsa:4096 -keyout /etc/exim.key -out /etc/exim.cert

Answer all questions with information you want the certificate to have. Once done, continue by typing:

chown mail:mail /etc/exim.key
chmod 644 /etc/exim.key
chmod 644 /etc/exim.cert
service exim restart

Related error message in one may see in /var/log/exim/mainlog:

(SSL_CTX_use_PrivateKey_file file=/etc/exim.key): error:0200100D:system library:fopen:Permission denied

Note that the /etc/proftpd.conf uses the certificate and the key as well, hence the need for 644 on the key.

How to prevent Exim from including the original email in a bounce

If you want to stop Exim from including the original message in a bounced email, add this line to the top section of your /etc/exim.conf:

bounce_return_message  = false

Save, exit and restart Exim. This doesn't stop bounce emails, only the original message from being included as part of the message (so it doesn't get re-flagged as spam on the other end).

How to prevent bounce emails from leaving your server

Although this method isn't entirely correct in its logic (as we do often want bounce messages to leave the system), but if you don't, edit your /etc/system_filter.exim, and find this code:

if not first_delivery
then
   finish
endif

Right before it, paste this code:

if $sender_address is ""
then
   if $header_Auto-Submitted: is not "auto-replied"
   then
       if ${lookup{${extract{2}{@}{$recipients}}}lsearch{/etc/virtual/domains}{yes}{no}} is "no"
       then
           noerror fail text "Delayed bounce message ignored"
           seen finish
       endif
   endif
endif

If you wish to get a copy of the dropped email, use this code instead:

if $sender_address is ""
then
   if $header_Auto-Submitted: is not "auto-replied"
   then
       if ${lookup{${extract{2}{@}{$recipients}}}lsearch{/etc/virtual/domains}{yes}{no}} is "no"
       then
           headers add "Old-Subject: $h_subject:"
           headers remove "Subject"
           headers add "Subject: [Delayed Bounce]$h_old-subject:"
           headers remove "Old-Subject"
           deliver "abuse@yourdomain.com"

           noerror fail text "Delayed bounce message ignored"
           seen finish
       endif
   endif
endif

Where you would replace abuse@yourdomain.com with the email you want. It would be a good idea to use a local address here (that exists on this box), because if you forward it outbound, you're probably going to flag yourself for sending spam and defeat the whole purpose of this guide.

This may help prevent backscatter, but this has not been confirmed.

Referenced URLopen in new window

How to log all outbound emails leaving my server

This guide will help you log all emails leaving your server that have sender domains which are in the /etc/virtual/domains file. Note that this assumes the "From" address is correct in the message, which isn't always the case. There may be a better variable to use and check, but this is my best guess at the moment.

  1. Edit the file /etc/system_filter.exim

  2. Find the code:

if not first_delivery
then
     finish
endif
  1. Right after the code from #2, add this code
if "${lookup{$sender_address_domain}lsearch{/etc/virtual/domains}{true}{false}}" is "true"
then
            unseen deliver "email@notification.com"
endif

Where you'd replace email@notification.com with the email value you want all outbound emails to be saved to.

  1. Save/exit and restart Exim:
service exim restart

How to force immediate bounce of email if an account is over quota

If you wish to immediately bounce emails that are sent to client who are over quota, you can edit your /etc/exim.conf file, and find this code at the bottom of the file:

begin retry
*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,8h

Insert a new line to make it look like:

begin retry
*                      quota
*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,8h

This will force all emails to an over-quota account to be immediately bounced.

Note that the message is already accepted, as Exim does not have a good smtp-time method of checking quotas.

Related: <directadmin.com/forum/showthread.php?t=38915>

How to only allow smtp auth login if encryption is enabled

It's more secure to require that a connection uses TLS/SSL before passing the password over the internet.

You can force Exim to do so by adding the line to your /etc/exim.conf authenticators:

server_advertise_condition = ${if def:tls_in_cipher }

They might look like this:

##################################################################################
# AUTHENTICATION CONFIGURATION
##################################################################################
begin authenticators

plain:
   driver = plaintext
   public_name = PLAIN
   server_prompts = :
   server_condition = "${perl{smtpauth}{${lc:$auth2}}{$auth3}}"
   server_set_id = ${lc:$auth2}
   server_advertise_condition = ${if def:tls_in_cipher }

login:
   driver = plaintext
   public_name = LOGIN
   server_prompts = "Username:: : Password::"
   server_condition = "${perl{smtpauth}{${lc:$auth1}}{${auth2}}}"
   server_set_id = ${lc:$auth1}
   server_advertise_condition = ${if def:tls_in_cipher }

Related, see section #7 of this document: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_default_configuration_file.html#SECTdefconfauthopen in new window


As RoundCube email does not use TLS by default, it will likely need to be updated, by editing /var/www/html/roundcube/config/config.inc.php and find the smtp_server line, and change it to be:

$config['smtp_server'] = 'tls://%n';

Note, you'll likely want to use this guide to copy the config.inc.php to /usr/local/directadmin/custombuild/custom/rouncdube/config.inc.php, so it's safe from future overwrites via CustomBuild call ./build roundcube.

How to only allow AUTH on port 587 (block on 25)

As port 587 is the common client entry point, some Admins may decided to take things one step further and entirely prevent Users from using port 25 for authentication.

The short answer is that we need the following to be set in Exim:

auth_advertise_hosts = ${if or { {eq {$received_port}{465}} {eq {$received_port}{587}} } {*}{}}

If you're running SpamBlocker 4.5.x, then this can be done without having to worry about the exim.conf being overwritten.

To do this, create/edit this file /etc/exim.variables.conf.custom, and add the above code inside it. This is just the placeholder for override settings.

To actually kick that over to the /etc/exim.variables.conf, we let CustomBuild do it with:

cd /usr/local/directadmin/custombuild
./build eximconf

which will download updated files, and merge the exim.variables.conf.default and exim.variables.conf.custom, into the exim.variables.conf for Exim to actually read.

You can test this functionality, by typing:

telnet localhost 25

and issue a EHLO command, e.g.,

EHLO localhost

And if it worked correctly, you will NOT see this in the output:

250-AUTH PLAIN LOGIN

Note, if you test from an external host, you'd swap "localhost" with your hostname for the telnet, and the local hostname (client side). Client host must not match the Exim host, else it will claim you're impersonating the hostname.

How to force authenticated users to only send from their authenticated domain

To make sure Users use their own domain in their From header, assuming you've got a newer exim.conf that supports /etc/exim.acl_check_message.pre.conf create the file and add this code to it:

deny
 authenticated = *
 condition = ${if or { { !eqi{${domain:$authenticated_id}} {$sender_address_domain} }\
                      { !eqi{${domain:{$authenticated_id}} {${domain:{${address:$header_From:}}} }\
                     }\
              }
 message = Your FROM address domain ( $sender_address_domain ) must match your domain name used in authenticated email user ( $authenticated_id ).

Character encoding in autoreplies and vacation messages.

By default, no character encoding is specified for autoreplies or vacation messages. If you'd like to define something, you can add this code:

headers = Content-Type: text/plain; charset="UTF-8"

into your uservacation and userautoreply transport sections of your /etc/exim.conf (not the directors, but rather the transports farther down in the exim.conf).

Adjust the charset value for the header as required.

Note, for the subject line, try this:

subject = "${if def:h_Subject: {Autoreply: \"${escape:${length_50:$rh_Subject:}}\"} {I am on vacation}}"

There are also reports of the use of $rh_Subject instead of $h_Subject working.


Another possible subject line:

 subject = ${if def:h_subject: \
               {Autoreply: ${rfc2047:${quote:${escape:${length_60:$h_subject:}} }} }\
               {Autoreply Message} \
           }

Yet a 3rd option below:

 headers = MIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit
 subject = ${if def:h_Subject: {Autoreply: ${quote:${escape:${length_50:$h_Subject:}}}} {Autoreply Message} }

How to manage the domain IPS file for exim outbound IP/interfaces so that mail is sent from a domain's dedicated IP

If you have clients/domains using dedicated IPs in lieu of the main server IP, you may want to set up the exim outbound interface to use that IP as well.

First of all, please make sure that add_domain_to_domainips is enabled on your server. You may confirm with the following command:

/usr/local/directadmin/directadmin config | grep add_domain_to_domainips

If the feature is disabled, enable it by executing the following commands:

/usr/local/directadmin/directadmin set add_domain_to_domainips 1
systemctl restart directadmin

DirectAdmin will use the following files for configuration:

/etc/virtual/domainips/etc/virtual/helo_data

Let's generate these files. /etc/virtual/domainips may be generated with the following command:

echo "action=rewrite&value=domainips" >> /usr/local/directadmin/data/task.queue

All domains and pointers will be added this way. DirectAdmin will update this file automatically in the future.

In case you would like to re-generate /etc/virtual/domainips from scratch, which is handy if everything is out of sync, start over with the following command:

echo "action=rewrite&value=domainips&empty=yes" >> /usr/local/directadmin/data/task.queue

If you would like to resync a specific domain (and its pointers), removing previous values of the affected domain from the domainips first, you may explicitly specify the domain variable, for example:

echo "action=rewrite&value=domainips&domain=domain.com" >> /usr/local/directadmin/data/task.queue

Similarly, for helo_data:

All:

echo "action=rewrite&value=helo_data" >> /usr/local/directadmin/data/task.queue

Just for one IP:

echo "action=rewrite&value=helo_data&ip=1.2.3.4" >> /usr/local/directadmin/data/task.queue

Samples

Sample /etc/virtual/helo_data:

1.2.3.4:mail.server.com
1.2.3.5:mail.other.com

where the server IP and main hostname do not need to be in this file. The IP lookup on the left must be unique, matching the IP used for the incoming connection.

Sample /etc/virtual/domainips:

domain.com:1.2.3.4
other.com:1.2.3.5

where you can have duplicate IPs on the right, but the left side must be unique (matches @domain.com).

Manual control

You can set:

add_domain_to_domainips=0

and manually manage these files.

Just remember to try and keep the forward and reverse dns lookups configured to match so that checks against Forward-confirmed reverse DNS (FCrDNS), aka full-circle rDNS pass. For example:

mail.domain.com -> 1.2.3.4
1.2.3.4 -> mail.domain.com

Another possible value is add_domain_to_domainips=2* , when it is set the /etc/virtual/domainips is unaffected. However, the /etc/virtual/helo_data file will use the rDNS for that given IP, instead of using the owned IP's user's main domain. This means you can now use shared IPs in the helo_data file.

Once setting the directadmin.conf variable to 2, you can issue a rewrite to create a fresh file, if needed:

echo 'action=rewrite&value=helo_data' >> /usr/local/directadmin/data/task.queue

and confirm the changes in /etc/virtual/helo_data after the dataskq has run.

The benefit of this is that:

  1. Shared IPs can be use for the HELO value in smtp.
  2. You can more easily control the forward and reverse IP lookups which are added to the file.

NOTE: The same action triggers addition of the domain to the file. As such, the value is only added when a User is created on this IP, but now it sets the value no matter what.

If you change the rDNS, simply add another User for this IP, and it will update the entry in the helo_data file.

How to configure exim to check quota on smtp-time

You can allow exim to block an inbound email at smtp-time via ACL, rather than accepting the message, and having it bounce after the dovecot lmtp delivery rejects it.

The ACL in question does not yet exist. If it will exist, it wouldn't be for a while after this version of DirectAdmin has been released. Just a prototype for future use.

This requires setting directadmin in suid mode and fix permissions with:

echo 1 > /root/.suid_directadmin
/usr/local/directadmin/directadmin permissions

It will set DA binary to be:

-rwsr-xr-x 1 root diradmin

This is used for per-User calls like:

./directadmin --doveadm-quota=user@domain.com

which can be called as root, mail or a User.

If called as a User, it will ensure that domain.com belongs to the UID caller (not likely a common usage, but is an option since suid was needed anyway for 'mail')

If root or mail, it will work for any email that exists the system.

If the email is valid, dovecot quotas work, then it will output something like:

18237:102400

which would be in KB, so the above example, the account is using about 20Meg of 100Meg.

You MUST check the exit code of the directadmin call. If it's not 0, then ignore this directadmin result.

If the account in question has unlimited dovecot quotas, then the output will be:

0:0

This feature uses the doveadm quota call to get the info, as dovecot is going to be what will accept/reject the email anyway.

Last Updated: