Setting up a mailserver on OpenBSD 6.9p10: Introduction The goal is to have a hosted mail server for my domain accessible to hosts both inside and outside the local network which use MacOS, Linux, and OpenBSD. Alhough mail is in the base install and can suffice to read local system mail on an OpenBSD workstation or messages from local network hosts (with some reconfiguration of smtpd.conf), it cannot access mail from a remote mail server. For this, use Thunderbird. Mutt, lynx, getmail/fetchmail, Apple Mail, etc. You can send mail from the terminal to remote addresses (see here, for example) with some reconfiguration of smtpd.conf, you just can't retrieve it using mail. Prior to doing this, consider: ° A static IP is (almost) mandatory as is 24/7 uptime. I recommend you spin up a cheap VPS. Some ISPs use dynamic addresses which do not change often, sort of s pseudo-static IP. If your mail server is not your primary one and you are just testing, this can be ok but you will likely run into issues with relays to other mail servers; for production, no. ° Check that port 25 is not blocked by your ISP or hosting provider. You can check from a remote host with https://www.yougetsignal.com/tools/open-ports/. You may be able to file a ticket to get that opened, but many large mail services will also not allow relay to a dynamic IP. A static IP in your ISP's block may be encumbered by poor reputation scores, blacklists, or reverse DNS issues so, again, relays may be blocked. ° OpenBSD /etc/services shows port 465 for smtps. Well, what about using this? To quote from Mailgun (https://www.mailgun.com/blog/which-smtp-port-understanding-ports-25-465-587/): "Interestingly, port 465 was never published as an official SMTP transmission or submission channel by the IETF. Instead, the Internet Assigned Numbers Authority (IANA), who maintains much of the core internet infrastructure, registered port 465 for SMTPS. The purpose was to establish a port for SMTP to operate using Secure Sockets Layer (SSL). SSL is commonly used for encrypting communications over the internet. The port was assigned for about one year when it was revoked in support of securing SMTP communications using Transport Layer Security (TLS). The nail in the coffin was a new protocol command "STARTTLS," introduced in RFC 2487. This command allows SMTP servers to communicate over existing ports by advertising whether the destination server supports TLS encryption. If so, the sending server can upgrade the connection using the "STARTTLS" SMTP command." Now, they're selling a service so have some incentive to paint a darker picture, but that's correct. Many mail servers relay over port 25, some over port 465, and some even over 587 (submission); most use SSL or TLS, but some use plain text. There are quite a few broken/ancient/misconfigured mail servers out there, not to mention all the spammers. ° As smtp is usually blocked to and from your home, running your mailserver on VPS hosted by some hosting service is preferred. You can get control of your DNS and, usually, get port 25 opened if needed. While you're at it, make sure your hosting provider also leaves open ports 465 and 567. pop/pop3 is (being) deprecated, so we will use only imap. Check that the imap (143), imap3 (220), and imaps (993) ports are open as well. ° Check that your IP address has not been blacklisted because of prior activity. You can use online services like https://whatismyipaddress.com/blacklist-check. You can also check the reputation of the IP address at sites like https://www.ipqualityscore.com/ip-reputation-check. If it is blacklisted, contact the maintainer/issuer of the blacklist and get it removed. ° Check that you can edit the reverse DNS records or that your ISP will. If your rDNS A record and MX record do not point to your mail server name, e.g. mail.example.com, you need to fix this. Check with https://mxtoolbox.com/ReverseLookup.aspx, for example. Other instructions about setting up a mail server on the web for reference: https://poolp.org/posts/2019-09-14/setting-up-a-mail-server-with-opensmtpd-dovecot-and-rspamd/ https://prefetch.eu/blog/2020/email-server/ https://www.vultr.com/docs/an-openbsd-e-mail-server-using-opensmtpd-dovecot-rspamd-and-rainloop https://wiki.ircnow.org/index.php?n=Opensmtpd.Configure?from=Openbsd.Opensmtpd#toc-7 https://wiki.ircnow.org/index.php?n=Dovecot.Install https://karchnu.fr/posts/2020-09-17-certificate-smtp-imap-antispam.html https://dev.to/nabbisen/series/1265 https://upcloud.com/community/tutorials/secure-postfix-using-lets-encrypt/ https://robpickering.com/using-lets-encrypt-tls-certificates-for-smtp-imap-and-https https://codedharma.com/posts/openbsd_email_1/ And, there are a bunch of others. With all these criteria in mind, let's move on to DNS. A. DNS In my experience, and speaking as someone who has run my own nameservers locally with BIND, with everyDNS (RIP), DYN, and dynu.com, that most of my errors were here. This is largely because articles (including this one) use the BIND format to describe DNS records but hosting services often use an interface to set DNS records which does not at all look like a BIND record. Vultr is no exception. I'm going to stick to BIND format though as you may be using another hosting service and I don't want to get bogged down in those particular specifics. 1. First, set up DNS for the mail server at your DNS provider A Record: smtp.example.com A 1.2.3.4 MX Records: example.com MX 1 smtp.example.com. @ MX 2 smtp.example.com. 2. TXT/SPF Records: This allows mail from the server on the mx record only only and fails if not correct: example.com. IN TXT "v=spf1 mx -all" This allows mail from the mx servers and from this specified ip address with a soft fail: example.com. IN TXT "v=spf1 ip4:1.2.3.4 mx ~all" See https://wiki.ircnow.org/index.php?n=DNS.SPF for options and format of SPF records. 3. CAA records - see getting certificates below. 4. Set up DKIM and DMARC (see next section). 5. Reverse DNS (rDNS), forward-confirmed reverse DNS (FCrDNS), and PTR records: If you have static IP at home or business, you need to contact your ISP to have them set up reverse DNS. If you hae a VPS or shared hosting, usually you can create PTR records in the administration panel or request it from your hosting company. The format of the PTR record is: 4.3.2.1.in-addr.arpa. 7200 IN PTR mail.example.com. Forward-confirmed DNS requires that an A record references the name and IP and a PTR record references the same IP and name, like so: mail 3600 IN A 1.2.3.4 4.3.2.1.in-addr.arpa. 7200 IN PTR mail.example.com. 6. TLSRPT and MTA-STS: See additional configuration below. 7. Test if DNS resolution is working. You can use https://mxtoolbox.com/ to check all your DNS records for confirmation and use https://multirbl.valli.org/ to check rDNS AND FCDNS. For additional reading: https://wiki.ircnow.org/index.php?n=DNS.Mail https://manuals.gfi.com/en/kerio/connect/content/server-configuration/mail-delivery-and-dns-records/essential-dns-records-for-mail-delivery-and-spam-protection-1223.html B. DKIM and DMARC 1. DKIM is a method for cryptographic signing of the mail for a server. The private key is kept on the server and signs the message; the public key is placed in a DNS record so other servers can confirm the origin of the message. First, lets generate the key pair. Create a user and group dkim: $ doas groupadd -v _dkimsign $ doas useradd -s /sbin/nologin -d /var/empty -g _dkimsign -G _smtpd _dkimsign You'll also need user and group _dovecot so, if you haven't already, install Dovecot: $ doas pkg_add dovecot Now make the /etc/mail/dkim directory: doas mkdir /etc/mail/dkim cd /etc/mail/dkim Generate the key pair: $ openssl genrsa -out private.key 2048 $ openssl rsa -in private.key -pubout -out public.key Fix the ownership and permissions: $ doas chmod 0440 private.key $ doas chmod 0444 public.key $ doas chown -R _smtpd:_dovecot /etc/mail/dkim/ $ doas chown root:_rspamd private.key Now, lets create the DNS record. The format is: anyalphanumstring._domainkey 86400 IN TXT "k=rsa; t=s; p=" anyalphanumstring can be anything; I usually use the date of the key generation so I can see if a new one has been added. "_domainkey" is the actual word; this does not refer to your domain's name. is the actual key value, stripped of the first and last line. You can generate this with: doas cat /etc/mail/dkim/public.key | awk '/-----/{if (NR!=1)print "";next}{printf $0}' - or use you favorite editor. You may read about _adsp. dkim records, but this has been deprecated. You can leave these off. You can sign the outgoing emails with dkim-proxy (in ports) or with rspamd (since v 1.5). We will use rspamd. When you set it up, you need to add a stanza to get the emails signed: allow_username_mismatch = true; domain { example.com { path = "/ect/mail/dkim/private.key"; selector = ""; } } where anyalphanumstring it the same selector you used in the DKIM TXT DNS record. We'll get back to this below. 2. DMARC This is relatively simple: _dmarc.example.com. TXT "v=DMARC1; p=reject; sp=reject; pct=100; aspf=s; adkim=s; fo=1; ruf=mailto:" where is the email address of the mail server adminstrator/postmaster, like postmaster@example.com. It does not have to be on the mail server we are building here. 3. Testing DKIM and DMARC You can use https://mxtoolbox.com/ to check all your DNS records are published and for confirmation of spelling and syntax. You can use https://dkimvalidator.com/ to actually send an email, but that assumes you have the system working. There are multiple sources for this on the web. The most complete for DKIM configuration is https://wiki.ircnow.org/index.php?n=DNS.DKIM#toc-4. The section on DMARC is good in https://prefetch.eu/blog/2020/email-server/#dkim. C. Get Let's Encrypt certificates: We will be setting up a httpd server to handle certificates for mail.example.com and _mta-sts.example.com from Let's Encrypt. You can do this with certbot, but I found setting up renewals easier using the http client. You can set up a web server on the mailhost that only handles the acme challenge and redirects all other requests. One note: smtpd does not currently support SAN certificates or SNI, so the certificate requested must be for the hostname of the mail server. We will also use this http server to enable MTA-STS. First, for the mail server itself. 1. Configure httpd server "mail.example.com" { listen on $ext_addr port $ext_HTTP_port location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } location * { block return 302 "https://$HTTP_HOST$REQUEST_URI" } } HTTP code 302 is a temporary redirection. You can use the block return 302 command to redirect the request to the www server for the domain elsewhere or you can create a static landing page on this server if example.com does not have a web site. That's it. Now check configuration (httpd -n) and start your httpd. 2. Configure acme-client: Add a stanza to acme-client.conf: domain mail.example.com { domain key "/etc/ssl/private/mail.example.com.key" domain certificate "/etc/ssl/mail.example.com.crt" domain full chain certificate "/etc/ssl/mail.example.com.fullchain.pem" sign with letsencrypt } 3. Now generate certificates: doas acme-client -v mail.example.com Check if the new certificates are in /etc/ssl and keys in /etc/ssl/private. 3. Add to smtpd.conf: see below 4. set up cron job to renew: doas crontab -e -u root Add: 30 0 * * * acme-client mail.example.com 5. Add CCA records to your DNS records. mail.example.com. CAA 0 issue "letsencrypt.org" References: https://www.romanzolotarev.com/openbsd/acme-client.html https://www.bsdhowto.ch/webserver.html 6. Setting up MTA-STS: This is becoming more generally applied but is stil not universal. I still would do it to future-proff your server and it may make rejection of mail as spam less likely. For instruction, go to "Additional Configuration" below. D. Set up virtual users. To prevent having to have every mail user have an actual account on the mail host, we'll use virtual users. Dovecot can use a variety of data sources for the virtual users including a simple list, flat file, redis, or a database like sqlite or mysql. Since I expect less than 20 users at max, a static list will be used, for now. 1. Create vmail user: doas useradd -c "Virtual Users Mail Account" -d /var/vmail -s /sbin/nologin / -u 2000 -g =uid -L staff vmail 2. Create the necessary users, directories, and files: doas touch /etc/mail/credentials doas chmod 0440 /etc/mail/credentials doas chown _smtpd:_dovecot /etc/mail/credentials doas useradd -c "Virtual Mail Account" -d /var/vmail -s /sbin/nologin / -u 2000 -g =uid -L staff vmail (You will get "useradd: Warning: home directory `/var/vmail' doesn't exist, and -m was not specified." That's fine.) doas mkdir /var/vmail doas chown vmail:vmail /var/vmail 3. Populate the /etc/mail/credentials file. Each line in the file has a particular format: john@example.com:$2b$10$_EXAMPLE_PASSWORD1_C3JbO4Ns2jJNZQfTS45MAnKi.IPrkKITyTa6:vmail:2000:2000:/var/vmail/example.com/john::userdb_mail=maildir:/var/vmail/example.com/john or username@domain.tld::vmail_uid:vmail_gid::: 4. You could write a simple script to generate the lines in /etc/mail/credentials: #!/bin/sh # vmail_credential_gen.sh 8/1/21 gsb # default shell script boilerplate # depending on your sh and env, you may or may not want all of this set -e # strict error set -u # don't expand undefined variable set -f # disable pathname expansion set -C # noclobber unset IFS # make IFS behave in default way "unalias" -a # remove all aliases export LC_ALL=C # remove localization # script body # Echo script id echo "Credential generator for /etc/mail/credentials" # Ask the user for their name echo "What is the username? (Enter name and hit Return)" read username # Ask for the password echo "What will be the password for $username@example.com? (Enter name and hit Return)" read pswd hash=$(smtpctl encrypt $pswd) echo echo "Password hash is $hash" echo # Echo the new entry for /etc/mail/credentials echo "Review the following line for errors:" echo vmailuser=$username@example.com:$hash:vmail:2000:2000:/var/vmail/example.com/$username::userdb_mail=maildir:/var/vmail/example.com/$username echo $vmailuser echo echo "If correct, enter y to append to /etc/mail/credentials (y/n)" read choice if [ "${choice}" = "y" ] ; then echo $vmailuser >> /etc/mail/credentials echo "Appended to /etc/mail/credentials. Check file for accuracy." else echo "Copy and paste manually, or re-run program if needed." fi echo "Append to /etc/mail/virtuals (y/n)" read choice if [ "${choice}" = "y" ] ; then echo $vmailuser >> /etc/mail/virtuals echo "Appended to /etc/mail/virtuals. Check file for accuracy." else echo "Copy and paste manually, or re-run program if needed." fi echo "Done" # End script vmail_credential_gen.sh 5. Create and populate the /etc/mail/virtuals file. doas touch /etc/mail/virtuals doas chmod 0440 /etc/mail/virtuals doas chown _smtpd:_dovecot /etc/mail/virtuals Edit the file to contain list and aliases of users: abuse@example.com: john@example.com hostmaster@example.com: john@example.com postmaster@example.com: john@example.com webmaster@example.com: john@example.com john@example.com: vmail peter@example.com: vmail mary@example.com: vmail E. Preliminary configuration and testing of OpenSMTPD 1. At this point, we might should go ahead and install all the other packages needed: pkg_add opensmtpd-extras opensmtpd-filter-rspamd dovecot dovecot-pigeonhole rspamd redis 1. OpenSMTPD is installed in base. First, backup the default smtpd.conf: doas cp /etc/mail/smtpd.conf /etc/mail/smtpd.conf.default Then create your new smtpd.conf like so: # smtpd.conf # PKI keys for TLS pki mail cert "/etc/ssl/mail.example.com.fullchain.pem" pki mail key "/etc/ssl/private/mail.example.com.key" # Tables table aliases file:/etc/mail/aliases table credentials passwd:/etc/mail/credentials table virtuals file:/etc/mail/virtuals # Listeners listen on all tls pki "mail" hostname "mail.example.com" listen on egress port submission tls pki "mail" hostname "mail.example.com" # Actions action "local_mail" mbox alias action "domain_mail" maildir "/var/vmail/example.com/%{dest.user:lowercase}" \ virtual action "outbound" relay # Rules # Local match from local for local action "local_mail" match from local for domain "example.com" action "domain_mail" match from local for any action "outbound" # Remote match from any for domain "example.com" action "domain_mail" match from any for any action "outbound" We'll flesh this out after dovecot and rspamd are set up. 2. Check configuration and restart smtpd: doas smtpd -nf /etc/mail/smtpd.conf doas rcctl restart smtpd 3. Check if it's working by sending messages from a local user to domain address: mail -s "Test mail from local user" john@example.com John, This might work. Pace ctrl-d Check if the mail is received: doas ls -al /var/vmail/example.com/john/new/ F. Adjust pf.conf. With this setup we will use imap and smtp. 1. Add to pf.conf on the firewall: ... mailserver = "10.1.1.2" email_ports = "{ smtp, imap, imap3, 465, submission, imaps }" ... # Direct email traffic to smtp server pass in on egress inet proto tcp from any to (egress) port $email_ports rdr-to $mailserver .... 2. Add to pf.conf on mailserver: ... email_ports = "{ smtp, imap, imap3, 465, submission, imaps }" ... # Pass in traffic to mailserver pass in on egress inet proto tcp from any to ( egress ) port $email_ports .... 3. Now try to send an email to john@example.com from Gmail or other remote mail service. Check as above whether it is received. You can't send mail yet, but at least 1/2 of the server is functional G. Install, configure and test Dovecot Here we basically follow https://www.vultr.com/docs/an-openbsd-e-mail-server-using-opensmtpd-dovecot-rspamd-and-rainloop#_Optional__Configure_RainLoop_Webmail with a few modifications. 1. define login class: Define a login class for the Dovecot daemon. At the bottom of /etc/login.conf add the following lines. dovecot:\ :openfiles-cur=1024:\ :openfiles-max=2048:\ :tc=daemon: Note that cap_mkdb(1) must be run after each edit of /etc/login.conf to keep the database version in sync with the plain file: cap_mkdb /etc/login.conf 2. Check /etc/dovecot/conf.d/10-ssl.conf to be sure the ssl_cert and ssl-key definitions are commented out as shown. ... # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before # dropping root privileges, so keep the key file unreadable by anyone but # root. Included doc/mkcert.sh can be used to easily generate self-signed # certificate, just make sure to update the domains in dovecot-openssl.cnf #ssl_cert = </etc/ssl/dovecotcert.pem #ssl_key = </etc/ssl/private/dovecot.pem ... 3. Instead of editing individually each of the many config files of Dovecot, you can simply create a /etc/dovecot/local.conf file which will override any options. This example is from the vultr.com instructions and works if you install by those instructions. If you use another means of auth, this will need to be edited: auth_mechanisms = plain first_valid_uid = 2000 first_valid_gid = 2000 mail_location = maildir:/var/vmail/%d/%n mail_plugin_dir = /usr/local/lib/dovecot managesieve_notify_capability = mailto managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext imapsieve vnd.dovecot.imapsieve mbox_write_locks = fcntl mmap_disable = yes namespace inbox { inbox = yes location = mailbox Archive { auto = subscribe special_use = \Archive } mailbox Drafts { auto = subscribe special_use = \Drafts } mailbox Junk { auto = subscribe special_use = \Junk } mailbox Sent { auto = subscribe special_use = \Sent } mailbox Trash { auto = subscribe special_use = \Trash } prefix = } passdb { args = scheme=CRYPT username_format=%u /etc/mail/credentials driver = passwd-file name = } plugin { imapsieve_mailbox1_before = file:/usr/local/lib/dovecot/sieve/report-spam.sieve imapsieve_mailbox1_causes = COPY imapsieve_mailbox1_name = Junk imapsieve_mailbox2_before = file:/usr/local/lib/dovecot/sieve/report-ham.sieve imapsieve_mailbox2_causes = COPY imapsieve_mailbox2_from = Junk imapsieve_mailbox2_name = * sieve = file:~/sieve;active=~/.dovecot.sieve sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment sieve_pipe_bin_dir = /usr/local/lib/dovecot/sieve sieve_plugins = sieve_imapsieve sieve_extprograms } protocols = imap sieve service imap-login { inet_listener imap { port = 0 } } service managesieve-login { inet_listener sieve { port = 4190 } inet_listener sieve_deprecated { port = 2000 } } ssl_cert = </etc/ssl/mail.crt ssl_key = </etc/ssl/private/mail.key userdb { args = username_format=%u /etc/mail/credentials driver = passwd-file name = } protocol imap { mail_plugins = " imap_sieve" } Be sure to edit the location of your TLS credentials in /etc/ssl. Then, enable and start dovecot. doas rcctl enable dovecot doas rcctl start dovecot Check 'pa aux' to see if it's running and review /var/log/maillog for error messages. H. Configure rspamd 1. DKIM signing: As noted above, you need to create /etc/rspamd/local.d/dkim_signing.conf: doas nano -w /etc/rspamd/local.d/dkim_signing.conf and add this: domain { example.com { path = "/etc/mail/dkim/example.com.key"; selector = "default"; } } where "default" is the date of key creation of whatever string you used in the DNS record. Now, restart rspamd: doas rcctl restart rspamd 2. Set up rspamd web interface: rspamd has a web ui which displays statistics and allows adjustment of the configuration. This is configured with /etc/rspamd/worker-controller.inc which is not to be edited. Instead, create and edit /etc/rspamd/overrides.d/worker-controller.inc:
doas cp /etc/rspamd/worker-controller.inc /etc/rspamd/override.d/worker-controller.inc:
doas nano-w /etc/rspamd/override.d/worker-controller.inc

displays

count = 1;
password = "q1";
secure_ip = "127.0.0.1";
secure_ip = "::1";
static_dir = "${WWWDIR}";

Edit this as so:


password = "alphanumstring";
secure_ip = "127.0.0.1";
#secure_ip = "::1";

here. That configuration redirects the https request to 127.0.0.1 which bypasses password authentication. You can comment out the secure_ip line to force all connections to authenticate or you can forward to another ip address besides localhost.

3. More securely use the rspamd web interface:

The best and easiest way to do this is with an SSH tunnel. This obivates the need for changing the rspamd configuration, using relayd, or tls certificates. First block port 11334 at the firewall. Then, create a SSH tunnel:

ssh -N -L local_port:web_UI_address_of_rspamd:remote_port_of_rspamd_web_UI ip.add.of.server

or

ssh -N -L 11334:127.0.0.1:11334 IP.ADD.OF.SVR

Leave this running and point your browser at 127.0.0.1:11334 to see the web UI securely.


I. Set up Sieve:

I refer you to the instructions here:
https://www.vultr.com/docs/an-openbsd-e-mail-server-using-opensmtpd-dovecot-rspamd_and-rainloop
 https://poolp.org/posts/2019-09-14/setting-up-a-mail-server-with-opensmtpd-dovecot-and-rspamd/


J. Further configuration of OpenSMTPD

Now, let's complete smtpd.conf:

# smtpd.conf

# PKI keys for TLS
pki mail cert "/etc/ssl/mail.example.com.fullchain.pem"
pki mail key "/etc/ssl/private/mail.example.com.key"

# Macros
filters = " { check_rdns check_fcrdns rspamd } "

# Filters
filter check_rdns phase connect match !rdns junk
filter check_fcrdns phase connect match !fcrdns junk
filter "rspamd" proc-exec "/usr/local/libexec/smtpd/filter-rspamd"

# Tables
table aliases file:/etc/mail/aliases
table credentials passwd:/etc/mail/credentials
table virtuals file:/etc/mail/virtuals

# Listeners
listen on all tls pki "mail" hostname "mail.example.com.example.com" mask-src filter $filters
#listen on all tls pki "mail" hostname "mail.example.com" mask-src filter "rspamd"
listen on egress port submission tls-require pki "mail" hostname "mail.example.com" \
  auth  filter "rspamd"

# Actions
action "local_mail" mbox alias 
action "domain_mail" maildir "/var/vmail/example.com/%{dest.user:lowercase}" virtual 
action "outbound" relay

# Rules

# Local
match from local for local action "local_mail"
match from local for domain "example.com" action "domain_mail"
match from local for any action "outbound"

# Remote
match from any for domain "example.com" action "domain_mail"
match auth from any for any action "outbound"


K. Install pf-badhost

For additional spam rejection and to protect your mail server, download and install pf-badhost (https://www.geoghegan.ca/pub/pf-badhost/">pf-badhost) as decribed on the authors page. (BTW, tip your local developer; both pf-badhost and unbound-adblock are wo
rthy projects.)

Edit pf-badhost.sh to include blocklists for email attackers:

....
##################################################################
# Block Lists
# Enter URL to any IP blocklist
....
### SMTP/E-Mail Attackers
https://lists.blocklist.de/lists/25.txt
https://lists.blocklist.de/lists/110.txt
https://lists.blocklist.de/lists/143.txt
https://lists.blocklist.de/lists/993.txt
https://lists.blocklist.de/lists/email.txt
https://lists.blocklist.de/lists/mail.txt
https://lists.blocklist.de/lists/imap.txt
https://lists.blocklist.de/lists/courierimap.txt
https://lists.blocklist.de/lists/courierpop3.txt
https://lists.blocklist.de/lists/pop3.txt
https://lists.blocklist.de/lists/postfix.txt
.... 

Then, restart pfbadhost to load new blocklists:

doas -u _pfbadhost pf-badhost -O openbsd


M. More testing

The acid test is now to send mail to one of your accounts at Google, Microsoft, Apple/iCloud, and others like ATT/Yahoo. If the message is received in your mailbox and not flagged as Spam/Junk, that's great. Now, reply to the message and look to see if the reply shows up in your mailbox of the newly commissioned mail server.

If not, go back to some of the tests detailed above. Instruction from https://prefetch.eu/blog/2020/email-server/#testing may be helpful. Display and read the headers and check DKIM both ways. Recheck the DNS configuration and reverse DNS. CheckTLS (https://www.checktls.com/howto.html#Deeper) and Hardenize (https://www.hardenize.com/) have online tools which can be helpful in pointing out problems. Make sure the mail is not getting trapped by rspamd (use the web ui to see the details).

Good luck!

N. Optional Configuration: TLSRPT and MTA-STS

SPF, DKIM and DMARC are widely used but spam volume has, if anything, increased. In 2018, the IETF released RFC 8460 and RFC 8461, which respectively define TLSRPT and MTA-STS. These are not widely adopted yet but email providers' spam filters may use presence or absense of TLSRPT and MTA-STS as part of their spam scoring system.

1. TLSRPT

TLS reporting, or TLSRPT for short, is very simple: all it does is provide a contact email address in case somebody has trouble with the TLS configuration of your SMTP server.

To enable it for your custom email domain example.com, simply create a DNS TXT record for the _smtp._tls subdomain:

_smtp._tls.example.com. TXT "v=TLSRPTv1; rua=mailto:"

without the angle braces, or,

_smtp._tls.example.com. TXT "v=TLSRPTv1; rua=mailto:postmaster@example.com"

where <contact> is an email address of your admin contact.

2. MTA-STS

MTA Strict Transport Security (MTA-STS) tells other servers that they should avoid sending you unencrypted email and should only accept certain certificates from your side. MTA-STS requires an HTTP web server but we already have one to manage our Let's Encrypt certificate renewals.

a. DNS: The DNS part is still pretty simple: create yet another DNS TXT record, this time for the subdomain _mta-sts:

_mta-sts.example.com. TXT "v=STSv1; id=<id%gt;"

The <id> identifies the policy; so you and remote servers can detect changes, I use the date and time of modification of mta-sts.txt. Every time you edit the mta-sts.txt, you need to update the <id> for remote servers can detect that the policy is changed and refresh their cache of your mta-sts.txt.

_mta-sts.example.com. TXT "v=STSv1; id=2108031905EDT"

Don't forget to create an A record which for subdomain mta-sts (without underscore):

mta-sts.example.com. IN A 1.2.3.4

And add CCA records to your new mta-sts subdomain:

mta-sts.example.com.  CAA 0 issue "letsencrypt.org"

b. Create the mta-sts policy file:

First, create the web root folder for the file.

doas mkdir -p /var/www/mta-sts/

Now create the file mta-sts.txt. The contents are as follows, where mx1.example.com and mx2.example.com are the mail hosts defined in example.com’s DNS MX records.

version: STSv1
mode: enforce
mx: mx1.example.com
mx: mx2.example.com
max_age: 

Note - weirdly, this file is said to apparently require CRLF Windows-style line endings ("\r\n") but appears to work fine with txt files created by nano. So, for our example:

doas nano -w /var/www/mta-sts/mta-sts.txt
version: STSv1
mode: testing
mx: mail.example.com
max_age: 86400
ctrl-O
ctrl-X

c. httpd: Set your web server to obtain certificates and serve the file. Note that the policy file must be served over HTTPS, so you need a yet another valid TLS certificate for the mta-sts subdomain.

# http server to obtain and renew Let's Encrypt certificate for mta-sts

server "mta-sts.example.com" {
        listen on $ext_addr port $ext_HTTP_port

        location "/.well-known/acme-challenge/*" {
                root "/acme"
                request strip 2
        }
        
        location * {
                block return 302 "https://$HTTP_HOST$REQUEST_URI"
        }
}

# https server for serve mta-sts.txt

#server "mta-sts.example.com" {
#        listen on $ext_addr port tls $ext_HTTPS_port
        
#        tls {
#            certificate "/etc/ssl/mta-sts.example.com.fullchain.pem"
#            key "/etc/ssl/private/mta-sts.example.com.key"
#            }

#        location "/.well-known/mta-sts.txt" {
#                root "/mta-sts"
#                request strip 1 
#                }

#        location "/.well-known/acme-challenge/*" {
#                root "/acme"
#                request strip 2
#        }
        
#}

Check and restart httpd:

doas httpd -n
doas rcctl restart httpd

d. Now get the new certificates:

Configure acme-client: Add a stanza to acme-client.conf:

domain mta-sts.example.com {
        domain key "/etc/ssl/private/mta-sts.example.com.key"
        domain certificate "/etc/ssl/mta-sts.example.com.crt"
        domain full chain certificate "/etc/ssl/mta-sts.example.com.fullchain.pem"
        sign with letsencrypt
}

Now generate certificates:

doas acme-client -v mta-sts.example.com

Check if the new certificates are in /etc/ssl and keys in /etc/ssl/private.

Now uncomment the mta-sts https server stanza in /etc/httpd.conf and restart httpd.

e. Set up cron job to check and renew certificate:

doas crontab -e -u root

Add:

30	2	*	*	*	acme-client mta-sts.example.com

f. Check your work by using various online MTA-STS validation tools:
https://esmtp.email/tools/mta-sts/">https://esmtp.email/tools/mta-sts/
https://aykevl.nl/apps/mta-sts/">https://aykevl.nl/apps/mta-sts/
https://www.checktls.com/howto.html#Deeper">https://www.checktls.com/howto.html#Deeper
https://www.hardenize.com/">https://www.hardenize.com/

Even if you did everything correctly, these tools will warn you that you’re not using DNSSEC/DANE. But, at this point, this is not widely adopted and can be a pain (see https://dane.sys4.de/common_mistakes). I'd pass on this at present.

Additional Reading/Sources:
https://prefetch.eu/blog/2020/email-server-extras/

version 9/3/21