FreeBSD.software
Home/Guides/OpenSMTPD on FreeBSD: Modern Mail Server Review
review·2026-04-09·11 min read

OpenSMTPD on FreeBSD: Modern Mail Server Review

Review of OpenSMTPD on FreeBSD: simple configuration, TLS setup, virtual users, spam filtering with rspamd, and comparison with Postfix and Sendmail.

OpenSMTPD on FreeBSD: Modern Mail Server Review

OpenSMTPD is a free, secure, and simple mail transfer agent developed as part of the OpenBSD project. It was designed from scratch to replace Sendmail with something that a competent sysadmin could configure in minutes rather than days. Where Postfix achieves security through modular process separation, and Sendmail achieves flexibility through a configuration language that borders on the occult, OpenSMTPD achieves both through a clean, human-readable configuration syntax and a conservative codebase that rejects complexity.

On FreeBSD, OpenSMTPD is available as a package and competes directly with Postfix for the role of MTA. This review covers OpenSMTPD's design philosophy, FreeBSD installation, TLS configuration, virtual user management, spam filtering with rspamd, and an honest comparison with Postfix and Sendmail for production mail serving.

OpenSMTPD Design Philosophy

OpenSMTPD was born from a simple observation: Sendmail's configuration is incomprehensible, Postfix's is sprawling, and both carry decades of accumulated complexity. The OpenBSD team wanted an MTA that:

  • Used a configuration file readable by humans without a manual
  • Handled the common cases (relay, local delivery, virtual domains) with minimal configuration
  • Was secure by default, with privilege separation and chroot
  • Maintained a small codebase that could be audited

The result is an MTA whose complete configuration for many deployments fits in 10-20 lines. This is not an exaggeration. A working relay configuration is five lines:

shell
listen on all tls pki mail.example.com action "relay" relay host smtp+tls://relay.example.com match from any for any action "relay"

That simplicity has tradeoffs. OpenSMTPD supports fewer features than Postfix. It does not have built-in content filtering, milter support is more recent and less tested, and some advanced routing scenarios require creative workarounds. For straightforward mail serving, those tradeoffs are worth it.

Installation on FreeBSD

From Packages

FreeBSD's base system includes Sendmail, but OpenSMTPD is available as a package:

sh
pkg install opensmtpd

Disable Sendmail first:

sh
# /etc/rc.conf sendmail_enable="NO" sendmail_submit_enable="NO" sendmail_outbound_enable="NO" sendmail_msp_queue_enable="NO"

Stop Sendmail:

sh
service sendmail stop

Enable OpenSMTPD:

sh
sysrc smtpd_enable="YES"

The configuration file is /usr/local/etc/mail/smtpd.conf. The binary is /usr/local/sbin/smtpd.

Verify Installation

sh
smtpd -n

This parses the configuration file and reports errors without starting the daemon. Always run this before restarting after a config change.

Basic Configuration

Local Delivery Only

The simplest useful configuration accepts mail for local users and stores it in their mailboxes:

sh
# /usr/local/etc/mail/smtpd.conf listen on localhost action "local" mbox alias <aliases> match for local action "local"

This listens on localhost only (no external mail), delivers to local users' mailboxes using the system alias table.

Full Mail Server Configuration

A production configuration that accepts mail for your domain, delivers locally, and relays outbound:

sh
# /usr/local/etc/mail/smtpd.conf # TLS certificates pki mail.example.com cert "/usr/local/etc/ssl/certs/mail.example.com.crt" pki mail.example.com key "/usr/local/etc/ssl/private/mail.example.com.key" # Tables table aliases file:/etc/mail/aliases table domains file:/usr/local/etc/mail/domains table virtuals file:/usr/local/etc/mail/virtuals # Listeners listen on all tls pki mail.example.com listen on all port 587 tls-require pki mail.example.com auth # Actions action "local_mail" maildir "/var/mail/%{dest.user}" alias <aliases> action "virtual_mail" maildir "/var/vmail/%{dest.domain}/%{dest.user}" virtual <virtuals> action "outbound" relay # Matching rules (order matters - first match wins) match from any for domain <domains> action "virtual_mail" match for local action "local_mail" match from local for any action "outbound" match auth from any for any action "outbound"

Start the daemon:

sh
service smtpd start

Configuration Syntax Walkthrough

OpenSMTPD's configuration follows a three-step model:

  1. listen -- define where to accept connections and with what options (TLS, authentication, port)
  2. action -- define what to do with mail (deliver to mailbox, relay to another server, pipe to a program)
  3. match -- define rules that connect incoming mail to actions based on sender, recipient, source, and other criteria

Rules are evaluated in order. The first matching rule determines the action. This is similar to PF firewall rules and feels natural to FreeBSD sysadmins.

TLS Configuration

Obtaining Certificates

Use Let's Encrypt via acme.sh:

sh
pkg install acme.sh acme.sh --issue -d mail.example.com --standalone acme.sh --install-cert -d mail.example.com \ --cert-file /usr/local/etc/ssl/certs/mail.example.com.crt \ --key-file /usr/local/etc/ssl/private/mail.example.com.key \ --fullchain-file /usr/local/etc/ssl/certs/mail.example.com.fullchain.crt \ --reloadcmd "service smtpd restart"

TLS Settings

OpenSMTPD uses LibreSSL (or OpenSSL) for TLS. Modern TLS settings:

sh
pki mail.example.com cert "/usr/local/etc/ssl/certs/mail.example.com.fullchain.crt" pki mail.example.com key "/usr/local/etc/ssl/private/mail.example.com.key" listen on all tls pki mail.example.com listen on all port 587 tls-require pki mail.example.com auth listen on all port 465 smtps pki mail.example.com auth
  • Port 25: accepts mail from other servers, offers STARTTLS but does not require it (many servers still send plain)
  • Port 587: submission port for authenticated users, requires STARTTLS
  • Port 465: implicit TLS submission (SMTPS), for clients that prefer it

Testing TLS

sh
openssl s_client -connect mail.example.com:25 -starttls smtp openssl s_client -connect mail.example.com:465

Verify the certificate chain and TLS version. You should see TLSv1.2 or TLSv1.3.

Virtual Users

OpenSMTPD supports virtual users through table-based mapping, without requiring system accounts for each mailbox.

File-Based Virtual Users

sh
# /usr/local/etc/mail/domains example.com example.org
sh
# /usr/local/etc/mail/virtuals info@example.com vmail support@example.com vmail admin@example.com john john@example.com vmail jane@example.org vmail

Create the virtual mail user and directory structure:

sh
pw useradd vmail -d /var/vmail -s /usr/sbin/nologin -m mkdir -p /var/vmail/example.com /var/vmail/example.org chown -R vmail:vmail /var/vmail

Mail for john@example.com is delivered to /var/vmail/example.com/john/ in maildir format.

Database-Backed Virtual Users

For larger deployments, use SQLite or PostgreSQL:

sh
pkg install opensmtpd-extras

Configure a SQLite table:

sh
# /usr/local/etc/mail/smtpd.conf table virtuals sqlite:/usr/local/etc/mail/sqlite.conf
sh
# /usr/local/etc/mail/sqlite.conf dbpath /usr/local/etc/mail/virtuals.db query_alias SELECT destination FROM virtuals WHERE email=?; query_domain SELECT domain FROM domains WHERE domain=?;

Create the database:

sh
sqlite3 /usr/local/etc/mail/virtuals.db << 'SQL' CREATE TABLE domains (domain TEXT PRIMARY KEY); CREATE TABLE virtuals (email TEXT PRIMARY KEY, destination TEXT); INSERT INTO domains VALUES ('example.com'); INSERT INTO virtuals VALUES ('info@example.com', 'vmail'); INSERT INTO virtuals VALUES ('john@example.com', 'vmail'); SQL

Authentication

OpenSMTPD authenticates users for outbound relaying (submission on port 587/465). Authentication methods include:

System Password Authentication

By default, OpenSMTPD authenticates against the system's password database (/etc/master.passwd):

sh
listen on all port 587 tls-require pki mail.example.com auth

The auth keyword enables authentication against system accounts. Users log in with their FreeBSD username and password.

Table-Based Authentication

For virtual users or when you do not want system accounts:

sh
# /usr/local/etc/mail/credentials john@example.com $2b$10$hash_of_password_here jane@example.org $2b$10$hash_of_password_here

Generate password hashes:

sh
smtpctl encrypt

Type the password, press Enter, and it outputs a bcrypt hash. Place this hash in the credentials file.

sh
table credentials file:/usr/local/etc/mail/credentials listen on all port 587 tls-require pki mail.example.com auth <credentials>

Spam Filtering with rspamd

OpenSMTPD integrates with rspamd through a filter mechanism:

sh
pkg install rspamd opensmtpd-filter-rspamd

Enable rspamd:

sh
sysrc rspamd_enable="YES" service rspamd start

Add the rspamd filter to OpenSMTPD:

sh
# /usr/local/etc/mail/smtpd.conf filter "rspamd" proc-exec "filter-rspamd" listen on all tls pki mail.example.com filter "rspamd"

rspamd provides spam scoring, DKIM signing and verification, SPF checking, DMARC enforcement, greylisting, and rate limiting. Its default configuration is effective out of the box. Tune it in /usr/local/etc/rspamd/.

DKIM Signing

Generate a DKIM key:

sh
mkdir -p /usr/local/etc/rspamd/local.d rspamadm dkim_keygen -d example.com -s mail -b 2048 \ -k /usr/local/etc/rspamd/dkim/example.com.mail.key

Configure rspamd for DKIM signing:

sh
# /usr/local/etc/rspamd/local.d/dkim_signing.conf domain { example.com { path = "/usr/local/etc/rspamd/dkim/example.com.mail.key"; selector = "mail"; } }

Add the DKIM public key as a TXT record in your DNS:

shell
mail._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=YOUR_PUBLIC_KEY"

SPF, DKIM, and DMARC Records

A production mail server needs proper DNS records:

shell
; SPF - authorize only your mail server example.com. IN TXT "v=spf1 mx a:mail.example.com -all" ; DKIM - public key for signature verification mail._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=YOUR_PUBLIC_KEY" ; DMARC - policy for handling failures _dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; pct=100"

OpenSMTPD vs Postfix

This is the comparison that matters for FreeBSD sysadmins choosing an MTA.

Configuration complexity. OpenSMTPD's configuration is dramatically simpler. A complete mail server config is 15-25 lines. Postfix's main.cf and master.cf together are typically 50-100 lines for equivalent functionality, with more parameters to understand. For sysadmins who configure a mail server once and maintain it for years, Postfix's learning curve is higher.

Feature completeness. Postfix wins. It has mature milter support (for amavis, opendkim, openarc, and other filters), extensive transport maps, header/body checks, rate limiting per sender/recipient/domain, LDAP and SQL integration for every lookup, proxy protocol support, and more. OpenSMTPD covers 90% of use cases; Postfix covers 99%.

Security track record. OpenSMTPD was designed from the start with privilege separation and minimal attack surface, following OpenBSD's security philosophy. However, OpenSMTPD has had critical vulnerabilities (CVE-2020-7247 was a remote code execution in the default configuration). Postfix has had far fewer security issues relative to its deployment base and codebase age. Both are significantly more secure than Sendmail.

Performance. Both handle thousands of messages per minute on modest hardware. Postfix's multi-process architecture gives it an edge under extreme load (100,000+ messages/hour). OpenSMTPD's event-driven model is efficient for typical volumes but has not been optimized for extreme throughput.

Community and ecosystem. Postfix has a larger community, more documentation, more third-party integrations, and more StackOverflow answers. OpenSMTPD's community is smaller but active, centered around the OpenBSD community.

Recommendation. Use OpenSMTPD if you value configuration simplicity, are running a small to medium mail server (up to a few thousand users), and do not need advanced features like LDAP-based routing or complex transport maps. Use Postfix for large-scale deployments, complex routing requirements, or when you need the broadest possible ecosystem of integrations.

For a Postfix setup guide on FreeBSD, see the Postfix mail server guide.

OpenSMTPD vs Sendmail

Sendmail ships in the FreeBSD base system and remains the default MTA. The comparison is brief: there is no reason to choose Sendmail for a new deployment in 2026.

Sendmail's sendmail.cf is generated from M4 macros in a process that is notoriously difficult to understand and debug. Its security history is poor. Its feature set is matched or exceeded by both Postfix and OpenSMTPD. Sendmail persists in FreeBSD's base system for historical reasons and backward compatibility, not because it is the best choice for new installations.

If you are currently running Sendmail on FreeBSD, migrating to OpenSMTPD is straightforward:

sh
# Disable Sendmail sysrc sendmail_enable="NO" sysrc sendmail_submit_enable="NO" sysrc sendmail_outbound_enable="NO" sysrc sendmail_msp_queue_enable="NO" service sendmail stop # Install and configure OpenSMTPD pkg install opensmtpd # ... configure /usr/local/etc/mail/smtpd.conf ... sysrc smtpd_enable="YES" service smtpd start # Update mailwrapper to use OpenSMTPD cat > /etc/mail/mailer.conf << 'EOF' sendmail /usr/local/sbin/smtpctl send-mail /usr/local/sbin/smtpctl mailq /usr/local/sbin/smtpctl makemap /usr/local/libexec/smtpd/makemap newaliases /usr/local/libexec/smtpd/makemap EOF

This ensures that system tools (cron, periodic) that call sendmail use OpenSMTPD's compatibility interface.

Operational Tips

Log monitoring. OpenSMTPD logs to syslog facility mail. Monitor delivery failures:

sh
grep "relay" /var/log/maillog | grep "stat=Temp"

Queue management. View the mail queue:

sh
smtpctl show queue

Flush the queue (retry all deferred messages):

sh
smtpctl schedule all

Remove a stuck message:

sh
smtpctl remove <envelope-id>

Testing delivery. Send a test message from the command line:

sh
echo "Test message body" | mail -s "Test subject" user@example.com

Check delivery:

sh
tail -f /var/log/maillog

Backup MX. Configure a secondary MX server with OpenSMTPD:

sh
# On the backup MX listen on all tls pki backup.example.com action "relay_primary" relay host smtp://mail.example.com backup match from any for domain "example.com" action "relay_primary"

FAQ

Q: Can OpenSMTPD run inside a FreeBSD jail?

A: Yes. OpenSMTPD runs well in a jail. Ensure the jail has a dedicated IP address and that DNS MX records point to it. No special kernel parameters are needed.

Q: Does OpenSMTPD support LDAP for user lookups?

A: Not natively in the base install. The opensmtpd-extras package adds LDAP, MySQL, PostgreSQL, and Redis table backends. Install with pkg install opensmtpd-extras.

Q: How do I handle catch-all addresses?

A: In the virtuals table, use @example.com as the email address to match all recipients for that domain: @example.com vmail.

Q: Can I use OpenSMTPD with Dovecot?

A: Yes. OpenSMTPD delivers mail to maildir format, and Dovecot reads from maildir. Configure OpenSMTPD to deliver to the directory Dovecot expects. Use LMTP for more reliable integration: action "deliver" lmtp "/var/run/dovecot/lmtp".

Q: How do I rate-limit incoming connections?

A: OpenSMTPD has basic connection rate limiting through listen options. For advanced rate limiting, use rspamd or PF's rate limiting features in front of OpenSMTPD.

Q: What happens if rspamd is down?

A: By default, filter-rspamd will tempfail messages (4xx response) if rspamd is unreachable. Sending servers will retry. This is safer than accepting unfiltered mail.

Q: How do I monitor OpenSMTPD?

A: Parse syslog for delivery statistics, or use smtpctl show stats for runtime counters. For graphing, pipe stats to a time-series database. There is no built-in Prometheus exporter, but community exporters exist.

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.