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 feature, 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.
- Turn it on in DirectAdmin:
cd /usr/local/directadmin
./directadmin set dkim 2 restart
- Enable it in the
exim configs
and Exim:
cd /usr/local/directadmin/custombuild
./build exim
./build eximconf
- 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.5
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=1692.
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.
- 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
- Ensure your spool directory is split into sub-folders. The default exim.conf should already have this enabled.
split_spool_directory = true
- 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.
- Exim provides a guide on how to use a RAM Disk, if you happen to have one available: http://wiki.exim.org/MakeEximFast
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_data 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 here.
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.
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.
Edit the file
/etc/system_filter.exim
Find the code:
if not first_delivery
then
finish
endif
- 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.
- 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: https://forum.directadmin.com/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#SECTdefconfauth
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:
- Shared IPs can be use for the HELO value in smtp.
- 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.