Configure OpenSMTPD (with LMTP)
This guide provides a sample configuration of OpenSMTPd using LMTP. This guide does not configure DNS records for mail. Specifically, SPF, DKIM, and DMARC configuration is covered in another guide.
Before we begin
Running a mail server requires proper DNS. Before configuring mail, make sure you understand how DNS works. This guide assumes you are running your own nsd server to provide DNS records for mail.
There is also the free OpenSMTPd book by one of the authors of OpenSMTPd.
Install
OpenBSD base includes smtpd(8) as part of the base system. Some related software, however must be installed from packages for this setup:
# pkg_add opensmtpd-table-passwd opensmtpd-filter-dkimsign--
Read the dkimsign filter README at
/usr/local/share/doc/pkg-readmes/opensmtpd-filter-dkimsign
.
Configuration
TLS
Use acme-client to request a TLS public cert and
private key in /etc/ssl/
.
Next, overwrite the default
smtpd.conf(5); replace the file in
the default /etc/mail/smtpd.conf
with a new configuration:
# PKI for TLS pki example.com cert "/etc/ssl/example.com.crt" pki example.com key "/etc/ssl/private/example.com.key"
This defines our public and private key pair for TLS encryption.
Tables
Next, we define 5 tables:
# tables setup table domains file:/etc/mail/domains table aliases file:/etc/mail/aliases table hosts file:/etc/mail/hosts table users file:/etc/mail/users
The domains
table contains a list of domains that our mail server should
receive mail on.
Note: Do not add domains that your mail server does not directly serve (for example, do not add domains you intend to forward mail to). If you add them by mistake, the mail server will not forward the mail properly.
The aliases(5) file helps handle mail
forwarding. It is written using key: value
pairs.
The hosts
file contains a list of IP addresses that this current host will
send email from.
The users
file contains a list of valid sending users.
All these tables will be explained further in the following sections.
Dealing with Spam
# Blocks junk mail filter check_rdns phase connect match !rdns junk filter check_fcrdns phase connect match !fcrdns junk filter "dkimsign" proc-exec "filter-dkimsign -d example.com -s mail -k /etc/mail/dkim/private.key" user _dkimsign group _dkimsign
The first filter will check if the sender has an rdns entry. If not, the mail will be labeled as junk.
The second filter will check if the sender's forward and reverse dns entry match. If not, the mail will be labeled as junk.
The third filter will sign outgoing email with the DKIM private key.
- -d specifies the domain name to sign for; you must replace
example.com
with your real domain. - -s specifies the selector (in this case
mail
). - -k specifies the path of the private key.
- user and group both specify
_dkimsign
, the user and group that does the signing
Macros
A macro defines a variable that will be replaced with a block of text:
# macros ipv4 = "192.168.0.1" ipv6 = "2001:db8::" optional = "pki example.com auth-optional mask-src senders <users> filter { check_rdns check_fcrdns } hostname example.com" required = "pki example.com auth mask-src senders <users> filter { dkimsign } hostname example.com"
Lines 2 and 3 define the IPv4 and IPv6 addresses used that smtpd(8) will listen on, for receiving mail from other mail servers and from email clients.
Line 4 tells opensmtpd to use the public/private keys we defined earlier for example.com
. We mask the sender's source (the from part of the Received
header). We also apply two filters to check for proper forward and reverse confirmed DNS entries. Finally, we indicate that the sending hostname must be example.com instead of the default server name.
Line 5 is identical to line 4 except it requires authentication with the password file and it checks if the sender is allowed.
Listeners
The listeners tell us what network interfaces, IP addresses, and ports to listen on.
# listeners listen on socket filter "dkimsign" listen on lo0 filter "dkimsign" listen on $ipv4 port 25 tls $check listen on $ipv6 port 25 tls $check listen on $ipv4 port 465 smtps $authcheck listen on $ipv6 port 465 smtps $authcheck listen on $ipv4 port 587 tls-require $authcheck listen on $ipv6 port 587 tls-require $authcheck
Line 2 tells smtpd to listen to the UNIX domain socket and to DKIM sign all emails. Line 3 tells us to listen to the loopback interface and also sign all emails.
Lines 4-5 tells smtpd to listen on the IPv4 and IPv6 address on port 25, to provide TLS if supported but to offer plaintext as a fallback. Only basic checking is done.
Lines 6-7 tells smtpd to listen on the IPv4 and IPv6 address on port 465, for SMTPS. TLS encryption is required and authentication checking is forced because this socket can be used for sending mail to other servers. We want to avoid an open mail relay.
Lines 8-9 is similar except it's for port 587, which is the SMTP submission port.
Rules
Next we define the actions that opensmtpd can take and how to decide which action to follow:
# rules action "lmtp" lmtp "/var/dovecot/lmtp" rcpt-to virtual <virtuals> action "outbound" relay src $ipv4 match from any for domain <domains> action "lmtp" match from local for any action "outbound" match from src <hosts> for any action "outbound" match auth from any for any action "outbound"
In line 2, we define the action "lmtp": we pass the mail to dovecot to handle using the Local Mail Transfer Protocol (LMTP). The actual recipient will be translated using the virtuals table.
In line 3, we define the action "outbound": we relay (send) the email out.
Line 5 defines our first matching rule: any email headed for one of our domains should be handed over to lmtp (handed over to dovecot).
Line 6 defines our second matching rule: any email from a local IP address or queue can relay (send) without authentication.
Line 7 defines our third matching rule: any email from our trusted /etc/mail/hosts
file will automatically be relayed (sent) without authentication.
Line 8 defines our last matching rule: any email that has been properly authenticated will be relayed (sent).
Complete configuration file
Here is the entire configuration file in /etc/mail/smtpd.conf
:
# PKI for TLS pki example.com cert "/etc/ssl/example.com.fullchain.pem" pki example.com key "/etc/ssl/private/example.com.key" # tables setup table domains file:/etc/mail/domains table passwd passwd:/etc/mail/passwd table virtuals file:/etc/mail/virtuals table hosts file:/etc/mail/hosts table users file:/etc/mail/users # Blocks junk mail filter check_rdns phase connect match !rdns junk filter check_fcrdns phase connect match !fcrdns junk filter "dkimsign" proc-exec "filter-dkimsign -d example.com -s mail -k /etc/mail/dkim/private.key" user _dkimsign group _dkimsign # macros ipv4 = "192.168.0.1" ipv6 = "2001:db8::" check = "pki example.com mask-src filter { check_rdns check_fcrdns } hostname example.com" authcheck = "pki example.com auth <passwd> mask-src senders <users> filter { dkimsign } hostname example.com" # listeners listen on socket filter "dkimsign" listen on lo0 filter "dkimsign" listen on $ipv4 port 25 tls $check listen on $ipv6 port 25 tls $check listen on $ipv4 port 465 smtps $authcheck listen on $ipv6 port 465 smtps $authcheck listen on $ipv4 port 587 tls-require $authcheck listen on $ipv6 port 587 tls-require $authcheck # rules action "lmtp" lmtp "/var/dovecot/lmtp" rcpt-to virtual <virtuals> action "outbound" relay src $ipv4 match from any for domain <domains> action "lmtp" match from local for any action "outbound" match from src <hosts> for any action "outbound" match auth from any for any action "outbound"
Configuring Virtual Users
A single user vmail will receive mail for all virtual users:
$ doas useradd -m -g =uid -c "Virtual Mail" -d /var/vmail -s /sbin/nologin vmail
/var/vmail will be used to store virtual users' maildir folders. It will be managed by dovecot, which receives mail via LMTP.
Adding users
Create a new file /etc/mail/virtuals
and add these lines:
root admin@example.com admin@example.com vmail username@example.com vmail
Now, any mail sent to root will get forwarded to admin@example.com.
NOTE: Make sure to check the mail account linked to root often! daily(8) and other programs will send mails to root.
You can optionally add one line for each user to provide aliases.
For each new user account, you will want to create a new line.
You'll also need to create one line for each user in /etc/mail/users
:
admin@example.com: admin@example.com username@example.com: username@example.com
A whitelist of known good senders goes into /etc/mail/hosts
:
192.168.1.1 2001:db8::
Replace IP addresses 192.168.1.1 and 2001:db8:: with your server's real IP addresses.
In /etc/mail/mailname
, put in the name you want to use for your mail server. This
is very important for passing anti-spam checks:
example.com
The list of domains this mail server can receive emails for will go inside /etc/mail/domains
:
example.com mail.example.com
In /etc/mail/passwd
, we have a list of colon-separated user credentials:
admin@example.com:$2b$10$h5itbhzs73T4jsHAj9YX6Tf63yRatAquGBxoCX67wyekhCH4ZqioD6lKh::::::userdb_quota_rule=*:storage=1G username@example.com:$2b$10$h5itbhzs73T4jsHAj9YX6Tf63yRatAquGBxoCX67wyekhCH4ZqioD6lKh::::::userdb_quota_rule=*:storage=1G
Each field is separated with a colon.
The first field tells you the username. Note that usernames include a domain -- this is because you might host mail for multiple domains. So, when logging in to the mail server, your mail client must be of the format username@example.com.
The second field is the password hash. To generate a hash, you can run encrypt:
$ encrypt
Type your password, then press enter
. Type ctrl+d
to quit.
smtpctl encrypt
also does the same thing:
$ smtpctl encrypt
WARNING: Special characters like $, when used in passwords, may cause issues with your mail client or with opensmtpd. To be safe, you might want to use only alphanumeric characters for your password. You can increase the length of the password for more security.
The last field sets how much data storage each user is allowed. The default here is 1 gigabyte.
IMAP and POP3 via dovecot
To finish the setup, we need to install and configure dovecot.
DKIM signing
We will need to set up dkim to have the mail properly signed.
Troubleshooting OpenSMTPd
Make sure to troubleshoot OpenSMTPd after configuration to ensure that mail is being delivered properly and that no open mail relay exists.