summaryrefslogtreecommitdiff
path: root/source/blog/2020/email-server/index.md
blob: 962e6aa7676d194c87b4a8662cd47bf7cf414030 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
---
title: "Setting up an email server in 2020 with OpenSMTPD and Dovecot"
date: 2020-04-27
layout: "blog"
toc: true
---

So, you want to set up your own email server? In that case, welcome.

There are many reasons to run a custom email server,
ranging from privacy concerns about providers like Google,
to just wanting to do it for fun and/or learning.
Since you're here, I assume you've already found a reason.

Beware: this is a messy topic, and the available documentation
is even messier, so it could take a while before you get it to work properly.
I've compiled this guide according to my experiences
in an attempt to make this dark art more accessible,
but your mileage may vary considerably. I hope you find it useful.

This guide is aimed at people who are comfortable with
the Linux/*BSD command line.

When you're done (if you get that far), take a look at the sequels
"[Setting up an email server in 2020 with OpenSMTPD and Dovecot: extras](/blog/2020/email-server-extras/)"
and "[Revisiting my email server in 2022](/blog/2022/email-server-revisited/)"
for ideas on how to extend your setup.

Last updated on 2022-09-12.



## Preparation

Setting up email is relatively complex compared to e.g. a static website,
because you need to configure not one, but *two* server programs,
*and* you need to shoehorn modern security features into email's Stone-Age design.
I'll start by explaining the general structure of a mail server setup.



### How email works

The programs involved in the exchange of emails are called [agents](https://en.wikipedia.org/wiki/Email_agent_(infrastructure)).
Officially, there are 5 different types of agent: MUA, MSA, MTA, MDA and MRA.
But fortunately, it's reasonable to treat the MRA and MSA
as being part of the MUA and MTA, respectively.

The *Mail User Agent* (MUA) is simply the client on your device at home
that you use to send and receive emails, and this guide assumes
you already have a favourite program for this, e.g. [Thunderbird](https://www.thunderbird.net/en-US/).
Nowadays it's fashionable to use a web interface for emails,
but that's also beyond the scope of this guide.

The *Mail Delivery Agent* (MDA) is a program that watches over
the server's copy of your mailbox: it manages your inbox,
remembers which messages you have or haven't read,
keeps a copy of your drafts, etc.
When you open your mailbox, your MUA will connect to
your server's MDA using the [IMAP](https://en.wikipedia.org/wiki/Internet_Message_Access_Protocol) protocol
(or [POP3](https://en.wikipedia.org/wiki/Post_Office_Protocol), but that one's [obsolete](https://pop2imap.com/)).

The *Mail Transfer Agent* (MTA) is responsible for
making messages arrive at the right destination.
When you send an email, your MUA will pass it on to your server's MTA,
which will in turn pass it on to the recipient's mail server.
Likewise, when someone sends *you* an email from another server,
the MTA will receive it and hand it over to the MDA so you can read it later.
In both cases the MTA speaks the [SMTP](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol) protocol.

In this guide our MDA will be [Dovecot](https://dovecot.org/),
which is a very popular choice for that role.
As for the MTA, there exist several options,
the most popular being [Postfix](http://www.postfix.org/) and [Exim](https://exim.org/).
However, this guide uses the newer, lesser-known [OpenSMTPD](https://opensmtpd.org/),
which in my experience is *much* easier to set up:
Postfix and Exim have complex configurations and
are geared towards large-scale email providers,
whereas OpenSMTPD is more beginner-friendly.



### Security

The base email system is horribly insecure on its own,
so we still need to duct-tape on some security features.
In this context, "security" has two meanings:
spam protecion and privacy protection (encryption).

Spam protection also means two things here:
defending yourself against spammers, and
preventing that *your* emails get flagged as spam.
The former is optional, but the latter is not:
big providers such as Google and Microsoft
use infamously strict spam filters,
and if they decide that your server is a spammer,
there's almost nothing you can do about it.
Spam protection techniques will be discussed
in more detail over the course of this guide.

Privacy protection is important in the 21st century:
you don't want a random router in the Internet to read all your emails,
which may contain sensitive information such as
private conversations and account password reset links.
You should therefore try to make sure that emails are
transported over an encrypted channel.
To do this, you have two options for encryption:
*mandatory* and *opportunistic* encryption.

Mandatory encryption is only practical for client-server
communication (not server-server), and is provided by IMAPS and SMTPS,
which wrap the IMAP and SMTP protocols in [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security),
in the same way that [HTTPS](https://en.wikipedia.org/wiki/HTTPS) does for [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol).

For server-server communication, the only option is
opportunistic encryption in the form of [STARTTLS](https://en.wikipedia.org/wiki/STARTTLS),
where communication is only encrypted if both parties agree
after a short unencrypted discussion.
That last part is vulnerable to [MitM](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) attacks,
where anyone along the path of the email servers' discussion
can alter the exchange to block the use of encryption,
which sometimes actually [happens](https://www.eff.org/deeplinks/2014/11/starttls-downgrade-attacks) in practice.

The only way to make sure that STARTTLS is used in that case
is to refuse any exchange unless the servers agree to use encryption.
Unfortunately, that's a risky approach that I can't recommend,
because not all servers support encryption (unbelievable, right?).
For example, I've received airline booking confirmations,
full of personal details, and made with billion-dollar companies,
sent across the Internet without any protection.

This guide includes intructions to enable encryption,
but assumes that you already have a TLS certificate for that.
If not, find a guide to get one from [Let's Encrypt](https://letsencrypt.org/) (it's free!),
and remember that you'll need to renew it every few months.
Using a self-signed certificate *may* work, but I don't recommend it.

In the rest of this guide I'll assume that
you have a public full-chain TLS certificate at `/etc/ssl/certs/example.com.pem`,
and a private encryption key at `/etc/ssl/private/example.com.pem`.



### Server

Obviously, you'll need a server to run the MTA and MDA on.
You can host your own at home, but the more reliable option is
to rent one in a data center ([VPS](https://en.wikipedia.org/wiki/Virtual_private_server)).
This guide was written with a Linux server in mind,
but in theory it should also work on the BSDs
([OpenBSD](https://www.openbsd.org/), [FreeBSD](https://www.freebsd.org/),
[NetBSD](https://www.netbsd.org/), etc.) with minimal adaptation.

The server must be online 24/7, you must have root SSH access,
it must have a static IP address, and TCP network port 25 must be open.
Especially check that last one: you may need to explicitly ask
your home ISP or the server provider to enable port 25,
because they often close it to prevent spam.
You can usually do this from their web interface.

You also must have a domain name, which I'll call `example.com`.
This will be necessary for basically everything:
DNS records, TLS certificate, MTA network configuration, etc.
If you don't have one yet, you can choose between many registrars
to rent one from. Personally I use and can recommend [Gandi](https://www.gandi.net/).

Note that it's a **bad** idea to use a domain like `foo.bar.com`,
where you control the `foo` part but *not* the `bar` part:
in that case, a spammer in control of `qux.bar.com`
could negatively affect *your* reputation
in the eyes of other email providers.

Lastly, when setting up an email server, you also have the choice
between using to *system* users or *virtual* users.
With system users, if an email arrives for `john@example.com`,
then the MTA and MDA will expect that there exists
a `john` Unix user on the server to deliver it to.
With virtual users, you have much more flexibility, so that's what we'll use.
All email will be managed under a single Unix user/group called `vmail`.
Create it as follows:
```sh
# GNU CoreUtils:
$ groupadd vmail
$ useradd -g vmail vmail
# BusyBox:
$ addgroup vmail
$ adduser -D -G vmail vmail
# *BSD:
$ no clue, but it should be similar
```


## DNS records

Now we must set up all the necessary DNS records, which
is usually possible from the domain registrar's web interface.
It may take a while for your changes to propagate over the Internet,
so I recommend doing this section now and the rest tomorrow.

Firstly, you should already have an A and/or AAAA record
to associate your domain `example.com` with the server's IP address.
For email it is **essential** that you also have [reverse DNS](https://en.wikipedia.org/wiki/Reverse_DNS_lookup)
set up correctly. If you're renting your server remotely,
you can often do this from the provider's configuration tool,
otherwise, you should create a PTR-type DNS record,
although that's beyond the scope of this guide.

Once you're done, I recommend testing your DNS records
using the [MX Lookup](https://mxtoolbox.com/MXLookup.aspx) online tool.



### MX

To inform the rest of the Internet that your server is an email server,
create an MX (Mail eXchanger) DNS record for your domain.
Note the dot at the end of the domain name:
```sh
example.com. MX 42 example.com.
```
When a message is sent to an email address ending in `@example.com`,
the sender will query DNS for any MX records for `example.com`.
There it will find a domain name (in this case `example.com` again),
for which it will look up the IP address using an A/AAAA record.
The domain name in the record must **not** have an associated CNAME record;
it must be directly translatable to an IP address.

You may have multiple MX records, containing different domain names,
each with a preference number (`42` in the example above).
The sender will try MX records with *lower* numbers first,
and if that server is unavailable, it will try a higher number.
If you have multiple mail servers (which is a good idea),
you can thus declare those as follows:
```sh
example.com. MX 13 mx1.example.com.
example.com. MX 42 mx2.example.com.
```
Here, a server sending an email to your domain `example.com`
will try to send it to the IP address of `mx1.example.com` first,
and if that fails, it will move on to `mx2.example.com`.
If both `mx1` and `mx2` have the same number, then the sender
will randomly choose one, which is useful for load balancing,
although that's probably overkill for a private server.



### SPF

The [Sender Policy Framework](https://en.wikipedia.org/wiki/Sender_Policy_Framework) (SPF),
is a feature which helps prevent spammers from impersonating
your server in an attempt to get around blacklists.
This security feature is **required** nowadays:
if you don't use it, you'll probably get flagged as spam.

SPF works by specifying which IP addresses are authorized
to send emails from your domain name.
You must publish this information in a
TXT-type DNS record (**not** SPF-type, which also exists!) with the following contents:
```sh
example.com. TXT "v=spf1 mx -all"
```
Everything after the version `v=spf1` is a list of *verification mechanisms*
for a spam filter to try out in the given order.
The `-all` at the end says to reject your email
if all of the previous mechanisms fail.
See the [SPF spec](https://tools.ietf.org/html/rfc7208) for details.

I recommend only using the `mx` mechanism, which tells the verifier
to look at the A/AAAA addresses of the domains in your MX records.
This allows you to add, remove, or change your servers
without needing to update this record.



### DKIM

Then we have [DomainKeys Identified Mail](https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail) (DKIM),
which is a more comprehensive form of anti-impersonation,
and, like SPF, is practically **mandatory** in the modern era.

It adds a cryptographic signature to all emails from your server,
which the receiver's spam filter will verify using the email's contents,
and a public key that you need to publish in a DNS record.
Again, you should implement *both* SPF and DKIM, despite their overlap.

To set up DKIM, create an RSA keypair, using the `openssl` utility:
```sh
$ openssl genrsa -out /path/to/dkim/private.key 2048
$ openssl rsa -in /path/to/dkim/private.key -out /path/to/dkim/public.key
```
The minimum size is 1024 bits, but I recommend 2048 bits.
Bigger is better, but because DNS is involved you can't stretch it
to 4096 bits without causing discomfort to [some](https://serverfault.com/questions/747185/dkim-can-i-use-a-rsa-key-larger-than-2048bit-i-e-4096) servers.
And I think it goes without saying that you should keep the private key private.

Importantly, the DKIM DNS record **cannot** be
attached directly to your domain `example.com`;
instead, it should belong to a subdomain of the form
`<selector>._domainkey.example.com`,
where `<selector>` is an alphanumeric string you can choose (e.g. today's date),
just remember your choice for later when configuring the DKIM signer.
And if you change your key, keep the old record around
for a while so old emails can still be verified.

Your DKIM policy must be published in a TXT record
as follows, where `<pubkey>` is the public RSA key `MI...AB`
stored in `/path/to/dkim/public.key`, with the newlines removed:
```sh
<selector>._domainkey.example.com. TXT "v=DKIM1; t=s; h=sha256; p=<pubkey>"
```
Here, `v=DKIM1` is the version and must be the first tag.
The flag `t=s` enables strict mode, as recommended by the [DKIM spec](https://tools.ietf.org/html/rfc6376),
meaning that emails sent from subdomains immediately fail verification.
The optional tag `h=sha256` blocks the use of the old SHA1 algorithm.



### DMARC

Lastly, we have [Domain-based Message Authentication, Reporting and Conformance](https://en.wikipedia.org/wiki/DMARC) (DMARC),
which is *technically* optional, but *highly* recommended,
because it will make you look more legitimate in the eyes of Google and Microsoft.
It can modify the behaviour of SPF and DKIM,
and also provides advice about what a receiver should do
if one of your emails fails verification.

To enable it, create yet another TXT record, which,
similarly to DKIM, **must** belong to the subdomain `_dmarc.example.com`,
and give it the following contents,
where `<admin>` is an email address of your choosing,
which may or may not belong to your domain:
```sh
_dmarc.example.com. TXT "v=DMARC1; p=reject; sp=reject; pct=100; aspf=s; adkim=s; fo=1; ruf=mailto:<admin>"
```
The version tag `v=DMARC1` must come first,
followed by `p=` and `sp=`, which control what to do to unverified messages
coming from the main domain and subdomains, respectively.
Here, `reject` means that delivery should be refused,
`none` asks to let it through anyway, and `quarantine` tells
the filter to take a closer look or to put it in a spam folder.
The percentage `pct=100` says how many of your emails to apply the policy to.
Next, `aspf=s` and `adkim=s` enable strict mode for SPF and DKIM,
which blocks subdomains from passing.
Finally, `fo=1` asks for a forensic report if verification fails,
and `ruf=` gives an address to send it to.
If in doubt, see the [DMARC spec](https://tools.ietf.org/html/rfc7489).



## MDA: Dovecot

[Dovecot](https://www.dovecot.org/) is a very popular IMAP server,
focused on being lightweight, simple, and secure,
and has extensive and up-to-date documentation.
It's very flexible and scalable, and keeps up well
with the lastest security best-practices.

If you installed Dovecot via a package manager,
you'll probably have lots of configuration files
in the `/etc/dovecot` directory.
I want you to delete all of them. Yes, `rm -rf` that crap.
Dovecot is simple to configure, and doesn't care where
you put its settings, so having all that chaos in `/etc/dovecot`
just makes things unnecessarily confusing.



### Network

Create a new configuration file `/etc/dovecot/dovecot.conf`,
and start by filling in the details of your TLS certificate,
making clear that unencrypted connections are unacceptable:
```sh
ssl = required
ssl_cert = </etc/ssl/certs/example.com.pem
ssl_key  = </etc/ssl/private/example.com.key

ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes

disable_plaintext_auth = yes
```
The final `disable_plaintext_auth` option tells Dovecot
to reject any passwords that were sent unencrypted.
This means it must be [hashed](https://en.wikipedia.org/wiki/Cryptographic_hash_function)
or sent over an encrypted connection, or both.

Next, tell Dovecot which protocols to use
and where to expect them as follows:
```sh
protocols = lmtp imap

service lmtp {
	unix_listener lmtp {
		user  = vmail
		group = vmail
	}
}

service imap-login {
	inet_listener imap {
		port = 143
	}
	inet_listener imaps {
		port = 993
	}
}
```
LMTP is the Local Mail Transport Protocol, which is basically SMTP
but for exchanges within a single server or over a trusted network.
When an email is received, Dovecot will start a child process
under the `vmail` user/group to deliver the message to its recipient.

Since we set `ssl = required` earlier, clients will only get their mail
if the STARTTLS handshake was successful during the IMAP exchange,
or if they connect via IMAPS to force the use of encryption.
You can therefore optionally remove one of the two
`inet_listener`s according to your preferences.



### Users

Next, we need to inform Dovecot which email addresses it should handle,
and what to do with their messages. Create a file `/etc/dovecot/users` for this,
which describes a user on each line in a similar format as `/etc/passwd`:
```sh
user:password:uid:gid::homedir
```
In this guide, we're using the `vmail` user for all accounts,
so leave the `uid`, `gid`, and `homedir` fields blank.
We'll be storing all emails in `vmail`'s home directory.
The `user` field should be the email address excluding the `@example.com`
(in fact, you *can* include it, but this guides assumes a small-scale
server managing only one domain, so we exclude it).
Create the password hash to put in the `password` field as follows:
```sh
# If your server is fast and has lots of RAM:
$ doveadm pw -s ARGON2ID-CRYPT
# If you're using a potato:
$ doveadm pw -s SHA512-CRYPT
```
After you've entered your password, simply copy-paste the entire
hash string outputted by the program into the `password` field.

Now, Dovecot needs a file describing user accounts on two separate occasions:
* To check whether a client logging into the IMAP server
  is valid and has given the right password.
  This is handled by the `passdb` block(s) in the configuration.
* To know which email addresses the server is responsible for.
  This is given by the `userdb` block(s) in the configuration.

These functions aren't necessarily fulfilled by the same `users` file:
you can map multiple email addresses to one acccount,
or multiple accounts to one email address.
For simplicity, though, we'll use the `users` file for both:
```sh
passdb {
	driver = passwd-file
	args = scheme=ARGON2ID-CRYPT username_format=%n /etc/dovecot/users
	#args = scheme=SHA512-CRYPT username_format=%n /etc/dovecot/users
}

userdb {
	driver = passwd-file
	args = username_format=%n /etc/dovecot/users
	override_fields = uid=vmail gid=vmail home=/home/vmail/%n
}
```
The `driver` option sets the kind of table Dovecot should expect.
We tell it to use a file in the `passwd`-like format described above,
but other possibilities include e.g. an SQL database.
The options available in `args` depend on the chosen `driver`.

In the `passdb` block, the hashing algorithm is given by `scheme`,
while `username_format=%n` says that the `users` file
only contains `name` out of `name@example.com`.

In the `userdb` block, we force the use of `vmail:vmail`
for all accounts, and tell Dovecot to put their data in `/home/vmail/%n`,
where `%n` means the address up until the `@`, so
e.g. mail to `name@example.com` is stored in `/home/vmail/name`.

Now that Dovecot knows where to store messages,
we just need to specify in what format to store them:
```sh
mail_location = maildir:~/Maildir
```
The two standard mailbox formats to choose from are `maildir` and `mbox`.
I highly recommend `maildir`; it's more modern than the ancient `mbox` format.
That `~/Maildir` says which subfolder to use.
Ensure that `/home/vmail` is owned by `vmail:vmail`,
so that Dovecot has write access.



## MTA: OpenSMTPD

[OpenSMTPD](https://opensmtpd.org/) is an MTA by the [OpenBSD](https://www.openbsd.org/) project,
who are known for their focus on security and minimalism.
Compared to other MTAs it's a joy to set up, thanks to
its intuitive configuration syntax and to-the-point manual.
This guide is for OpenSMTPD version 6.4 or newer:
older versions used a substantially different syntax.

If you have any problems with OpenSMTPD,
take a look at the maintainer's [blog](https://poolp.org/),
which contains a lot of useful information,
and was a big help when writing this guide.



### Users

To begin, delete the contents of the `/etc/smtpd/aliases` file,
if it exists, which maps recipient addresses to system users.
In our case, we're using `vmail` for everyone,
and we'll let Dovecot manage the details by simply writing:
```sh
@ vmail
```
Then create a new file `/etc/smtpd/passwds`
and fill it in according to the following format,
where `<user>` could be anything you want,
not necessarily the same account name as in Dovecot:
```sh
<user> <hash>
```
Generate the password hash with this command for each user.
Again, the password doesn't need to be the same as in Dovecot,
but for your own convenience it's probably best if it is:
```sh
$ smtpctl encrypt '<password>'
```
Then, like with Dovecot, just delete the contents of
the main config file  `/etc/smtpd/smtpd.conf`,
and start by putting in the following:
```sh
table aliases "/etc/smtpd/aliases"
table passwds "/etc/smtpd/passwds"
```


### Network

Write your domain name on a single line in `/etc/smtpd/mailname`.
This is the name that OpenSMTPD will use to introduce itself
to other servers, and it's important that this matches
the reverse DNS domain name of the server's IP:
```sh
example.com
# Or mx1.example.com or whatever
```
Then continue in `/etc/smtpd/smtpd.conf` by importing your TLS certificate:
```sh
pki "example.com" cert "/etc/ssl/certs/example.com.pem"
pki "example.com" key "/etc/ssl/private/example.com.key"
```
And tell OpenSMTPD which keys to use for the [Sender Rewriting Scheme](https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme),
which prevents forwarded emails from breaking SPF and looking like spam:
```sh
srs key "<secret1>"
srs key backup "<secret2>" # optional, read below
```
It's recommended to change the key every year or so,
but in that case you need to ensure that emails from the last month
can still be verified using the old one, so if you change it,
simply move it to the backup slot for a month.

It's very important that the secrets can't be guessed,
otherwise *anyone* can send mail through your server,
so I recommend generating these keys randomly as follows:
```sh
$ head -c 30 /dev/urandom | base64
```
Next, define the spam filters as follows.
For the last line to work, you'll need to [download](https://github.com/poolpOrg/filter-rspamd)
and build the `filter-rspamd` adapter binary for yourself,
created by OpenSMTPD's official maintainer.
We'll set up the Rspamd service in the next section,
which will be responsible for spam filtering and DKIM signing:
```sh
filter   "rdns" phase connect match   !rdns disconnect "550 DNS error"
filter "fcrdns" phase connect match !fcrdns disconnect "550 DNS error"
filter "rspamd" proc-exec "/etc/smtpd/filter-rspamd"
```
I cannot overstate the importance of the first two lines:
these will block hundreds of spam attempts, and have,
at least for me, never blocked anything legitimate so far.

The only thing left to do here is to tell OpenSMTPD which ports to listen on
and what to do with the incoming traffic.
This comes in two parts: first, we listen on port 25 for incoming
messages for your domain coming from other email servers:
```sh
# Inbound
listen on eth0 port 25 tls pki "example.com" filter { "rdns", "fcrdns", "rspamd" }
action "RECV" lmtp "/var/run/dovecot/lmtp" rcpt-to virtual <aliases>
match from any for domain "example.com" action "RECV"
```
Line 1 says to listen on `port 25` of interface `eth0`,
providing *optional* `tls` using the certificate for `example.com`,
and passing everything through the three filters definer earlier.
Making TLS mandatory is a **bad** idea here, because not all servers can use TLS.

Line 2 defines an action called `RECV`,
which relays an email to Dovecot's LMTP socket,
with the `rcpt-to` and `virtual` making sure
that Dovecot will actually accept the message.

Line 3 then simply says that any incoming mail
for your domain should have the action `RECV` applied to it,
unless the spam filters rejected it.

Secondly, we listen on port 465 (SMTPS)
and/or port 587 (STARTTLS) for messages getting sent
from your email client to the rest of the world,
so we require user authentication:
```sh
# Outbound
listen on eth0 port 465 smtps       pki "example.com" auth <passw