A word on spammers, broken mail servers, and open relays
We're going to pause here for just a moment to reflect on the configuration choices we're making. The very last thing you want is to set up an "open relay"—a mail server that will happily accept e-mail from anyone and send it to anyone. In ancient times, before spam (yes, there were such days, when dragons roamed the earth) this wasn't bad behavior at all—in fact, it was downright friendly. Those days are long since past, though. Open relays are forbidden since they can be used by spammers to deluge people with spam.
Our Postfix configuration comes out of the box without this
problem—even if you went live with the default Postfix + Dovecot config
mail-stack-delivery package, you wouldn't be an
open relay. However, we're taking things far, far beyond that—the
restrictions we're placing on senders and recipients are strict indeed.
In fact, there's a chance that the hard requirements we're putting in
place on what servers we will and won't talk to will prevent us from
exchanging e-mail with other badly configured but legitimate mail
You know what? Too bad. Seriously. Spammers have absolutely polluted and destroyed e-mail, and not bundling your server with heavy armor is like walking through downtown London on a rat-petting mission during the Black Death. If the party with whom you're going to be communicating can't be bothered to configure their mail server correctly, then you shouldn't be e-mailing them.
I don't want to paint too dark a picture here—you'll almost
certainly have no problems swapping e-mail with every single normal
person you want to communicate with. But the caveat is still worth being
aware of. To that end, the three
reject_code entries under
the "Dealing with rejection" comment section tell our server to reject
messages that match the our rejection criteria with a 550 error, which
should tell the remote server that its message wasn't delivered and it
shouldn't try to send it again (as opposed to the default 450 error,
which implies that the remote server should retry sending.
Now it's time to plug in that SSL certificate you acquired earlier. First, though, we set
smtpd_tls_ask_ccert = yes
to tell Postfix that we want it to ask remote servers to identify
themselves with a certificate. There is another option to actually
require remote servers to do so; that setting makes your server a
lot less friendly, but you might consider doing it if you don't care
about e-mailing any domain that hasn't configured SSL/TLS.
The next two options,
smtpd_tls_key_file, should point to the full path of your SSL/TLS certificate and decrypted key file, respectively.
smtpd_tls_CAfile is used by Postfix to validate
remote servers' certificates. It needs to be a single file rather than a
whole directory, but fortunately, Ubuntu comes with a large Certificate
Authority bundle file at
/etc/ssl/certs/ca-certificates.crt. Point it at that file.
The remaining options should be set as listed, especially
smtp_tls_ciphers = high, since that will force Postfix to not use weak encryption ciphers. Of particular importance is
which is the setting that tells Postfix that it should use SSL/TLS
itself when communicating. "May" tells Postfix that it should use
SSL/TLS if the remote host supports it. There is a stricter option
("encrypt") to force Postfix to always encrypt, but that makes your server non-compliant with IETF RFC 2487
(allowing opportunistic encryption instead of requiring it makes you a
better Internet citizen, but that may not be something you particularly
Virtual user settings and other misc things
The last few sections can be entered as-is. We'll focus on the
settings prefixed with "virtual" in just a moment. Pay particular
attention to the two
smtp_tls parameters—those are required
to make sure your server allows mail clients to send mail with SSL/TLS
encryption rather than forcing them to send mail in the clear.
dovecot_destination_recipient_limit parameter is worth mentioning: it's necessary
because Postfix will be adding a "Delivered-To" header in e-mails it
kicks over to Dovecot for delivery, and so it needs to deliver each
message singly so it can add the header to each one (as opposed to
delivering in a batch).
There's another Postfix configuration file we need to make some changes in, and that'e
This is the file that controls the commands and parameters used when
Postfix connects to various other services (like Dovecot). We've got two
changes to make here: first, to turn on "submission" so that Postfix
listens for incoming mail on port 587, and then to define our Dovecot
/etc/postfix/master.cf for editing. At the beginning, you'll see a number of commented-out lines (
#dnsblog, and so on); locate the line that starts with
#submission and un-comment it, so that it looks like this:
Then, at the bottom of the same file, append the following lines:
(It's important to include the indents at the beginning of the second and third lines.)
Next, we make some maps. But not paper maps—map files!
Mappity-map, then hash back
At several places in our Postfix config file, we reference "maps" and "hashes"—these are lookup files where Postfix stores information. It's possible to use a database like MySQL or PostgreSQL as a data store for Postfix, but to keep things simple we're not going to do that in this tutorial. If you're setting up a large mail server, though, storing lookup items in a database is probably wise. Also, if you're setting up a large mail server, you probably shouldn't be following this guide.
The first map file listed is
/etc/aliases, which tells
Postfix which real local accounts are associated with which e-mail
addresses. Some applications will attempt to send local mail as part of
their normal functioning (like, status reports to the local root
account, for example), so it's not a bad idea to use the aliases file
here to point mail bound for certain local accounts to actual domain
e-mail addresses. Modify the file's contents to look like this:
This will cause all local mail delivery bound for those accounts to be delivered into the "firstname.lastname@example.org" account. As you add applications that create local service accounts, it's a good idea to include them in this aliases file.
Postfix needs a binary version (a hash) of that file, too, so you'll need to run the
newaliases command, which will create a hashed version of the file (named
The next map in this configuration is the
setting. I've included this in here because I use the setting to map
mail sent from my Web server's local service account (www-data) to
instead be sent from an actual mail account I've created. Most
applications let you specify a "from" address, but the canonical map is
useful for those that don't and instead insist dumbly on sending mail
from "email@example.com". My
/etc/postfix/canonical file contains a single entry:
This forces mail sent from "firstname.lastname@example.org" to instead be
sent using "email@example.com," which is the account I use as a
general service delivery type account. You can optionally plug your own
info in there, or you can leave the
canonical_map setting blank and not use it. If you do use it, you'll need to hash the resulting file using the
postmap command, like this:
This will produce a
canonical.db file for Postfix to use.
Next, we'll get into the first portion of setting up our virtual user configuration. This is extremely important, because these next few files will figure heavily into helping Postfix decide where and how e-mails actually get delivered.
The first file to create is simple: the
virtual_mailbox_domains file, which tells Postfix which domain(s) its virtual users live in. Create a new file in
virtual-mailbox-domains and add the following into it:
Then hash it with the
This will create a
virtual-mailbox-domains.db file for
Postfix to read. All of our maps files will need to be hashed with this
command in order to be turned into the binary hash format that Postfix
Next, we need a file for the
in order to actually tell Postfix the virtual users for which it's
responsible for mail delivery. Earlier, we decided on three "real"
virtual users, and this is where they're defined. Create a new file in
virtual-mailbox-users and enter the following:
You can use whatever you want for your main address—your first name, your last name, a nickname, whatever. Same for the "postbot" service account—I use "firstname.lastname@example.org" for mine because that's awesome, but you can do whatever you'd like. Finally, it's wise to have at least one "webmaster" account, specifically named such, in order to prove ownership of the domain. Just make sure you've got two columns, since this file will be used to map e-mail addresses to allowed SASL-authenticated accounts—in other words, one of the things we're defining here is that when you authenticate to Dovecot as "email@example.com," Postfix knows that you're allowed to send e-mail from the "firstname.lastname@example.org" e-mail address.
After the file has been created, hit it with postmap:
The last map is
virtual_alias_maps, where you can link
alias e-mail addresses to real e-mail addresses. For example, want to
very quickly create a "email@example.com" address to use as a
throwaway for registration at a website? Add a line in this file
aliasing "firstname.lastname@example.org" to "email@example.com," and
mail sent to that address will show up in your inbox. When you've gotten
the registration e-mail and clicked the link, you just remove the line
postmap, and the "firstname.lastname@example.org" stops working. Create a file in
virtual and enter the following:
(I also found when configuring Postfix that you do in fact need to alias your real address to your real address as well, hence the first three entries that appear to contain the same address twice.)
It's a good idea to alias a list of other common admin names (hostmaster, postmaster, root, abuse, and so on) to your webmaster account—registrars in particular will sometimes attempt to get a hold of you with those addresses.
In this configuration, Postfix will bounce e-mails sent to addresses not explicitly defined in this file. If you don't want that, though, you can set up a catch-all alias that will route e-mail bound to addresses that don't match any of the aliases. To do this, add the following line at the top of the file:
Substitute whatever account you want to be the dumping ground in place of "email@example.com". I don't do this, but some people want the option.
Once you have your aliases map created and set how you want it, hit it with
postmap to hash it and make it ready for use:
You should see
virtual.db in the directory now, and that's the last map we need to create.
You can go ahead and reload Postfix at this point in order to implement your changes. There are still several lines in the configuration that are commented out, but that's OK—we're going to come back to them. For now, restart Postfix to make the configuration live:
Now, let's get some groundwork laid so that we can do another config job on Dovecot!