# Host emails To get in charge of your communication tools is a big deal to more freedom and independence. This part will describe how to host an email server at home. No database will be required because it has no benefit on a small server. Let's keep things simple ! Setting up a mail server is often considered difficult. That's why we will split this tutorial in small easy steps: complex, but not complicated. In order, you will: * Configure specific DNS records; * Create certificates to secure logins; * Consider using virtual users ; * Configure opensmtpd (smtpd), the daemon in charge of receiving and sending emails; * Configure dovecot so you can read your emails from multiple devices with a client like Thunderbird through IMAP protocol; * Ensure your messages won't be considered as spams * Install antispams on different levels if you want to. Of course, you'll learn how to add new accounts and how to configure a mail client. You first have to open port 25 (smtp) in your firewall and router. Some ISP are very restrictive with this port. You can ask them to be more permissive, but make inquiries first to avoid bad surprises. At last resort, we'll discuss how to use external smtp serices. Read also opensmtpd main developper article about this subject. (HTM) https://poolp.org/posts/2019-09-14/setting-up-a-mail-server-with-opensmtpd-dovecot-and-rspamd/ ## DNS configuration for an email server Emails requires specific DNS records. You have add at least two new fields. First, make sure you have an "A" record (probably): ``` athome.tld. IN A 192.0.2.2 ``` Of course, use your real IP here. You must add a MX field pointing to the previous record: ``` athome.tld. IN MX 1 athome.tld. ``` Notice ending dots. "1" describe the weight of the field. This parameter will be used to prioritize mails servers because some of them will be backups if the main server is unavailable. We'll talk about this later. Some may want to use a specific domain, another A field to organize their mail servers. That is not mandatory, but interesting: ``` mail1.athome.tld. IN MX 1 mail1.athome.tld. mail1.athome.tld. IN A 192.0.2.2 ``` Below is another example using a different syntax: ``` $ORIGIN athome.tld [...] @ IN MX 10 mail1.athome.tld. @ IN A 192.0.2.2 mail1 IN A 192.0.2.3 ``` Here, you can see the mail server for this zone is hosted on a different IP. That's all for now. ## Get certificates To encrypt traffic with your email server, you'll need TLS certificates. It is explained in the chapter about httpd. Notice you can use self-signed certificates if you prefer, that is absolutely not an issue. (see man ssl(8)) In the next parts, we'll consider using letsencrypt certificates to keep consistent. Just remember to have a certificate for the domain of the MX field of your server. ## A mail server in 10 minutes (almost ^^) I you're in a hurry, here is a quick setup to have a working email server. It will also be a good starting point to build on later. With the following: * Mail accounts are system user accounts. * Messages are stored in a ~/Mailir folder in user's home. * An user "jdoe" will get an email address "jdoe@athome.tld". * Just use adduser command to add an account. You should set for those users the shell /sbin/nologin. * An username is valid for every domain names served. Later, we'll discuss virtual users to go further and achieve more specific tasks. But here, we're in a rush so let's go! 😊 ### smtpd.conf file Edit /etc/mail/smtpd.conf: ``` # Generic config # Tables table aliases "/etc/mail/aliases" # Certificates pki athome.tld key "/etc/ssl/private/athome.tld.key" pki athome.tld cert "/etc/ssl/athome.tld.crt" # Get messages listen on all tls pki athome.tld # To send with mail client listen on all port submission tls-require pki athome.tld auth # ACTIONS action "sendthismail" relay # System aliases action in_maildir maildir alias <aliases> # Get match for local action in_maildir match from any for domain athome.tld action in_maildir # Sending match for any action "sendthismail" match auth from any for any action "sendthismail" ``` That's it 😊 There a almost more comments than reals instructions. ### Dovecot configuration (IMAP) Install dovecot: ``` # pkg_add dovecot. ``` In /etc/dovecot/local.conf add: ``` # listen on IPV4 and IPV6. listen = *, [::] # We use Maildir mail_location = maildir:~/Maildir # only username, not user@domain.tld to auth auth_username_format = %n # imap > pop protocols = imap # Safety. Edit those lines ! ssl = yes ssl_cert = </etc/ssl/athome.tld.crt ssl_key = </etc/ssl/private/athome.tld.key disable_plaintext_auth = yes # auth methods passdb { driver = bsdauth } userdb { driver = passwd } ``` Reload dovecot: ``` # rcctl restart dovecot ``` Here you go, it's done, you can configure your mail client. ## Full mail server with virtual users "Virtual users" means they are not UNIX system users with a shell. However, they are obviously using your mail server. New accounts won't be created with adduser but you will edit a file with the username and it's password hash. Here we'll discuss how to install a SMTP (Opensmtpd) and IMAP (Dovecot) server ### One user to rule them all: _vmail We will create an user with the sweet name "_vmail" to manage every emails access. It won't have any shell, it's safer 😊. ``` # useradd -m -g =uid -c "Virtual Mail" -d /var/vmail -s /sbin/nologin _vmail ``` A new directory is created: /var/vmail. Emails will be stored inside, but following a structure with subdirectories for each virtual users. As example: ``` /var/vmail/athome.tld/batman/Maildir /var/vmail/athome.tld/user/Maildir /var/vmail/athome.tld/ninja/Maildir ... ``` ### /etc/mail/virtuals In this file, we write user's emails, one on each line. Actually, it works like /etc/mail/aliases. (read man aliases(5) 😉) ``` heroes@athome.tld batman@athome.tld,superman@athome.tld batman@athome.tld _vmail superman@athome.tld _vmail scoobydoo@athome.tld _vmail ``` As you can see, every email addresses belongs to user _vmail. Notice the first line: you see an example showing how to transfer emails sent to "heroes@athome.tld" to "batman@athome.tld" and "superman@athome.tld". ### /etc/mail/passwd Same as before, one line per passphrase: ``` batman@athome.tld:$2b$09$lerdFpdQtnu.Bs5EpAsVbeF851GjdD0aza8IDhho38i1DOHk.ujzi superman@athome.tld:$2b$09$VRU/CYJUS3QZHVUFP70xIOURPbiNQeyOEZHoZo6NOY3uO.XSpd2MW ``` Notice how ":" split email address and the hashed passphrase: <email>:<hash>. To hash passphrases, use encrypt: ``` encrypt -b a -p ``` Or ``` smtpctl encrypt passphrase ``` You're prompted to enter the passphrase. Press "Enter" to see the hash of the password and copy it in /etc/mail/passwd. ### (Facultative) Adjust files permissions Previous files shouldn't be readable by everyone. Let's adjust permissions so root and mail daemons -- dovecot and smtpd -- can read passwords. It is not mandatory, but I suggest this part as good habits that can hurt anyone 😉. Dovecot and smtpd run as users _dovecot and _smtpd. If one day, one of this process is compromised, it will avoid privilege escalation and threaten the whole system. Let's create a new group _maildaemons for _dovecot and _smtpd to ease permissions: ``` # groupadd _maildaemons # usermod -G _maildaemons _smtpd # usermod -G _maildaemons _dovecot ``` Of course, if you haven't installed dovecot yet since we discuss about it later: "# pkg_add dovecot". Now we can set owner and group for files storing logins and passwords: ``` # chown root:_maildaemons /etc/mail/passwd /etc/mail/virtuals ``` Finally, only root can modify these files and _maildaemons can only read. Others can't do anything: ``` # chmod 640 /etc/mail/passwd /etc/mail/virtuals ``` To check everything is as expected: ``` # ls -l /etc/mail/passwd -rw-r----- 1 root _maildaemons 17226 Nov 12 08:40 /etc/mail/passwd ``` ### Opensmtpd (smtpd) config Opensmtpd or smtpd is the default mail server shipped with OpenBSD. You just have to configure it. First of all, make sure you opened ports: 25 (smtp), 587 (submission) and 993 (imaps). The latter will be user with dovecot. Do not care about 465 (smtps) since it is deprecated. To configure smtpd, edit /etc/mail/smtpd.conf. Instructions will be applied in order. We will split it in 3 parts: * Generic options for smtpd; * Actions we will apply on envelopes later; * Rules matching envelopes and associated action to apply. Adjust the example below to your needs: ``` # Generic configuration # Tables table aliases "/etc/mail/aliases" table passwd "/etc/mail/passwd" table virtuals "/etc/mail/virtuals" # Certificates pki athome.tld key "/etc/ssl/private/athome.tld.key" pki athome.tld cert "/etc/ssl/athome.tld.crt" # Listening ports # Reception listen on all tls pki athome.tld # Sending with a mail client listen on all port submission tls-require pki athome.tld auth <passwd> # ACTIONS action "sendthismail" relay action local_mail maildir alias <aliases> action virtual_maildir maildir "/var/vmail/%{dest.domain:lowercase}/%{dest.user:lowercase}/Maildir" virtual <virtuals> # In/Out # Reception # Message for virtual users match from any for domain athome.tld action virtual_maildir # Message for system users match from any for local action local_mail # Sending match auth from any for any action "sendthismail" match for any action "sendthismail" ``` There is almost nothing to change in this file, except domain name. > WAIIIIIT a minute! Tell me more! Take a look at each lines: First, there are generic instructions * table aliases ...: This file is an aliases file, to forward envelopes between system users. * table passwd ...: Hashed passwords are stored here * table virtuals ...: Virtual users file. It is also a alias file. * pki ...: Certificate and key location for encrypted traffic. * listen on all tls pki athome.tld: smtpd listen (on port 25) to receive mails from other servers. Here, traffic is tls encrypted if possible with the certificate defined before. * listen on all port submission tls-require pki athome.tld auth <passwd>: The server listen on port "submission" and require tls encryption and authentication matching table <passwd>. It is necessary to send email using a mail client from another device than the server itself. Then, we define actions applied on envelopes. * action "sendthismail" relay: smtpd send the mail to the smtp server "written on the envelope". * action local_mail maildir alias <aliases>: smtpd deliver the envelope in a maildir directory after matching with the file <aliases>. It is for system users. * action virtual_maildir maildir "/var/vmail/%{dest.domain:lowercase}/%{dest.user:lowercase}/Maildir" virtual <virtuals>: Here, smtpd deliver in a Maildir directory located in _vmail's directory. Envelopes are stored according to domain name and user recipient. Everything is lowercased to avoid mistakes. That's here the magic of virtual users. At last, we apply actions according to envelope criterias. If not mentioned, the rule match a local mail. In other case, we add "from any". * match for local action local_maildir: deliver local mails. * match from any for domain athome.tld action virtual_maildir: if the message come from the outside, it is saved in the appropriate maildir according to domain name and recipient's name. * match auth from any for any action "sendthismail": If the envelope comes from a mail client outside after auhtentication, send the message to the recipient's smtp server. * match for any action "sendthismail": We send every other messages from the inside of the server. Finally, in order to label your outgoing messages with the appropriate domain name, add in /etc/mail/mailname your email's domain name. It's the domain mentioned in the MX record. ``` athome.tld ``` Now enable and start smtpd: ``` # rcctl enable smtpd # rcctl restart smtpd ``` That's all for smtpd 😊. ### Dovecot We will use Dovecot as IMAP server so you can read mails from a client like Thunderbird. As usual, install dovecot with pkg_add: ``` # pkg_add dovecot ``` Now configure dovecot. Edit /etc/dovecot/local.conf: ``` # listen IPv4 and IPv6 listen = *, [::] # imap protocols = imap # Encryption. Edit those lines according to your certificates. ssl = yes ssl_cert = </etc/ssl/athome.tld.crt ssl_key = </etc/ssl/private/athome.tld.key disable_plaintext_auth = yes # where mails are stored. %d is domain, %n is username mail_location = maildir:/var/vmail/%d/%n/Maildir # essential since we edited persmission on /etc/mail/passwd service auth { user = $default_internal_user group = _maildaemons } # Auth methodes passdb { args = scheme=blf-crypt /etc/mail/passwd driver = passwd-file } # Mails are /var/vmail , belongs to _vmail userdb { driver = static args = uid=_vmail gid=_vmail home=/var/vmail/%d/%n/ } ``` I left comments above to help you understand what is done here. Adjust ssl_cert and ssl_key according to your certificates. By the way, ssl configuration is already available in /etc/dovecot/conf.d/10-ssl.conf. It is supposed to help us with a script generating a self-signed certificate. However, you probably already have your own. You should comment lines in this file: ``` # file: /etc/dovecot/conf.d/10-ssl.conf #ssl_cert = </etc/ssl/dovecotcert.pem #ssl_key = </etc/ssl/private/dovecot.pem ``` Finally, reload mail daemons: ``` # rcctl enable dovecot # rcctl start dovecot # rcctl restart smtpd ``` Now you can use a mail client to read your messages. ### Add a mail account Add a new line for the new account in /etc/mail/virtuals and /etc/mail/passwd then reload tables for smtpd (dovecot read them on the fly): ``` smtpctl update table virtuals smtpctl update table passwd ``` Or # rcctl restart smtpd ## Manage multiple domains You can host an email server and manage multiple domain names. However, you should organize how you set this up. Below are a few notes on how to achieve this. ### smtpd changes for multi-domains I suggest to create a file containing every hosted domain, one per line. Let's call it /etc/mail/domains: ``` athome.tld domain.tld other.bar ``` Now, in /etc/mail/smtpd.conf you can write one line for multiple domains: ``` table domains "/etc/mail/domains" ... match from any for domain <domains> action virtual_maildir ``` Take care of used TLS certificates. If you have a certificate for each domain, you can specify each of them in smtpd.conf. Make sure you have a default certificate in the end (*). ``` pki athome.tld key "/etc/ssl/private/athome.tld.key" pki athome.tld cert "/etc/ssl/athome.tld.crt" pki domain.tld key "/etc/ssl/private/domain.tld.key" pki domain.tld cert "/etc/ssl/domain.tld.crt" pki other.bar key "/etc/ssl/private/other.bar.key" pki other.bar cert "/etc/ssl/other.bar.crt" pki "*" key "/etc/ssl/private/athome.tld.key" pki "*" cert "/etc/ssl/athome.tld.crt" ... listen on all tls ... listen on all port submission tls-require auth <passwd> ``` HOWEVER, you can use only one certificate matching multiple domains. To do so, use "alternative names" in acme-client configuration. It is absolutely valid and much easier to manage. If so, configure smtpd as if there was only one certificate. ### dovecot changes to support multiple domains Dovecot will need some care to handle certificates for each domain. Add "local_name" sections in its configuration so it looks like this: ``` ssl = yes ssl_cert = </etc/ssl/athome.tld.crt ssl_key = </etc/ssl/private/athome.tld.key # no plaintext disable_plaintext_auth = yes local_name domain.tld { ssl_cert = </etc/ssl/domain.tld.crt ssl_key = </etc/ssl/private/domain.tld.key } local_name other.bar { ssl_cert = </etc/ssl/other.bar.crt ssl_key = </etc/ssl/private/other.bar.key } ``` Here also, a single certificate for multiple domains is much more easier to set up. ## Redirecting mails As explained in man aliases(5), you can redirect mails to various destination. As example, you host jwayne@athome.tld and want to redirect every mails received by jwayne to batman@wayne.com. Edit /etc/mail/virtuals and add: ``` jwayne.athome.tld: batman@wayne.com ``` You can set redirections in /etc/mail/aliases too. For system users, you can use their login only: ``` root: jdoe hostmaster: root postmaster: root webmaster: bruce jdoe: jdoe@domain.tld ``` Remember to restart smtpd so changes are considered: ``` # rcctl restart smtpd ``` Easy. 😎 ## How to configure you mail client ? To use your mail server with a client such as Thunderbird, use the parameters below: * Server name: athome.tld * Email: jdoe@athome.tld * Username: if you set up virtual users, you need to write the full mail address as in /etc/mail/virtuals. In other case, the username is enough. * IMAP: port: 993 ; SSL: SSL/TLS * SMTP: port: 587 ; SSL: STARTTLS ## DNS record for clients configuration (facultative) To help clients finding automatically how to configure parameters to use your mail server, you can add specific DNS records. ``` _submission._tcp.athome.tld 86400 IN SRV 0 1 587 athome.tld _imap._tcp.athome.tld 86400 IN SRV 0 0 0 . _imaps._tcp.athome.tld 86400 IN SRV 0 1 993 athome.tld ``` Read rfc6186 about these records. (HTM) https://datatracker.ietf.org/doc/html/rfc6186 ## Do not loose mails: MX fields and backup If, for reasons, your server is offline for a few days or a week, mails could be lost. Normally, senders try again for a while if they couldn't deliver a message. However, you can plan secondary mail servers to keep your messages if yours is unreachable. You only need: * Another server (ahem... 😕) * A friend with its own server 😊 It will keep messages for your server in queue and will deliver them as soon it gets back online. On your side, add a new MX field in your DNS zone with a bigger weight. This field points to the secondary server: ``` @ IN MX 10 athome.tld. @ IN MX 70 mail.friend.eu. ``` In the above example, your server is ligther (10) than the secondary (70). This means a sending server will try first to deliver on your server, then on the secondary if the first failed to answer. On his side, your friend just has to add your domain as a backup. If he uses smtpd, then his /etc/mail/smtpd.conf should look like this: ``` action relaybackup relay backup mx "athome.tld" ... match from any for domain athome.tld action relaybackup ``` Of course, you should return the favor 😉. ## Do not be considered as a spam (SPF, DKIM...) Some servers could consider your mails as spams. There are a few proofs of good faith you can setup if possible. They are not mandatory. Keep in mind that most spams comes from most well known servers (gmail, I'm looking at you) so don't be too hard on yourselves. ### Reverse DNS Your ISP might let you configure a reverse DNS. As it suggests, a reverse DNS links your IP to your domain name. Look in your ISP panel for reverse DNS, or ask them directly. They are responsible for this 😉. If you can't and reaaaallly want a rDNS, you could rent a VPN and get a dedicated IP with a rDNS configured by the VPN provider. But in most cases, following next steps should be sufficient. ### SPF SPF records show that only YOUR server is allowed to send mails for YOUR domain name. Since it's usually the server's admin who also deals with DNS record, it's a proof of good faith. Add a DNS record of type SPF in your zone such as: ``` athome.tld. SPF "v=spf1 a mx ~all" ``` Or use a TXT field if SPF is not available: ``` athome.tld. TXT "v=spf1 a mx ~all" ``` Above is a very simple example that works for most cases. Consider reading about SPF records if you want to fine-tune this record. ### DKIM signing With a private key, your server will sign outgoing emails. In DNS records, you will publish a public key to let recipient check if it matches the signature from your server. > Ahem... Say that again? Here we go. We will generate a private and a public key. Private key is used to sign mails. It is "private" because you must be the only one able to add a signature to outgoind mails. Public key displayed in DNS record -- viewable by all -- let one check signature authenticity. You can see it as a unique puzzle piece, the only one that can fit the puzzle. We'll see two ways to sing outgoing messages: one with an smtpd extension, the other with dkimproxy. You also could to the same with rspamd, it is described later, following the same method to generate keys. Choose the one you prefer 😉. Following commands below, you will create a directory for keys, set permissions on this folder and go inside before generating keys with openssl and set permissions on the private part: ``` # mkdir -p /etc/dkim/ # chmod 770 /etc/dkim/ # cd /etc/dkim/ # openssl genrsa -out private.key 2048 # openssl rsa -in private.key -pubout -out public.key # chmod 400 private.key ``` Add a DKIM or TXT field so anyone can check signature on your messages match what is published in DNS records. Mails will receive a flag "dkimpubkey" when signed, it is used to identify the signature in DNS record. * Field name: dkimpubkey._domainkey. * Content: v=DKIM1; k=rsa; p=... Replace ... by the content of public.key: ``` # cat /etc/dkim/public.key ``` The record will look like this: ``` dkimpubkey._domainkey IN TXT ( "v=DKIM1; k=rsa; t=s;p=v+Fb...vhP/oB") ``` Since smtpd has filters support, you can sign your messages with port opensmtpd-filter-dkimsign: ``` # pkg_add opensmtpd-filter-dkimsign ``` Make sure the script can read keys generated as seen before: ``` # chown -R _dkimsign:_dkimsign /etc/dkim/ ``` In /etc/mail/smtpd.conf, you add now a new filter with instructions on how to sign messages: ``` filter "dkimsign" proc-exec "filter-dkimsign \ -d <domain> \ -s <selector> \ -k /etc/dkim/private.key" \ user _dkimsign group _dkimsign ``` Replace <domain> with your domain name and <selector> by dkimpubkey: that's what we defined in the DNS field earlier. Now, make sure outgoing mails are processed by this new filter. In /etc/mail/smtpd.conf, the line for outgoing messages now look like this: ``` listen on all port submission tls-require auth <passwd> filter "dkimsign" ``` As an alternative, you can use dkimproxy if you prefer to sign mails. As usual: ``` # pkg_add dkimproxy ``` Make sure dkimproxy can read keys: ``` # chown -R _dkimproxy:_dkimproxy /etc/dkim/ ``` Now configure dkimproxy to match you configuration (domain and DNS selector): In /etc/dkimproxy_out.conf: ``` listen 127.0.0.1:10027 relay 127.0.0.1:10028 domain athome.tld signature dkim(c=relaxed) signature domainkeys(c=nofws) keyfile /etc/dkim/private.key selector dkimpubkey ``` Of course, edit domain and selector according to your DNS record. Now, tell smtpd to listen for incoming signed and to-send messages on port 10028. They will be tagged "DKIM". Then we can send mails with this tag. On the contrary, they are forwarded to dkimproxy on port 10027. In /etc/mail/smtpd.conf: ``` listen on lo0 port 10028 tag DKIM ... match tag DKIM for any action "sendthismail" match auth tag DKIM from any for any action "sendthismail" ... action dkimproxy relay host smtp://127.0.0.1:10027 ... match auth from any for any action dkimproxy match for any action dkimproxy ``` Finally enable dkimproxy and restart smtpd: ``` # rcctl enable dkimproxy_out # rcctl start dkimproxy_out # rcctl restart smtpd ``` ### Check it works Follow instructions on mail-tester.com. You'll send a mail to a randomized recipient and get a score: (HTM) https://www.mail-tester.com/ (BIN) ../../mail-tester-en.png You may read about dmarc and other advices if you want to fin tune your configuration. Remember your score is already better than most "big" provider. Last time I checked with a gmail address, I got 6.1/10... 😜 See also: (HTM) http://isnotspam.com/ (HTM) https://mxtoolbox.com/deliverability ## Blocking ISP: use external SMTP If your ISP restrict the use of smtp port (25), you can't send any email from your server. To fix this, you may: * Change for another ISP 😁 * Use an external smtp relay. That's what we'll discuss here. However, you need another smtp provider. Put the necessary credentials to access this mail account in /etc/mail/secrets: ``` # echo "secret_id user:passphrase" > /etc/mail/secrets ``` Make sure permissions are appropriate, you don't want everyone to know your password: ``` # chmod 640 /etc/mail/secrets # chown root:_smtpd /etc/mail/secrets ``` Then, edit /etc/mail/smtpd.conf so outgoing messages go through external mail server: ``` ... table secrets "/etc/mail/secrets" ... listen on all... ... action "relay" relay host smtp+tls://secret_id@smtp.example.com \ auth <secrets> mail-from "@athome.tld" ... match from any for any action "relay" ``` Some details: * table secrets ...: file where credentials to auth on external server are stored. * action "relay" relay ...: new action so outgoing messages through external server. Edit smtp.example.com according to your mail provider. * smtp+tls ...: Which protocol is used to communicate with external server. * mail-from "@athome.tld: It is important to show your messages comes from YOUR server, not the relay. In the end, reload smtpd. ``` rcctl restart smtpd ``` Read the example in the end of smtpd manpage to learn more. (HTM) https://man.openbsd.org/smtpd.conf ## Avoid receiving spam: senderscore filter Senderscore keeps a database of mail server reputation. (HTM) https://www.senderscore.org/ A moderate reputation doesn't mean much, but a bad one means the server already has sent spams before. You can use a filter in smtpd to recognize as spam incoming mails according to senderscore. Install opensmtpd-filter-senderscore port. Then, edit /etc/mail/smtpd.conf to add a filter: ``` filter senderscore \ proc-exec "filter-senderscore -junkBelow 70 -slowFactor 2000" ... listen on all tls pki athome.tld filter { senderscore } ``` ## Avoid receiving spams: spamassassin spamassassin is a well-known anti-spam. It is used by OpenBSD project with spamd for their mailing lists. (HTM) https://spamassassin.apache.org/ ### Quick setup using filter-spamassass You may want to use the filter opensmtpd-filter-spamassassin: install the port then read /usr/local/share/doc/pkg-readmes/opensmtpd-filter-spamassassin. In a few words: ``` # pkg_add p5-Mail-SpamAssassin opensmtpd-filter-dkim # rcctl enable spamassassin # rcctl start spamassassin ``` (no need spampd here) /etc/mail/smtpd.conf: ``` filter "spamassassin" proc-exec "filter-spamassassin" [...] listen on all tls pki chezmoi.tld.pki filter { spamassassin senderscore } ``` ### Using tags Let's see how to use it with smtpd using tags since the setup is interesting if you want to understand how things works. Install appropriate ports: ``` # pkg_add p5-Mail-SpamAssassin spampd ``` Then, run spamassassin daemons. You may add a few flags to make sure it is running as we expect. ``` # rcctl enable spampd # rcctl set spampd flags "--relayhost=127.0.0.1:10026" # rcctl start spampd # rcctl enable spamassassin # rcctl start spamassassin ``` Every incoming mails now must be checked by spammassassin, which is listening on port 10025. Once they've been scanned, they will be delivered on port 10026 and tagged "SPAMASSASSIN" so we don't check them twice. That's how it looks in /etc/mail/smtpd.conf: ``` ... # mails checked by spammassassin listen on lo0 port 10026 tag SPAMASSASSIN ... action spamassassin relay host smtp://127.0.0.1:10025 ... # system mails accept from local for local alias <aliases> deliver to maildir "~/Maildir" # Mails scanned by SPAMASSASSIN match tag SPAMASSASSIN from any for domain "athome.tld" action virtual_maildir # not tagged mails, must be checked by spammassassin match from any for domain "athome.tld" action spamassassin ... ``` Spams subject are modified by spammassassin. You can automatically delete them, but it's a risk in case of false positive. (HTM) https://wiki.apache.org/spamassassin/DeletingAllMailsMarkedSpam In order to save spams in a junk folder, modify smtpd's action so it checks for X-spam header: ``` # /etc/mail/smtpd.conf action virtual_maildir maildir "/var/vmail/%{dest.domain:lowercase}/%{dest.user:lowercase}/Maildir" junk virtual <virtuals> ``` ## Avoid receiving spams: rspamd Rspamd is a very complete mail filter. It is not only an anti-spam, but can handle greylisting, DKIM... (HTM) https://rspamd.com/ It is also very fast and efficient. If you want to use it, you should read it's official documentation. For now, let's see how to use it with OpenBSD's smtpd as an antispam and for DKIM. ### Install rspamd ``` # pkg_add rspamd redis opensmtpd-filter-rspamd # rcctl enable redis rspamd # rcctl start redis rspamd ``` Then configure rspamd: ``` # rspamadm configwizard ``` Finally, consider handling too large logs with newsyslog: ``` # Add in /etc/newsyslog.conf /var/log/rspamd/rspamd.log 644 5 300 * Z ``` ### Add rspamd to /etc/mail/smtpd.conf Just add a new filter named "filter-rspamd" and use it for incoming messages. ``` filter rspamd proc-exec "filter-rspamd" # filtre en reception listen on all tls pki athome.tld \ filter { rspamd } ``` ### DKIM with rspamd Since rspamd can handle DKIM signatures, you won't have to configure dkimproxy or another tool. Create keys as described before and make sure they belong to _rspamd group. ``` # chown -R _rspamd:_rspamd /etc/dkim/ ``` Remember to edit your DNS zone 😉. Now create /etc/rspamd/local.d/dkim_signing.conf: ``` # If true, username does not need to contain matching domain allow_username_mismatch = true; path = "/etc/dkim/private.key"; selector = "dkimpubkey"; ``` Then add a few lines in /etc/mail/smtpd.conf to sign outgoing messages: ``` filter rspamd proc-exec "filter-rspamd" # Send and DKIM sign with rspamd listen on all port submission tls-require pki athome.tld auth \ filter { rspamd } ``` ### Greylisting Rspamd does greylisting by default. If you want to still use spamd instead, disable rspamd greylisting in /etc/rspamd/local.d/actions.conf: ``` greylist = none; ``` And /etc/rspamd/local.d/greylist.conf: ``` enabled = false; ``` ### Spamtraps You can use a spamtrap (like what spamd does) using the following lines in /etc/rspamd/local.d/spamtrap.conf: ``` action = "no action"; learn_spam = true; map = file://$LOCAL_CONFDIR/maps.d/spamtrap.map; enabled = true; ``` Then fill /etc/rspamd/maps.d/spamtrap.map with regular expressions of fake trap mail addresses: ``` /^trap@athome.tld$/ /^fake@athome.tld$/ ``` ### Blacklists To do so, use multimap module. (HTM) https://rspamd.com/doc/modules/multimap.html ### rspamd WebUI Dig a SSH tunnel from your computer and open in a browser http://localhost:9999. ``` ssh -N -L 9999:127.0.0.1:11334 sshuser@athome.tld ``` Enjoy wonderfull charts 😄 ## Manage spams with dovecot You might want to help the anti-spam to learn if it missed spams or got wrong for some messages. If you use dovecot and a mail client with IMAP protocol, you can move spams in "Junk" folder so the anti-spam recognize them in the future. On the contrary, moving a mail from "Junk" to "INBOX" folder indicates it is legitimate. No matter if you use rspamd or spammassassin, we explain for both. 3 steps are necessary: * 1. Install dovecot plugin. * 2. Enable and configure the plugin. * 3. Create scripts so the anti-spam can learn. It is described in dovecot documentation (you should read 😉) (HTM) https://wiki2.dovecot.org/HowTo/AntispamWithSieve First, let's install dovecot pigeonhole plugin: ``` # pkg_add dovecot-pigeonhole ``` Add imap_sieve in plugins list to enable it at the end of /etc/dovecot/local.conf: ``` protocol imap { mail_plugins = $mail_plugins imap_sieve } ``` Then, still in dovecot's local.conf, configure sieve plugin so it run scripts according to where messages are moved. ``` plugin { sieve_plugins = sieve_imapsieve sieve_extprograms # When a message is moved in Junk folder; report as spam imapsieve_mailbox1_name = Junk imapsieve_mailbox1_causes = COPY imapsieve_mailbox1_before = file:/usr/local/lib/dovecot/sieve/report-spam.sieve # When a mail is removed from Junk folder: it is nor a spam imapsieve_mailbox2_name = * imapsieve_mailbox2_from = Junk imapsieve_mailbox2_causes = COPY imapsieve_mailbox2_before = file:/usr/local/lib/dovecot/sieve/report-ham.sieve sieve_pipe_bin_dir = /usr/local/lib/dovecot/sieve sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.execute } ``` Now create two files in the directory /usr/local/lib/dovecot/sieve/. The first is report-spam.sieve: ``` require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; if environment :matches "imap.user" "*" { set "username" "${1}"; } pipe :copy "learn-spam.sh" [ "${username}" ]; ``` The second is report-ham.sieve: ``` require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; if environment :matches "imap.mailbox" "*" { set "mailbox" "${1}"; } if string "${mailbox}" "Trash" { stop; } if environment :matches "imap.user" "*" { set "username" "${1}"; } pipe :copy "learn-ham.sh" [ "${username}" ]; ``` Now reload dovecot and compile the above scripts: ``` # rcctl restart dovecot # sievec /usr/local/lib/dovecot/sieve/report-spam.sieve # sievec /usr/local/lib/dovecot/sieve/report-ham.sieve ``` As you may have noticed, the above files call learn-spam.sh and learn-ham.sh. Thoses scripts will be different wether you use rspamd or spammassassin since they don't learn spams/hams with the same command. Read the next part 😉. ### Learning scripts for spamassassin Scripts below are stored in /usr/local/lib/dovecot/sieve/. ``` #!/bin/sh #learn-spam.sh exec /usr/local/bin/spamc -u ${1} -L spam #!/bin/sh # learn-ham.sh exec /usr/local/bin/spamc -u ${1} -L ham ``` You'll have to set appropriate spamassassin flags to use the above scripts : ``` # rcctl set spamassassin flags -l ``` ### Learnin scripts for rspamd Scripts below are still in /usr/local/lib/dovecot/sieve/. ``` #!/bin/sh #learn-spam.sh exec /usr/local/bin/rspamc -d "${1}" learn_spam #!/bin/sh # learn-ham.sh exec /usr/local/bin/rspamc -d "${1}" learn_ham ``` ### Scripts for both Scripts must be executables: ``` # chmod +x /usr/local/lib/dovecot/sieve/learn-*.sh ``` At last, reload dovecot: ``` # rcctl reload dovecot ``` Here you go, now your anti-spam will learn when you'll move messages in approriate folders. Learn more with dovecot official documentation. (HTM) https://wiki2.dovecot.org/HowTo ## Fight against spams before receiving mails: OpenBSD's spamd You can sort incoming spams into a Junk folder. But imagine you can annoy spammers 😁? That's what spamd can do, faking being a mail server and holding spammers so they can't deliver spams while it's talking to them veeery slowly. ### How does spamd work ? You can let somewhere on the web a fake mail address: a spamtrap. Everyone sending a message to this address will be blacklisted and trapped. In the meantime, new senders are greylisted. They're told to try again later. Every proper email server will try again. Spammers won't, so you don't get the spam. Others who try again correctly are put on a whitelist. There is also a blacklist-only mode, trapping IPs from lists you already have. However, this means senders do things correctly. That's is sadly not always true for commercial senders. This said, it is easy to put a server on a whitelist. To keep track of good and bad senders, the command spamd-setup should be run periodically. Everything is very well explained in spamd(8) manpage. You must read it since the following are just advices, not a complete howto. (HTM) https://man.openbsd.org/spamd ### Set spamd up ``` # rcctl enable spamd # rcctl set spamd flags "-v -G 25:4:864" # rcctl start spamd ``` Also enable spamlogd to keep track of servers already whitelisted and to whitelist servers you write to. ``` # rcctl enable spamlogd # rcctl start spamlogd ``` spamd is running in front of smtpd (like a shield, or a janitor 😉). To do so, edit packet-filter configuration: spamd should redirect mails to smtpd if it is not a spam. Add in /etc/pf.conf: ``` table <spamd-white> persist table <nospamd> persist file "/etc/mail/nospamd" pass in on egress proto tcp to any port smtp divert-to 127.0.0.1 port spamd pass in on egress proto tcp from <nospamd> to any port smtp pass in log on egress proto tcp from <spamd-white> to any port smtp ``` On line order: * Define a table to keep track of legitimate senders: <spamd-white> * Create a file /etc/mail/nospamd keeping custom-defined IP spamd should consider as not-spam. * Everything coming on port smtp goes to spamd. * We let in IPs listed in <nospamd> table. * Same with <spamd-white>, IPs known as non-spammers can come in. Remember to reload pf: ``` # pfctl -ef /etc/pf.conf ``` It is necessary to reload spamd blacklist in pf. Edit root's crontab with "# crontab -e" then uncomment the line below: ``` ~ * * * * /usr/libexec/spamd-setup ``` With ~, spamd-setup is run at a random schedule 😉. ### Spamtrap with spamd Let somewhere on the web fake email addresses: spamtraps. Everyone writing to these addresses is a spammer and will be trapped. Of course, those addresses don't really exist! To keep these spamtraps for bots only, you can add such html snippets on your website so they are invisible for human eyes: ``` <a href="mailto:trap@athome.tld"></a> ``` You can copy it on public pastebins too. To teach spamd what are spamtraps, use: ``` # spamdb -T -a 'trap@athome.tld' ``` ### Use pre-existing black/white lists Some nice people gather IP lists and let everyone download them. To use such lists, edit /etc/mail/spamd.conf. As example, the default configuration uses nixspam's list: (HTM) http://www.heise.de/ix/nixspam Add in /etc/mail/spamd.conf the following lines: ``` all:\ :nixspam # Nixspam recent sources list. # Mirrored from http://www.heise.de/ix/nixspam nixspam:\ :black:\ :msg="Your address %A is in the nixspam list\n\ See http://www.heise.de/ix/nixspam/dnsbl_en/ for details":\ :method=http:\ :file=www.openbsd.org/spamd/nixspam.gz ``` At the beginning, you can read all. Then are written lists you want to use and configured below, separated with ":". Use an URL to download the list with spamd-setup automatically or a file already on your server. ### bsdly's blacklist Peter N.M.Hansteen publish a blacklist, gathered with its own spamtraps. (HTM) http://www.bsdly.net/ Avoid to download it too often or you'll be put on a blacklist. Be kind with Peter's bandwidth 😉. To get the list every hour past 20 minutes: ``` 20 * * * * /usr/local/sbin/bsdly-spamd ``` Here is bsdly-spamd script you should copy and make executable: ``` #!/bin/sh # update bsdly.net traplist into DST URL="https://www.bsdly.net/~peter/bsdly.net.traplist" # alternative URL #URL="https://home.nuug.no/~peter/bsdly.net.traplist" DST=/var/db/bsdly.traplist ftp -o "${DST}" "${URL}" ``` Then add the new list in /etc/mail/spamd.conf so spamd uses /var/db/bsdly.traplist file: ``` all:\ :nixspam:bsdlyblack: nixspam:\ :black:\ :msg="Your address %A is in the nixspam list\n\ See http://www.heise.de/ix/nixspam/dnsbl_en/ for details":\ :method=https:\ :file=www.openbsd.org/spamd/nixspam.gz bsdlyblack:\ :black:\ :msg="SPAM. Your address %A has sent spam within the last 24 hours. See http://www.bsdly.net/~peter/traplist.shtml for details.":\ :method=file:\ :file=/var/db/bsdly.traplist ``` ### uceprotect black and whitelists Below we describe how to periodically download lists provided by uceprotect. We will use rsync to reduce bandwidth usage. (HTM) http://www.uceprotect.net/en/index.php Add a new cronjob to call a script downloading lists. Not too often or you'll be blacklisted. ``` 10 * * * * /usr/local/sbin/uceprotect-spamd ``` /usr/local/sbin/uceprotect-spamd is the script below: ``` #!/bin/sh RSYNC="/usr/bin/openrsync -a" URLS="rsync-mirrors.uceprotect.net::RBLDNSD-ALL/dnsbl-1.uceprotect.net rsync-mirrors.uceprotect.net::RBLDNSD-ALL/dnsbl-2.uceprotect.net rsync-mirrors.uceprotect.net::RBLDNSD-ALL/ips.whitelisted.org" OUT="/var/db/RBLDNSD-ALL/" mkdir -p "${OUT}" for URL in ${URLS}; do ${RSYNC} "${URL}" "${OUT}" done ``` Load the lists in /etc/mail/spamd.conf. There are white and blacklists. ``` all:\ :nixspam:bgp-spamd:bsdlyblack:\ rbldnsd-1:rbldnsd-2:rbldnsd-white: ... rbldnsd-1:\ :black:\ :msg="Your address %A is listed on UCEPROTECT-Level 1\n \ see http://www.uceprotect.net/en":\ :method=file:\ :file=/var/db/RBLDNSD-ALL/dnsbl-1.uceprotect.net rbldnsd-2:\ :black:\ :msg="Your address %A is listed on UCEPROTECT-Level 2\n \ see http://www.uceprotect.net/en":\ :method=file:\ :file=/var/db/RBLDNSD-ALL/dnsbl-2.uceprotect.net rbldnsd-white:\ :white:\ :method=file:\ :file=/var/db/RBLDNSD-ALL/ips.whitelisted.org ``` Do not hesitate do donate to uceprotect.net for all their work 😄. ### Common issues with greylisting Some big mail provider uses multiple servers to send mails. If you do greylisting, the IP trying to send an email from a provider might change between two delivery attemps. This means spamd can't recognize a legitimate server, never whitelist the IP and you never get the mail. However, you can whitelists those domains if you want. Create a file containing domains not to greylist: /etc/mail/nospamd_domains_list.txt. ``` gmail.com hotmail.com facebookmail.com apple.com microsoft.com lists.openbsd.org linkedin.com freebsd.org twitter.com amazon.com yahoo.com yahoo.fr live.fr mail-out.ovh.net mxb.ovh.net gandi.net laposte.net protonmail.com ``` Add more domains if you need to. Now create a script to get sending IP of above domains: /usr/local/sbin/generate-nospamd: ``` #!/bin/sh # /usr/local/sbin/generate-nospamd DOMAINS=/etc/mail/nospamd_domains_list.txt WHITELIST=/etc/mail/nospamd echo "#$(date)" > "$WHITELIST" smtpctl spf walk < "${DOMAINS}" >> "$WHITELIST" exit 0 ``` Call this script daily with /etc/daily.local and reload nospamd table: ``` # /etc/daily.local /usr/local/sbin/generate-nospamd pfctl -t nospamd -T replace -f /etc/mail/nospamd ``` ### Blacklist only mode for spamd Read "man spamd" at section "BLACKLIST-ONLY MODE" so you can trap spammers from blacklists files without greylisting. ### See spamd activity Run "spamdb" to see what's happening: ``` # spamdb WHITE|62.4.1.33|||1462699174|1462699174|1465809574|1|0 GREY|182.70.43.24|abts-mum-dynamic-024.43.70.182.airtelbroadband.in|<Estella32@thunderguy.co.uk>|<toto@athome.tld>|1473409924|1473424324|1473424324|1|0 GREY|14.183.132.63|static.vnpt.vn|<Abby5@toddelliott.com>|<kiki@athome.tld>|1473410586|1473424986|1473424986|1|0 ``` Read spamdb(8) manpage to learn what it means. (HTM) http://man.openbsd.org/spamdb To translate times in human-readable format, run date with -r flag: ``` $ date -r 1462699174 Sun May 8 11:19:34 CEST 2016 ``` You can put on whitelist an IP with spamdb -a: ``` # spamdb -a "62.4.1.37" ``` ### Share spamd data between secondary servers Remember to keep spamd databases synchroniszd between your server and backups (secondary MX). Read about -Y and -y flags in spamd manpage. (HTM) https://man.openbsd.org/spamd#Y ## Check everything works well To make sure your mail server works as expected, you can send an email to friends. however, this may be an issue since: * You must wait for their answer. * You won't get every data you may need. * You need friends 😜. Luckily there are robots that can automatically answer. As example: * echo@generic-nic.net * echo@nic.fr * autoreply@dmarctest.org Or see the following websites: (HTM) http://www.mail-tester.com (HTM) https://dkimvalidator.com/results (HTM) https://mxtoolbox.com/ ## What if smtp server doesn't work as expected? You should look at smtpctl command to get details about what's happening. As example, to have generic status: ``` # smtpctl show stats control.session=1 mda.envelope=0 mda.pending=0 mda.running=0 mda.user=0 mta.connector=1 mta.domain=1 mta.envelope=1 mta.host=2 mta.relay=1 mta.route=1 mta.session=1 mta.source=1 mta.task=1 mta.task.running=0 queue.evpcache.load.hit=1675 queue.evpcache.size=2 queue.evpcache.update.hit=6 scheduler.delivery.ok=826 scheduler.delivery.tempfail=6 scheduler.envelope=2 scheduler.envelope.incoming=0 scheduler.envelope.inflight=1 scheduler.ramqueue.envelope=2 scheduler.ramqueue.message=2 scheduler.ramqueue.update=0 smtp.session=0 smtp.session.inet4=787 smtp.session.local=31 smtp.tls=0 uptime=777861 uptime.human=9d4m21s ``` To see awaiting envelopes: ``` # smtpctl show queue 1101f6e60c169eac|inet4|mta||0100015b3a046476-f7d7955a-5842-49af-927c-4fa677f311c6-000000@bounces.duolingo.com|deux@domaine.eu|deux@domaine.eu|1491327053|1491672653|0|5|pending|3154|Network error on destination MXs 1a2123e1c2b3e462|inet4|mta||gitlab@framasoft.org|deux+framagit@domaine.eu|deux+framagit@domaine.eu|1491333449|1491679049|1491333849|1|inflight|50|Network error on destination MXs ``` To see in real time what's happening: ``` # smtpctl monitor ``` And of course; read man smtpctl 😉. --- (DIR) Table of contents (BIN) Donate --- (DIR) /