OpenSMTPD

Related articles
Mail server
OpenSMTPD
is a free
mail transfer agent
, developed as part of the OpenBSD project. This article builds upon
Mail server
.
Installation
Install
the
opensmtpd
package.
Configuration
OpenSMTPD is configured in
/etc/smtpd/
. The main configuration file is
/etc/smtpd/smtpd.conf
; see
smtpd.conf(5)
for its documentation.
Make sure to test the configuration using:
# smtpd -n
If you get a message that says
configuration OK
—you are ready to
start
or
restart
smtpd.service
. If not, work on any configuration errors and try again.
Local mail
To have local mail working, for example for
cron
mails, it is enough to simply
start
smtpd.service
.
The default configuration of OpenSMTPD is to do local retrieval and delivery of mail to
Maildir
, and also relay outgoing mail. See
smtpd.conf(5)
.
Local mail only
To do only local mail, the following is enough:
/etc/smtpd/smtpd.conf
listen on localhost
action "local" maildir alias <aliases>
match for local action "local"
Hybrid : local mail and relay
These two lines in
/etc/smtpd/smtpd.conf
:
action "local" maildir alias <aliases>
action "relay" relay host "smtps://smtp.example.net" mail-from "@example.net"
match for local action "local"
match for any action "relay"
configure OpenSMTPD to:
send local email
locally
, without going through a relay (useful for cron & at mail notifications)
use a relay to send a mail outside of localhost
Simply replace
smtp.example.net
by your ISP mail server, or another server at your convenience.
Relay only
To send all local emails through a relay invoke
procmail
:
/etc/smtpd/smtpd.conf
action "local" mda "procmail -f -" virtual <aliases>
action "relay" relay host "smtps://label@smtp.example.net" auth <secrets> mail-from "@example.net"
match for local action "local"
match for any action "relay"
The aliases option is used for the local user mapping, for a simplified mapping you can use virtual aliases with a catch all:
/etc/smtpd/aliases
@ user@example.net
/var/spool/mail/
OpenSMTPD 6.6.3p1
changed the default local mail configuration to use
maildir
in
~/Maildir/
instead of
mbox
in
/var/spool/mail/
username
to avoid security issues.
To have your local mails go to the
/var/spool/mail/
username
instead, replace
action "local" maildir alias <aliases>
with
action "local" maildir
"/var/spool/mail/%{user.username}"
alias <aliases>
in
/etc/smtpd/smtpd.conf
.
Alternatively, set the
MAIL
environment variable
, that is understood by most email clients, to point to
~/Maildir/
. E.g.:
export MAIL="${HOME}/Maildir/"
Simple OpenSMTPD/maildir configuration
TLS
To obtain a certificate, see
OpenSSL#Usage
.
Note
OpenSMTPD has solid defaults, SSLv3 is always disabled and the default
ciphers
are not known to be insecure. You might still want to test the server as described in
Server-side TLS
.
Create user accounts
Create a user account on the mail server for each desired mailbox.
# useradd -m roger
# useradd -m shirley
OpenSMTPD will deliver messages to the user account's maildir in
/var/spool/mail/
username
/
Multiple SMTP email addresses can be routed to a given maildir if desired.
Craft a simple smtpd.conf setup
A working configuration can be had in as little as nine lines:
/etc/smtpd/smtpd.conf
pki mx.domain.example cert         "/etc/smtpd/tls/smtpd.crt"
pki mx.domain.example key          "/etc/smtpd/tls/smtpd.key"

table creds file:/etc/smtpd/creds
table vdoms file:/etc/smtpd/vdoms
table vusers file:/etc/smtpd/vusers

listen on eth0 tls pki mx.domain.example
listen on eth0 port 465 smtps pki mx.domain.example auth <creds>
listen on eth0 port 587 tls-require pki mx.domain.example auth <creds>

action "receive" maildir "/var/spool/mail/%{user.username}" virtual <vusers>
action "send" relay

match from any for domain <vdoms> action "receive"
match for any action "send"
Create tables
For the domain table file; simply put one domain per line:
/etc/smtpd/vdoms
example.org
example.com
For the user table file; list one inbound SMTP email address per line and then map it to an maildir user account name, SMTP email address, or any combination of the two on the right, separated by commas.
/etc/smtpd/vusers
roger@example.org          roger
newsletters@example.org    roger,roger.rulz@mail.example

roger@example.com          roger
shirley@example.com        shirley
info@example.com           roger,shirley
contact@example.com        info@example.com
For the creds table file; put the user name in the 1st column and the password hash in the 2nd column
/etc/smtpd/creds
roger
password_hash_created_using_'smtpctl encrypt'_command
shirley
password_hash_created_using_'smtpctl encrypt'_command
DKIM
To sign messages with
DomainKeys Identified Mail
(DKIM), install
opensmtpd-filter-dkimsign
.
filter-dkimsign(8)
supports RSA and Ed25519 keys. While
RFC 8463
requires for verifiers to support Ed25519, not all of them do, so it may be best to use both Ed25519 and RSA.
Create private keys for DKIM
Create a directory for storing the keys:
# install -dm750 -g smtpd /etc/smtpd/dkim
Create private keys using
OpenSSL
.
Ed25519:
# openssl genpkey -algorithm ed25519 -out /etc/smtpd/dkim/dkim_ed25519.key
RFC 8301
mandates support for RSA keys ranging from 1024 bits to 4096 bits, so create a 4096 bit RSA key:
# openssl genrsa -out /etc/smtpd/dkim/dkim_rsa4096.key 4096
Change the
file permissions
so that
filter-dkimsign
, which runs with the
smtpd
user and group permissions, can access it:
# chown root:smtpd /etc/smtpd/dkim/dkim_*.key
# chmod 640 /etc/smtpd/dkim/dkim_*.key
Prepare DNS records
DKIM uses a TXT record with the domain name
selector
._domainkey.
domainname
, e.g.
selector1._domainkey.mydomain.example
. See
Wikipedia:DomainKeys Identified Mail#Verification
for more details. The following example will use
selector1._domainkey.domain.example
for the Ed25519 key and
selector2._domainkey.domain.example
for RSA.
Use the following commands to get DNS record values from the public keys
[1]
:
# openssl pkey -in /etc/smtpd/dkim/dkim_ed25519.key -pubout | openssl asn1parse -offset 12 -noout -out /dev/stdout | openssl base64 | sed '1s/^/v=DKIM1;h=sha256;k=ed25519;p=/'
# openssl pkey -in /etc/smtpd/dkim/dkim_rsa4096.key -pubout | sed '1s/.*/v=DKIM1;h=sha256;k=rsa;p=/;:nl;${s/-----.*//;q;};N;s/\n//g;b nl;'
Update you DNS records using these values.
Configure filter-dkimsign
Define the filters in
/etc/smtpd/smtpd.conf
and add the filter chain to all
listen
directives. Replace
mydomain.example
with your domain name and
selector1
and
selector2
with the
_domainkey
selectors matching with your DNS records.
/etc/smtpd/smtpd.conf
...
filter "dkimsign_ed25519" proc-exec "filter-dkimsign -t -a ed25519-sha256 -d mydomain.example -s selector1 -k /etc/smtpd/dkim/dkim_ed25519.key"
filter "dkimsign_rsa4096" proc-exec "filter-dkimsign -t -a rsa-sha256 -d mydomain.example -s selector2 -k /etc/smtpd/dkim/dkim_rsa4096.key"
filter "dkimsign" chain { "dkimsign_ed25519", "dkimsign_rsa4096" }
...
listen on mydomain.example port 465 smtps
filter "dkimsign"
listen on socket
filter "dkimsign"
...
Tip
listen on socket
is enabled by default and typically does not need to be added manually, but in this case it needs to be added so that the filter can be applied to it.
Troubleshooting
Console debugging
If you are having problems with mail delivery, try
stopping
the
smtpd.service
and launching the daemon manually with the "do not daemonize" and "verbose output" options. Then watch the console for errors.
# smtpd -dv
Subsystem tracing
Add the
-T
flag to get real-time subsystem tracing
# smtpd -dv -T smtp
Alternately, use the
smtpctl trace
subsystem
command if the daemon is already running. The trace output will appear in the console output above as well as the
journalctl
output for the smtpd.service. For example:
# smtpctl trace expand && smtpctl trace lookup
...will trace both aliases/virtual/forward expansion and user/credentials lookups.
Manual Submission port authentication
Encode username and password in base64
$ printf '\0%s\0%s' 'username' 'password' | base64
Connect to submission port using
openssl s_client
command, using one of the following commands:
To connect via port 465 (implicit TLS):
$ openssl s_client -host mx.domain.example -port 465
To connect via port 587 (STARTTLS):
$ openssl s_client -host mx.domain.example -port 587 -starttls smtp
Enter
EHLO
myhostname
followed by
AUTH PLAIN
. Paste in the base64 string from step above after
334
response:
250 HELP
EHLO test.domain.example
250-mx.hostname.example Hello test.domain.example [127.0.0.1], pleased to meet you
250-8BITMIME
250-ENHANCEDSTATUSCODES
250-SIZE 36700160
250-DSN
250-AUTH PLAIN LOGIN
250 HELP
AUTH PLAIN
334 
dXNlcm5hbWUAdXNlcm5hbWUAcGFzc3dvcmQ=
235 2.0.0: Authentication succeeded
"Helo command rejected: need fully-qualified hostname"
When sending email, if you get this kind of messages, set your FQDN in the file
/etc/smtpd/mailname
. Otherwise, the server name is derived from the local
hostname
returned by
gethostname(3p)
, either directly if it is a fully qualified domain name, or by retrieving the associated canonical name through
getaddrinfo(3)
.
System users authentication failure
If you are using the system users and the authentication with valid credentials fails, you have to configure
PAM
:
/etc/pam.d/smtpd
auth required pam_unix.so
account required pam_unix.so
password required pam_unix.so
session required pam_unix.so
See also
Wikipedia:OpenSMTPD
OpenSMTPD pairs well with
Dovecot
. Combine the two for a nice minimalist mailserver
OpenSMTPD project page
Simple SMTP server with OpenSMTPD