Taking (back) control of my email
Intro
Up until recently, my personal email (rolando.cl) was hosted as a google account (I was able to get the free app tier when Google was offering it). It works, but because I'm in a stage where I wanted to be able to take back control of different pieces of my digital life, I decided to give this a try.
The strategy was simple:
Be able to have a working email server that would allow me to receive email and have some basic spam filtering. For sending email, the server should relay to something that's more suited for that (Amazon SES or Sendgrid or something similar).
For accessing emails, it should support IMAP
The solution
My solution was to reuse my current backup server and add the capabilities I wanted. It also gave me the opportunity to update ZFS on that machine and try the new encryption, that way my email would be encrypted on rest.
In the end, this is the high level overview:
- Postfix for sending/receiving emails
- SMTPD (sending) with SASL authentication through dovecot
- Relay to SES for sending emails
- Dovecot for IMAP & auth
- Sieve (Pigeonhole) for email filtering and fun stuff
- Spamassasin for spam filtering
- Email encrypted at rest using ZFS encryption
- Encrypted backups on S3 and other ZFS machine
The auth database for Dovecot is a simple hash database. In the near future, I might add a small service that would manage the static files & sieve filters using a local sqlite database.
Anyway. Let's head into the details. The backup server is an Archlinux ARM machine (rpi3) as described in my post from 2016. It was super easy to install postfix, dovecot and spamassasin. In the next few sections, I'll highlight the details that might be relevant if you want to replicate the setup.
The last two points of my setup are out of the scope of this post, and you should make sure that if you build your own email server, you are able to keep it safe (at least do some backup).
Initial install of things and preparation
The first thing you need to do, is to install the packets. I'm going to assume you're in arch, but replace the commands with your own package manager from your distro:
sudo pacman -Syu dovecot postfix spamassassin pigeonhole
With that done, you can now head to the configuration. I mostly followed the arch wiki for postfix and dovecot. Below are the most important details that might not be exactly the same as in there.
I also used virtual users/domains and followed a very similar scheme as to the one described in the arch wiki for Virtual mail user system (I didn't install roundcube though, I didn't want a web ui on my machine).
Postfix
I decide to use virtual users, but unlike the wiki docs for arch, my database would be just a regular hash-file with the emails. This is my section to cover that:
virtual_mailbox_domains = /etc/postfix/vhosts.txt virtual_mailbox_base = /home/vmail virtual_mailbox_maps = hash:/etc/postfix/vmaps.txt virtual_uid_maps = static:5000 virtual_gid_maps = static:5000 virtual_alias_maps = hash:/etc/postfix/valias.txt virtual_transport = dovecot
You will need to create the vhosts.txt
, vmaps.txt
and valias.txt
as specified in the wiki.
I'm using static uid & gid because all email will live under the user
& group vmail
, that has an id 5000 (created previously). Its home is
under an encrypted zfs dataset, and this is where all the mail is
created. The last line in that section tells postfix to use dovecot to
finally deliver the email. In my case, I'm using LMTP.
In the master.cf
file, the only thing I changed from the default,
was the addition of the dovecot entry, including spamassassin:
dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/bin/vendor_perl/spamc -u spamd -e /usr/lib/dovecot/dovecot-lda -f ${sender} -d ${recipient}
Dovecot
I pretty much followed the instructions in the Arch wiki, however when
generating the dhparam, I used openssl with the -dsparam
option to
avoid waiting forever on my rpi3 (more info about this in this
question on SO), like this:
opennssl dhparam -dsaparam -out /etc/dovecot/dh.pem 4096
To create a user password, you would use something like this:
doveadm pw -s crypt -u user@domain.com
And add the result to /etc/dovecot/users
in the right format:
user@domain.com:<password-hash>
In order to activate auth-passwd for dovecot, you need to un-comment
the right section in 10-auth.conf
and then edit
auth-passwdfile.conf.ext
. Mine looks like this:
passdb { driver = passwd-file args = scheme=CRYPT username_format=%u /etc/dovecot/users } userdb { driver = static args = uid=vmail gid=vmail home=/home/vmail/%d/%n }
This file also tells dovecot to use the /etc/dovecot/users
file for
password authentication, but the user config is "static", in this case
all users will have the same uid
and gid
, as well as home location
(you can use Variables in there as you can tell from my config).
Testing everything
At this point, you should be able to reconfig your mx dns settings and
point them to your new server. If you send a test email from another
server, you should be able to receive it, and it should arrive in
/home/vmail/domain.com/user
. Dovecot should create the root Maildir
in the users' home and you should also be able to connect to your IMAP
server using a regular Email client: I tried iOS Mail.app and
Wanderlust, but pretty much any client should work.
Securing your SMTP
Something you should do, is to make really sure your SMTP server
(postfix) is not an open relay, otherwise it will get abused by
spammers. This should be simple: just restrict relay from everyone,
except authorized (logged in) users. To achieve this, this is my
config (in main.cf
):
# only trust our local machine for relay mynetworks_style = host myorigin = $mydomain # SASL through dovecot smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth # relay settings smtpd_sender_restrictions = permit_sasl_authenticated,reject_unauth_destination
With those settings, you should be able to auth to the SMTP server, it
should use dovecot (as noted by the smtpd_sasl_type
), but there's
one thing you need to change in the dovecot config to reflect that,
you need to tell the dovecot's auth server to use a local unix socket,
in 10-master.conf
:
service auth { unix_listener auth-userdb { } # Postfix smtp-auth unix_listener /var/spool/postfix/private/auth { mode = 0666 } }
If you restart dovecot and postfix at this point, they should be able
to talk to each other. One hint in debugging things, if you're using
systemd
to orchestrate everything (and you should), you can open the
logs for both dovecot and postfix in two separate terminals while
debugging your server:
# open logs (and follow) for dovecot journalctl -f -u dovecot.service # open logs (and follow) for postfix journalctl -f -u postfix.service
Having them open and checking while I was trying to login and send test emails helped me a lot.
Relay (send email)
While you should be able to receive email, with the setup so far, you will not be able to send anything: remember that relay was closed. To fix this, and to make sure that whoever is sending email is a trusted service, I recommend using a third party server that knows how to handle outgoing mail: you can select from many providers, including Gmail if you want. In my case, I opted for AWS Simple Email Service (SES), because I was already using other AWS services from them. The setup should be similar, given that the provider allows sending email through an authenticated smtp server.
In your postfix's main.cf
, you should add something like this:
relayhost = [email-smtp.us-east-1.amazonaws.com]:587 smtp_sasl_auth_enable = yes smtp_tls_security_level = encrypt smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_use_tls = yes smtp_sasl_security_options = noanonymous smtp_sasl_tls_security_options = $smtp_sasl_security_options
What this is doing, is configuring postfix to use SES for relaying, turning on SASL on the smtp protocol, making sure we use TLS, letting postfix know where to find the password for sasl auth when connecting to a smtp server that requests authentication.
The /etc/postfix/sasl_passwd
file looks something like this:
[email-smtp.us-east-1.amazonaws.com]:587 username:password
Both username
and password
are in plain text, so make sure the
file is owned by root
and chmod 0600
. I tried to use dovecot's
auth for that as well but I was not successful. Maybe in the future
^_^.
Sieve for mail filtering
Up to now, you can receive email, it will be scanned by spamassassin
(you should check the headers of your email, they should contain
something like this: X-Spam-Checker-Version: SpamAssassin 3.4.1
(2015-04-28) on alarmpi
). But everything will still arrive in your
Inbox. In order to take action on that, you can use something like
Sieve.
Dovecot supports Sieve through pigeonhole
, you should have this
already installed from the first part of this post.
You can go super fancy with filters: having global filters that act on all of your users' emails, vacation responders, whitelists, etc. You can also have a per-account filter (just a single file in your virtual user home) and that will be triggered every time you receive email. That's the approach I went for simplicity (I only have one account, my own personal one) and it makes it easy for me to add/remove things as I want.
To enable Sieve support in dovecot, you need to modify the
corresponding config, in my case it was 90-sieve.conf
:
plugin { sieve = file:~/current.sieve }
This is telling Dovecot that if there is a file named current.sieve
in the user's home (virtual user home, in my case
/home/vmail/domain.com/user
), try to use that as the active sieve
filtering script.
My script is basically filtering for spam, and also some sort of white-list: only specific users go directly to Inbox, the rest (if they're not spam), go to Inbox.Other:
require ["fileinto", "reject", "mailbox", "imap4flags"]; if header :contains "X-Spam-Flag" "YES" { addflag "\\Seen"; fileinto :create "Spam"; } elsif not address :is "from" ["m@rolando.cl", "user@domain.com", "user2@domain.com"] { fileinto :create "INBOX.Other"; }
Writing Sieve filters can be tricky at first, but they are super helpful. You can find a bunch of examples in the Dovecot documentation.
Final remarks
If you followed everything, you should have a working email server
that will receive all your email (make sure to have backups and/or
encrypt /home/vmail
) and securely send your email through a trusted
provider. I hope you enjoyed and that this tutorial/post helped you
learn more about Email serving. It's not an easy task but for me
personally, it's something I wanted to do for a long time.