Table of contents
- What do we need
- Postfix config
- Dovecot config
- Configure SSL
- Add new email to Gmail
Usually when you open your first domain and want to play around with your own setup you quickly figure out that you need/want to send emails and create email accounts using the very same domain. There are lots of providers that will handle this task for a small monthly fee or maybe your hosting provider offers that in the price you are already paying, but... if you want to learn how to do it by yourself or want to save few bucks with a little bit of extra effort this little guide might save you some time and show how to create secure and reliable SMTP mail server with low maintenance effort.
The setup I am about to show, step by step, will help you to setup your own Postfix mail server that will handle all incoming and outgoing emails for your domain and will keep those emails stored on your Gmail account (no don't need to worry about email storage). At the end you will use Gmail to send and receive emails for your domain email e.g. email@example.com.
So let's see what we want to achieve:
- Emails that we receive for our new email address(s) will be forwarded to our Gmail account so that they are stored there.
- From our Gmail account be able to reply using our new mail address (e.g. firstname.lastname@example.org).
As described, the idea is to use Gmail as our mail client to operate our new domain emails.
My assumption before we begin is that you already registered your domain, know how to manage DNS records (MX, A and TXT) and have basic Linux skills.
For this setup I am going to do it using AWS EC2, so some additional steps will be required.
What do we need
- Ubuntu 20.04 LTS (no worries setup is almost the same on any Linux)
Assuming you have your instance up and running let's install our packages
sudo apt-get update sudo apt-get install mysql-server sudo apt-get install postfix postfix-mysql sudo apt-get install dovecot-mysql dovecot-common
To install Certbot follow the instructions here https://certbot.eff.org/lets-encrypt/ubuntufocal-other.
Preparing the database
Let's create our database and our user for the database. First login to your database as root:
Then let's create our mail database and a user, so we can connect to that database.
CREATE DATABASE mail_server; CREATE USER 'mail_user'@'127.0.0.1' IDENTIFIED BY 'ChangeMe'; GRANT ALL PRIVILEGES on mail_server.* TO 'mail_user'@'127.0.0.1'; USE mail_server;
Next we need our basic tables so we can define domain(s) that this email server will manage, tables for our users (who will be allowed to send emails) and forwarding rules.
And now let's insert our first configuration. For this article I will assume that our domain is example.com and our user who can send emails is email@example.com. Also we will configure one extra email address firstname.lastname@example.org that will be forwarded to our gmail address.
For the password we are using SHA256-CRYPT and this is how you can generated the hash for password:
sudo dovecot pw -s SHA256-CRYPT
In the INSERT statement above we used password youMustChangeMe.
This is the last step of preparation before we begin configuration for Postfix and Dovecot. Since we are using EC2 instance we need to allow incoming traffic on these ports:
- Port 25 - Simple Mail Transfer (SMTP-MTA). Used by MTA to MTA communication (mail server to mail server) also known as SMTP relaying. Described in RFC 5321.
- Port 465 - Deprecated but... Historically, port 465 was initially planned for the SMTPS encryption and authentication “wrapper” over SMTP, but it was quickly deprecated in favour of STARTTLS over SMTP. Because of old systems that are still using it I would recommend still keeping it.
- Port 587 - Message submission (SMTP-MSA), a service that accepts submission of email from email clients (MUAs). When a mail client or server is submitting an email to be routed by a proper mail server, it should always use this port. Described in RFC 6409.
Since we are using AWS EC2 there is one more step we need to do (actually two). By default AWS block all outgoing traffic on port 25 and you cannot enable this on your own. Basically you need to request a support ticket so they enable it for your account. More details and link to support ticket can be found here https://aws.amazon.com/premiumsupport/knowledge-center/ec2-port-25-throttle/. I would recommend (as AWS does in the upper link) when you create a ticket to also tell them to configure reverse DNS (rDNS) records back to your IP addresses. When you send emails, it's a best practice to set up an rDNS record to help prevent outbound emails from being flagged as spam. So basically in our example rDNS for our elastic IP should be mail.example.com (AWS needs to configure this) and our A record should point to the same elastic IP address.
Keep in mind that you could wait several days until AWS allows outbound Port 25 and up to a week until rDNS changes are propagated.
SPF TXT record
The Sender Policy Framework (SPF) is an email-authentication technique which is used to prevent spammers from sending messages on behalf of your domain.
And why do we need this? Well, if you don't set it up most probably your mails will be marked as spam by most other mail servers. It is very easy to set it up since it is just a TXT record in your DNS zone config. An SPF record lists all authorized hostnames / IP addresses that are permitted to send email on behalf of your domain.
So go ahead and create TXT record for your mail domain with the following content.
v=spf1 a mx ~all
This will tell that our A and MX records are allowed to send email for this domain. If you want to know more or have a bit more complex setup I recommend reading here https://www.dmarcanalyzer.com/spf/how-to-create-an-spf-txt-record/.
After your configuration is done you can validate it using a lot of online tools, e.g. https://www.dmarcanalyzer.com/spf/checker/.
Awesome, we are done with all pre-setup and we are ready to jump to configuring our mail server. So what is Postfix? Postfix is a free and open-source mail transfer agent that routes and delivers electronic mail. Check more details here.
Let's start by telling Postfix how to fetch information from our database.
Let's create a file called /etc/postfix/mysql-virtual-mailbox-domains.cf for our virtual_mailbox_domains.
user = mail_user password = ChangeMe hosts = 127.0.0.1 dbname = mail_server query = SELECT 1 FROM virtual_domains WHERE vd_name='%s'
When Postfix receives an email it will first check if does this virtual mailbox domain belong to this server by running the upper query. It is not important what is the result of the query as long as it return something.
Now we need to tell Postfix about our new config. For that we can use this command:
sudo postconf virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
or you can go ahead and directly edit /etc/postfix/main.cf. If you use the command you don't need to reload Postfix. Now we can test our new config:
sudo postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
If everything is ok, you will get '1' printed in your terminal.
We need to tell Postfix about our email addresses that can (are allowed to) receive emails. So let's create /etc/postfix/mysql-virtual-mailbox-maps.cf.
Make Postfix aware about our config:
sudo postconf virtual_mailbox_maps=mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
And we can test the new config:
sudo postmap -q email@example.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
We expect the above command to print '1' if everything is working fine. If you are wondering why we don't use the password here it is because Postfix is just checking if the email address exists and should it receive emails. The password will be needed to send emails from that account and Dovecot will be dealing with this part later on.
Next up is configuring virtual_alias_maps that is used to for forwarding emails from one email address to others. In our case we will forward emails to our gmail address. You can also forward to multiple email addresses in two ways, comma separated email addresses or a new row in the database. If you use multiple email addresses you can actually create a mailing list.
We need to create another config file /etc/postfix/mysql-virtual-alias-maps.cf.
user = mail_user password = ChangeMe hosts = 127.0.0.1 dbname = mail_server query = SELECT va_destination FROM virtual_aliases WHERE va_source='%s'
Tell Postfix about it:
sudo postconf virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf
And we can test our new config:
sudo postmap -q firstname.lastname@example.org mysql:/etc/postfix/mysql-virtual-alias-maps.cf
We should also protect our database password and allow only postfix to read the file by executing the following:
sudo chgrp postfix /etc/postfix/mysql-*.cf sudo chmod u=rw,g=r,o= /etc/postfix/mysql-*.cf
Wow, actually that is now enough for you to receive emails directed to email@example.com and get them delivered to your gmail address. You can now go and test it. I would recommend not to send emails from gmail account that is about to receive the email but rather use some other email address.
Enable SMTP Submission port (587) and SMTP SSL port (465)
By default Postfix will only use SMTP Port 25 but we also want to enable SMTP Submission & SSL ports. To do this edit /etc/postfix/master.cf:
And we need to restart Postfix after above changes.
sudo service postfix restart
But what about sending emails? Let's go ahead and add configuration for that as well...
Normally you use Dovecot to stores emails on your hard disk, applies filters and lets your users fetch their emails using the POP3 and IMAP protocols but in this tutorial we are only using it to provide SASL authentication. Why do we need that?
Well, Postfix SMTP servers need to decide whether an SMTP client is authorized to send mail to remote destinations, or only to destinations that the server itself is responsible for. Usually, Postfix accept mail to remote destinations when the client's IP address is in the "same network" as the server's IP address.
SMTP clients outside the SMTP server's network need a different way to get "same network" privileges. To address this need, Postfix supports SASL authentication. Postfix does not implement SASL itself, but instead uses existing implementations as building blocks. You can use two implementations, Cyrus SASL library or Dovecot. In this article I will show you how to do it using Dovecot.
Let's enable authentication service so that Postfix can use Devecot. We need to edit the file /etc/dovecot/conf.d/10-master.conf, look for section "service auth" and edit to match:
What did we do here? Postfix runs in a chroot environment located at /var/spool/postfix so it can’t access anything outside of that directory. This actually creates socket file communication between Dovecot and Postfix.
Now we need to change the following file /etc/dovecot/conf.d/10-auth.conf. This will enable sql lookup.
Next we need to tell Dovecot how to read our user and password information from the db. For this we will edit /etc/dovecot/dovecot-sql.conf.ext and add the following at the end:
In order to protect the file so you don't leak your password we can change the file access to root:
All that is left now is to restart Dovecot.
sudo service dovecot restart
Finally we can also quickly test this using
sudo doveadm auth login firstname.lastname@example.org
After that if everything works you should see something like "passdb: email@example.com auth succeeded". Don't mind the errors "userdb lookup" since we are not using local storage so it is not important in this setup.
First we need to generate SSL certificates. Use the following command. Before you do it you need to make sure that the A record for your mail domain is pointing to the server you are executing this command from.
sudo certbot certonly --standalone -d mail.example.com
Now let's tell Postfix about it and set our mail hostname.
sudo postconf -e 'smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem' sudo postconf -e 'smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem' sudo postconf -e 'myhostname = mail.example.com'
Test your setup
There are a various online tools to test your setup to make sure your new mail server is secure. Here is some sites that can help you:
Setup another address in your Gmail account
Ok, so we are receiving our emails, but let's configure the sending part as well. For this last step we will jump to your Gmail account and open "Settings" -> "Accounts and Import" and then click "Add another email address". Follow the steps and input your mail server details for your virtual user.
And after this screen you will get a verification email from Gmail and that is it! You can now send email, in our case, as firstname.lastname@example.org When you compose new email in Gmail you will now have a dropdown in "From" field where you can select your new email.
Hope you had fun along the way and learned that is is actually quite easy to setup your own email server for you domain. Postfix is a very powerful, secure and easy to operate SMTP server. Dovecot is an amazing POP3/IMAP server, but in our use case we used it only for authentication so I encourage you to explore it more.
So... at the end we managed to using Gmail as our email client to send and receive emails from our new domain email address :)
- How to host multiple domains on one mail server (multiple SSL configs)
- Limit the users to certain email addresses
- Turn on DKIM signing for your messages
- Publish a DMARC record for your domain
- Create Docker image or EC2 template for the whole setup
- Store emails on your own server (instead of gmail forward) and configure POP3/IMAP so users can get retrieve their emails