How To: Install an E-Mail Server on Fedora 40
PostgreSQL will be used to store data about mailboxes and aliases.
OpenDKIM
sudo dnf install opendkim opendkim-tools
In file /etc/opendkim.conf
set the domain and the mode to sign and
verify :
Domain example.org
Mode sv
Generate the signing key for the domain:
cd /etc/opendkim/keys
sudo opendkim-genkey -d example.org
sudo chown opendkim:opendkim /etc/opendkim/keys/*
Start the OpenDKIM service and make it start with the system:
sudo systemctl enable --now opendkim
DNS
Create the following record, replacingGET_ME_FROM_DEFAULTTXT
by what comes after p=
in
/etc/opendkim/keys/default.txt
:
default._domainkey.example.org. 1 IN TXT "v=DKIM1;t=s;h=sha256;k=rsa;p=GET_ME_FROM_DEFAULTTXT"
SpamAssassin
sudo dnf install spamassassin
sudo systemctl enable --now spamassassin
sudo useradd -d /var/spool/spamassassin -s /bin/false spamassassin
Postfix
DNS
Create those records in your zone:
smtp.example.org. 1 IN CNAME server1.example.org.
example.org. 1 IN MX 100 smtp.example.org.
default._bimi.example.org. 1 IN TXT "v=BIMI1;l=https://www.example.org/images/logo.svg"
_dmarc.example.org. 1 IN TXT "v=DMARC1; p=reject; rua=mailto:postmaster@example.org;"
The BIMI record is used to display a brand logo in Gmail and other e-mail clients.
Thev=spf1 mx -all
SPF record will ensure that no server can send email from your domain except the
ones
in your domain's MX records:
example.org. 1 IN TXT "v=spf1 mx -all"
TLS Certificate
sudo certbot certonly --nginx -d smtp.example.org
Configuration
Install the postfix packages:
sudo dnf install postfix postfix-pgsql
Create the user and the directories which will contain the actual email data:
useradd -d /var/mail -U -u 5000 vmail
mkdir -p /var/mail/vmail/example.org
chown -R vmail:vmail /var/mail/vmail
Set up the database:
sudo -u postgres psql
CREATE DATABASE postfix;
USE postfix;
CREATE TABLE addresses (email VARCHAR(50) NOT NULL PRIMARY KEY, active BOOLEAN NOT NULL DEFAULT true, passwd
VARCHAR(106) NOT NULL);
CREATE TABLE aliases (source VARCHAR(50) NOT NULL PRIMARY KEY, target VARCHAR(50) NOT NULL);
CREATE USER postfix WITH ENCRYPTED PASSWORD '';
GRANT SELECT ON public.addresses TO postfix;
GRANT SELECT ON public.aliases TO postfix;
INSERT INTO public.addresses (email, active, passwd) VALUES ('postmaster@example.org', true, 'mygreatpassword');
Create file /etc/postfix/pgsql_mailboxes.cf
:
user = postfix
password =
hosts = 127.0.0.1
dbname = postfix
query = SELECT 1 FROM addresses WHERE email = '%s'
Create file /etc/postfix/pgsql_aliases.cf`
:
user = postfix
password =
hosts = 127.0.0.1
dbname = postfix
query = SELECT 1 FROM aliases WHERE source = '%s'
Edit file /etc/postfix/main.cf
:
myhostname = server1.example.org
mydomain = example.org
mydestination = localhost.$mydomain, localhost
inet_interfaces = all
smtpd_tls_cert_file = /etc/letsencrypt/live/smtp.example.org/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/smtp.example.org/privkey.pem
virtual_mailbox_base = /var/mail/vmail
virtual_mailbox_domains = example.org
virtual_mailbox_maps = pgsql:/etc/postfix/pgsql_mailboxes.cf
virtual_alias_maps = pgsql:/etc/postfix/pgsql_aliases.cf
virtual_gid_maps = static:5000
virtual_uid_maps = static:5000
virtual_minimum_uid = 5000
virtual_transport = lmtp:unix:private/dovecot-lmtp
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
milter_default_action = accept
milter_protocol = 2
smtpd_milters = unix:/run/opendkim/opendkim.sock
non_smtpd_milters = unix:/run/opendkim/opendkim.sock
In file /etc/postfix/master.cnf
,
uncomment smtp, submission and submissions and their arguments (beware not to uncomment actual comments about the configuration!).
Then, add as an argument to service smtp
:
-o content_filter=spamassassin
Then, add a new service:
spamassassin unix - n n - - pipe user=spamassassin argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
Start the postfix systemd service and make it start with the system:
systemctl enable --now postfix
Dovecot
DNS
imap.example.org. 1 IN CNAME server1.example.org.
TLS Certificate
sudo certbot certonly --nginx -d imap.example.org
Configuration
sudo dnf install dovecot dovecot-pgsql dovecot-pigeonhole
openssl dhparam -out /etc/dovecot/dh.pem 4096
Edit file /etc/dovecot/dovecot.conf
:
protocols = imap pop3 lmtp
Edit file /etc/dovecot/conf.d/10-mail.conf
:
mail_location = maildir:/var/mail/vmail/%d/%n
mail_uid = 5000
mail_gid = 5000
mail_privileged_group = vmail
Edit file /etc/dovecot/conf.d/15-lda.conf
:
postmaster_address = postmaster@example.org
protocol lda {
# Space separated list of plugins to load (default is global mail_plugins).
mail_plugins = $mail_plugins sieve
}
Edit file /etc/dovecot/conf.d/20-lmtp.conf
:
protocol lmtp {
# Space separated list of plugins to load (default is global mail_plugins).
mail_plugins = $mail_plugins sieve
postmaster_address = postmaster@example.org
}
Edit file /etc/dovecot/conf.d/10-master.conf
:
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service auth {
#unix_listener auth-userdb {
# #mode = 0666
# #user =
# #group =
#}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
}
}
Create file /etc/dovecot/conf.d/10-ssl.conf
with contents:
ssl_cert = </etc/letsencrypt/live/imap.example.org/fullchain.pem
ssl_key = </etc/letsencrypt/live/imap.example.org/privkey.pem
ssl_dh = </etc/dovecot/dh.pem
Create file /etc/dovecot/conf.d/10-auth.conf
with contents:
#!include auth-system.conf.ext
!include auth-sql.conf.ext
Create file /etc/dovecot/dovecot-sql.conf.ext
with contents:
driver = postgres
connect = host=127.0.0.1 dbname=postfix user=postfix password=
default_pass_scheme = PLAIN
password_query = \
SELECT email as username, passwd AS password FROM addresses WHERE email = '%u'
user_query = \
SELECT 5000 AS uid, 5000 as gid, email, '/var/mail/vmail/%d/%n' AS home \
FROM addresses WHERE email = '%u'
iterate_query = SELECT email AS user FROM addresses
Start the dovecot systemd service and make it start with the system:
systemctl enable --now dovecot
Setting up Thunderbird Autoconfig
DNS
Create the following record in your DNS zone:
autoconfig.example.org. 1 IN CNAME server1.example.org.
Issue a new Let's Encrypt TLS certificate:
sudo certbot certonly --nginx -d autoconfig.example.org
Create file: /etc/nginx/conf.d/autoconfig.example.org.conf
with the
following contents:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name autoconfig.example.org;
# SSL
ssl_certificate /etc/letsencrypt/live/autoconfig.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/autoconfig.example.org/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/autoconfig.example.org/chain.pem;
# logging
access_log /var/log/nginx/access.log combined buffer=512k flush=1m;
error_log /var/log/nginx/error.log warn;
root /var/www/autoconfig.example.org;
include sts;
}
# HTTP redirect
server {
listen 80;
listen [::]:80;
server_name autoconfig.example.org;
location / {
return 301 https://autoconfig.example.org/$request_uri;
}
}
Create file: /var/www/autoconfig.example.org/mail/config-v1.1.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">
<emailProvider id="example.org">
<domain>example.org</domain>
<displayName>example.org mail service</displayName>
<displayShortName>example.org mail service</displayShortName>
<incomingServer type="imap">
<hostname>imap.example.org</hostname>
<port>993</port>
<socketType>SSL</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</incomingServer>
<outgoingServer type="smtp">
<hostname>smtp.example.org</hostname>
<port>465</port>
<socketType>SSL</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</outgoingServer>
</emailProvider>
</clientConfig>
Reload NGINX's configuration with:
sudo systemctl reload nginx