Configure OpenSMTPD (with Maildir)
This guide provides a sample configuration of OpenSMTPd using Maildir. 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 and placed in ~/Maildir/.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 and placed in ~/Maildir/.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 smtpd(8) to use the
public/private keys defined earlier for example.com
. It optionally allows
authentication using normal login credentials present in the
master.passwd(5) file, for users that want
to send email to an external server using port 25. When relaying mail to an
external server, it is important to require authentication to avoid configuring
an open mail relay by mistake. New users can be created
with adduser(8) and passwords can be
modified with passwd(1).
senders <users>
checks if the user is allowed to send email as the
specified user by consulting the users table stored in /etc/mail/users
.
mask-src
masks the sender's source (the from part of the Received
header) for privacy. filter { check_rdns check_fcrdns }
then checks for
properly matching forward and reverse DNS entries.
Finally, hostname example.com
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. It also does not check forward and reverse DNS. This is because authentication already ensures the user is trusted, and the user may be sending email from a residential IP address without proper DNS records.
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 $optional listen on $ipv6 port 25 tls $optional listen on $ipv4 port 465 smtps $required listen on $ipv6 port 465 smtps $required listen on $ipv4 port 587 tls-require $required listen on $ipv6 port 587 tls-require $required
Line 2 tells smtpd(8) to listen to the unix(4) domain socket and to sign all mail with DKIM. Line 3 tells us to listen to the loopback interface and also sign all emails.
Lines 4-5 tells smtpd(8) to listen on port 25 on the IPv4 and IPv6 addresses defined by the earlier macros. TLS will be provided if the client supports it, but plaintext will be offered as a fallback. Authentication is optionally offered if the client wants to relay mail to an external server.
Lines 6-7 tells smtpd(8) to listen on port 465 on the IPv4 and IPv6 addresses defined in the macros using SMTPS. TLS encryption is required and authentication checking is forced. These sockets will be used for relaying mail to external servers.
Lines 8-9 are similar except they are 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 "maildir" maildir "%{user.directory}/Maildir" junk alias <aliases> action "outbound" relay src <hosts> match from any for domain <domains> action "maildir" match from local for any action "outbound" match auth from any for any action "outbound"
Line 2 defines the action "maildir"
: mail destined for our domains (what is
listed in /etc/mail/domains
) will be delivered to the user's ~/Maildir
folder.
Line 3 defines the action "outbound"
: outbound mail is relayed (sent) to
external mail servers.
Line 4 defines the first matching rule: any email headed for one of our domains
will be handed over to the action "maildir"
.
Line 5 defines the second matching rule: any email from a local IP address or queue can relay (send) without authentication. This guide assumes all users on localhost are trusted senders.
Line 6 defines the 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.crt" pki example.com key "/etc/ssl/private/example.com.key" # 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 # 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::" 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" # listeners listen on socket filter "dkimsign" listen on lo0 filter "dkimsign" listen on $ipv4 port 25 tls $optional listen on $ipv6 port 25 tls $optional listen on $ipv4 port 465 smtps $required listen on $ipv6 port 465 smtps $required listen on $ipv4 port 587 tls-require $required listen on $ipv6 port 587 tls-require $required # rules action "maildir" maildir "%{user.directory}/Maildir" junk alias <aliases> action "outbound" relay src <hosts> match from any for domain <domains> action "maildir" match from local for any action "outbound" match auth from any for any action "outbound"
Adding users
For each new user, add a line such as the following in /etc/mail/aliases:
username: username
To handle email forwarding, add this line:
username: username@example.com
You can ensure any mail sent to root gets forwarded to your username and external email address:
root: username, username@example.com
Now, any mail sent to root will get forwarded to username
's Maildir and
also to username@example.com
NOTE: Make sure to check the mail account linked to root often! daily(8) and other programs send mails to root.
One line must be created for each user in /etc/mail/users
:
username: username@example.com
The mail server's public IP addresses which are used to send email go 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.
example.com
WARNING: It is essential for the mail server name to match the forward and reverse DNS entries to pass anti-spam checks.
The list of domains this mail server can receive mail for go inside
/etc/mail/domains
:
example.com mail.example.com
Authentication is handled by normal login credentials. Most likely, this means passwords can be set with passwd(1):
$ passwd $USERNAME
WARNING: Special characters such as $
, when used in passwords, may
cause issues with your mail client or with OpenSMTPd. To avoid this problem,
consider using only alphanumeric characters for your password. To improve
security, increase the length of the password.
IMAP and POP3 via dovecot
It is possible to offer POP and IMAP service by installing dovecot and configuring OpenSMTPd to use LMTP. POP and IMAP makes it much more convenient for average users to access email from computers and phones.
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.