<p>
The main parts to deliver electronic mail over the internet are as follows:
</p>
<ul>
<li>Message Transfer Agent (MTA)</li>
<li>Mail Delivery Agent (MDA)</li>
<li>Mail User Agnet (MUA) or e-mail client</li>
</ul>
<p>
Exim is the default message transfer agent (MTA) of Debian.<br />
It is installed by default and configured to do local mail delivery only.
</p>
<p>
This tutorial explains how to configure Exim 4 on Debian 10 (buster)<br />
to send and receive mails for your own domain over the internet.
</p>

<h3>Contents</h3>
<ul>
<li><a href="#domain">Domain</a>
<ul>
<li><a href="#domain_zone">Zone</a></li>
<li><a href="#domain_spf">SPF</a></li>
<li><a href="#domain_rdns">rDNS</a></li>
<li><a href="#domain_checkmx">Check MX Record</a></li>
</ul>
</li>
<li><a href="#conf">Basic Configuration</a>
<ul>
<li><a href="#conf_dpkg-reconfigure">dpkg-reconfigure</a></li>
<li><a href="#conf_hostname">Hostname</a></li>
<li><a href="#conf_aliases">Aliases</a></li>
<li><a href="#conf_testlocal">Test Local Delivery</a></li>
<li><a href="#conf_testremote">Test Remote Connectivity</a></li>
</ul>
</li>
<li><a href="#tls">SSL/TLS Encryption</a>
<ul>
<li><a href="#tls_config">Configuration</a></li>
<li><a href="#tls_letsencrypt">Let&apos;s Encrypt</a></li>
<li><a href="#tls_testencrypt">Test Encryption</a></li>
</ul>
</li>
<li><a href="#auth">Authentication</a>
<ul>
<li><a href="#auth_config">Configuration</a></li>
<li><a href="#auth_accounts">Accounts</a></li>
</ul>
</li>
<li><a href="#dkim">DKIM</a>
<ul>
<li><a href="#dkim_genkey">Generate Key</a></li>
<li><a href="#dkim_config">Configuration</a></li>
<li><a href="#dkim_pubkey">Publish Public Key</a></li>
</ul>
</li>
<li><a href="#links">External Links for further Information</a></li>
</ul>

<h3 id="domain">Domain</h3>
<p>
In the following examples, the domain is called <code>example.net</code>.<br />
The IPv4 address of the server running the MTA is <code>192.0.2.1</code><br />
and the IPv6 address is <code>2001:db8:10::1</code> in the examples.
</p>

<h4 id="domain_zone">Zone</h4>
<p>
Relevant parts in the zone of the domain are specified as follows:
</p>
<pre class="file"><code class="language-dns">@     IN  MX    10 mail.example.net.  ; The MX record specifies the mail server
mail  IN  A     192.0.2.1             ; IPv4 address for mail.example.net
mail  IN  AAAA  2001:db8:10::1        ; IPv6 address for mail.example.net
@     IN  TXT   "v=spf1 ip4:192.0.2.1 ip6:2001:db8:10::1 ~all"
</code></pre>

<h4 id="domain_spf">SPF</h4>
<p>
The Sender Policy Framework (SPF) allows other MTAs to check<br />
if they should accept or reject an incoming mail.
</p>
<p>
MTAs analyze the SPF information of the domain in the sender&apos;s<br />
mail address (e.g. <code>@example.net</code>).<br />
The SPF information is stored in a TXT record of the domain.<br />
This record specifies the IP addresses that are allowed to transfer mail<br />
where the sender&apos;s mail address ends with <code>@example.net</code>.<br />
<code>~all</code> means that other MTAs should treat a mail with a sender&apos;s<br />
mail address <code>@example.net</code> from all other IP addresses as spam.
<p>

<h4 id="domain_rdns">rDNS</h4>
<p>
When communicating with other MTAs, it is common that the IP address of<br />
the connecting MTA is checked by doing a reverse DNS lookup.<br />
If <code>mail.example.net</code> resolves to <code>192.0.2.1</code>, it is expected that<br />
a reverse DNS lookup of <code>192.0.2.1</code> gives <code>mail.example.net</code>.<br />
Same applies for the IPv6 address.
</p>

<h4 id="domain_checkmx">Check MX Record</h4>
<p>
The MX record of a domain can be checked using online tools:<br />
<a href="https://mxtoolbox.com/MXLookup.aspx" target="_blank">
https://mxtoolbox.com/MXLookup.aspx</a>
</p>

<h3 id="conf">Basic Configuration</h3>

<h4 id="conf_dpkg-reconfigure">dpkg-reconfigure</h4>
<p>
Execute the following command to reconfigure the installed Exim package:
</p>
<pre><code class="language-bash">dpkg-reconfigure exim4-config</code></pre>
<p>
The following questions will be asked:
</p>
<ol>
<li>General type of mail configuration:<br />
<code>internet site; mail is sent and received directly using SMTP</code></li>
<li>System mail name:<br />
<code>example.net</code></li>
<li>IP-addresses to listen on for incoming SMTP connections:<br />
<code>127.0.0.1 ; ::1 ; 192.0.2.1 ; 2001:db8:10::1</code></li>
<li>Other destinations for which mail is accepted:<br />
<code>example.net ; local-hostname</code></li>
<li>Domains to relay mail for:<br />
(leave empty)</li>
<li>Machines to relay mail for:<br />
(leave empty)</li>
<li>Keep number of DNS-queries minimal (Dial-on-Demand)?<br />
<code>No</code></li>
<li>Delivery method for local mail:<br />
<code>Maildir format in home directory</code></li>
<li>Split configuration into small files?<br />
<code>Yes</code></li>
</ol>
<p>
Answering these questions edits the following file:
</p>
<dl class="file">
<dt><code class="filename">/etc/exim4/update-exim4.conf.conf</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">#...
# This is a Debian specific file

dc_eximconfig_configtype='internet'
dc_other_hostnames='example.net ; local-hostname'
dc_local_interfaces='127.0.0.1 ; ::1 ; 192.0.2.1 ; 2001:db8:10::1'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname=''
dc_mailname_in_oh='true'
dc_localdelivery='maildir_home'
</code></pre>
</dd>
</dl>
<p>
Afterwards, <code>update-exim4.conf</code> is called to update the configuration files.
</p>

<h4 id="conf_hostname">Hostname</h4>
<p>
When another MTA connects, the hostname in the SMTP greeting is expected to<br />
match the DNS record.<br />
This can be achieved by setting the hostname of the system or by specifying<br />
the hostname in a configuration file:
</p>
<dl class="file">
<dt><code class="filename">/etc/exim4/conf.d/main/00_exim4-config_localmacros</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">MAIN_HARDCODE_PRIMARY_HOSTNAME = mail.example.net
</code></pre>
</dd>
</dl>

<h4 id="conf_aliases">Aliases</h4>
<p>
In the following example, mail for <code>root</code> is forwarded to <code>johndoe</code>:
</p>
<dl class="file">
<dt><code class="filename">/etc/aliases</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">root: johndoe
</code></pre>
</dd>
</dl>
<p>
To reload the aliases:
</p>
<pre><code class="language-bash">newaliases</code></pre>

<h4 id="conf_testlocal">Test Local Delivery</h4>
<p>
Send a mail to <code>johndoe</code> on the local system to see if the delivery<br />
of mails work:
</p>
<pre><code class="language-bash">echo "This is a simple test." | mail johndoe@example.net -s "Test"</code></pre>
<p>
The mail is expected to be delivered into the directory <code>/home/johndoe/Maildir/new/</code>.
</p>

<h4 id="conf_testremote">Test Remote Connectivity</h4>
<p>
Connect to the MTA from a remote host:
</p>
<pre><code class="language-bash">telnet mail.example.net 25</code></pre>
<p>
The SMTP greeting is expected to be shown.
</p>

<h3 id="tls">SSL/TLS Encryption</h3>
<p>
The used SSL/TLS certificate has to include <code>mail.example.net</code>.
</p>

<h4 id="tls_config">Configuration</h4>
<p>
To enable STARTTLS on port 25 and SSL/TLS on port 465, add the following lines:
</p>
<dl class="file">
<dt><code class="filename">/etc/exim4/conf.d/main/00_exim4-config_localmacros</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">MAIN_TLS_ENABLE = yes
MAIN_TLS_CERTIFICATE = /etc/letsencrypt/live/example.net/fullchain.pem
MAIN_TLS_PRIVATEKEY = /etc/letsencrypt/live/example.net/privkey.pem

daemon_smtp_ports = 25 : 465
tls_on_connect_ports = 465
</code></pre>
</dd>
</dl>
<p>
Further information can be found in
<code class="filename">/usr/share/doc/exim4-base/README.Debian.gz</code>.
</p>

<h4 id="tls_letsencrypt">Let&apos;s Encrypt</h4>
<p>
<code>certbot</code> installs TLS/SSL certificates from Let&apos;s Encrypt an a way<br />
that only <code>root</code> can read them.
</p>
<p>
If Exim cannot read the certificate, there is a message in the log file<br />
that looks like this:
</p>
<dl class="file">
<dt><code class="filename">/var/log/exim4/mainlog</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">2020-01-02 12:12:12 TLS error on connection from mail.other-mta.net [212.212.212.212]
  (cert/key setup: cert=/etc/letsencrypt/live/example.net/fullchain.pem key=/etc/letsencrypt/live/example.net/privkey.pem):
  Error while reading file.
</code></pre>
</dd>
</dl>
<p>
Exim runs as user <code>Debian-exim</code>. Add this user to the group <code>ssl-cert</code>:
</p>
<pre><code class="language-bash">usermod -a -G ssl-cert Debian-exim</code></pre>
<p>
Allow users in the group <code>ssl-cert</code> to access the certificates:
</p>
<pre><code class="language-bash">chgrp ssl-cert /etc/letsencrypt/live /etc/letsencrypt/archive
chmod g+rx /etc/letsencrypt/live /etc/letsencrypt/archive
chgrp -R ssl-cert /etc/letsencrypt/archive
chmod -R g+r /etc/letsencrypt/archive
</code></pre>
<p>
Let&apos;s Encrypt certificates are valid for 90 days.<br />
<code>certbot</code> renews expired certificates automatically.<br />
Exim needs to reload the configuration after the certificate has been renewed.<br />
This is done automatically by placing an executable script as renewal hook:
</p>
<dl class="file">
<dt><code class="filename">/etc/letsencrypt/renewal-hooks/deploy/reload_exim4.sh</code></dt>
<dd>
<pre class="file"><code class="language-bash">#!/bin/sh
systemctl reload exim4.service
</code></pre>
</dd>
</dl>

<h4 id="tls_testencrypt">Test Encryption</h4>
<p>
If SSL/TLS encryption works on port 465, the SMTP greeting should be shown<br />
when executing the following command:
</p>
<pre><code class="language-bash">openssl s_client -connect mail.example.net:465</code></pre>

<h3 id="auth">Authentication</h3>
<p>
Without authentication, the MTA does not accept mail for a destination<br />
that is not specified in the configuration files.<br />
A mail client needs to be authenticated so that the MTA accepts and<br />
relays mail to any destination.
</p>

<h4 id="auth_config">Configuration</h4>
<p>
A configuration for PLAIN authentication is found in a comment in<br />
<code class="filename">/etc/exim4/conf.d/auth/30_exim4-config_examples</code>.
</p>
<p>
This configuration is written into a new file:
</p>
<dl class="file">
<dt><code class="filename">/etc/exim4/conf.d/auth/30_exim4-config_plain</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">plain_server:
  driver = plaintext
  public_name = PLAIN
  server_condition = "${if crypteq{$auth3}{${extract{1}{:}{${lookup{$auth2}lsearch{CONFDIR/passwd}{$value}{*:*}}}}}{1}{0}}"
  server_set_id = $auth2
  server_prompts = :
  .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS
  server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}}
  .endif
</code></pre>
</dd>
</dl>

<h4 id="auth_accounts">Accounts</h4>
<p>
Usernames and passwords for Exim are specified with the following syntax:
</p>
<dl class="file">
<dt><code class="filename">/etc/exim4/passwd</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">username:crypted-password:(clear-password)
</code></pre>
</dd>
</dl>
<p>
To crypt a password use the command line tool <code>mkpassd</code>.<br />
It is part of the <code>whois</code> package.
</p>
<p>
Ensure that only Exim can read the accounts:
</p>
<pre><code class="language-bash">chown root:Debian-exim /etc/exim4/passwd
chmod 640 /etc/exim4/passwd
</code></pre>
<p>
Further information can be found in the corresponding manual page:
</p>
<pre><code class="language-bash">man exim4_passwd</code></pre>

<h3 id="dkim">DKIM</h3>
<p>
DomainKeys Identified Mail (DKIM) means that the domain of a mail can be<br />
verified. The MTA signs outgoing mails using a private key specific for DKIM.<br />
The public key is published in a TXT record of the domain.
</p>
<p>
If the key pair is updated, the old public key should still be available<br />
on DNS servers to verify old mails. The selector determines the used key.
</p>

<h4 id="dkim_genkey">Generate Key</h4>
<p>
For DKIM, 1024-bit RSA keys are common.<br />
The following commands generate a 1024-bit RSA key and allow Exim to access<br />
the private key:
</p>
<pre><code class="language-bash">mkdir -p /etc/exim4/dkim/example.net
cd /etc/exim4/dkim/example.net
openssl genrsa -out privkey.pem 1024
chgrp Debian-exim privkey.pem
chmod g+r privkey.pem
</code></pre>

<h4 id="dkim_config">Configuration</h4>
<p>
In the following example, the date when the key was created (<code>20200423</code>) is used<br />
as selector. To enable DKIM, add the following lines:
</p>
<dl class="file">
<dt><code class="filename">00_exim4-config_localmacros</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">DKIM_DOMAIN = example.net
DKIM_SELECTOR = 20200423
DKIM_PRIVATE_KEY = /etc/exim4/dkim/example.net/privkey.pem
</code></pre>
</dd>
</dl>

<h4 id="dkim_pubkey">Publish Public Key</h4>
<p>
The following command shows the public key:
</p>
<pre><code class="language-bash">openssl rsa -in /etc/exim4/dkim/example.net/privkey.pem -pubout</code></pre>
<p>
This public key is published in a TXT record of the domain.<br />
Ensure that the selector <code>20200423</code> matches the selector in the config.
</p>
<pre class="file"><code class="language-dns">20200423._domainkey  IN  TXT  "k=rsa; p=MIGfMA0G...QQIDAQAB"
</code></pre>

<h3 id="links">External Links for further Information</h3>
<ul>
<li><a href="https://www.exim.org/" target="_blank">
https://www.exim.org/</a></li>
<li><a href="https://tools.ietf.org/html/rfc7208" target="_blank">
https://tools.ietf.org/html/rfc7208</a></li>
<li><a href="https://tools.ietf.org/html/rfc6376" target="_blank">
https://tools.ietf.org/html/rfc6376</a></li>
<li><a href="https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html" target="_blank">
https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html</a></li>
<li><a href="https://debian-administration.org/article/718/DKIM-signing_outgoing_mail_with_exim4" target="_blank">
https://debian-administration.org/article/718/DKIM-signing_outgoing_mail_with_exim4</a></li>
</ul>