How I made my own send-and-receive email server

Saarang
13 min readMar 31, 2024

--

Using the SMTP protocol in order to send mail

As you climb up higher and higher up the web development ladder, you’re eventually going to reach a point where you might want to add email support to your web application, whether that be for customer support or for a simple password reset. From what I’ve seen, a lot of these companies have their own limitations and whatnot, so while most of the solutions out there like Resend will probably be viable for most people, I decided that I’d rather create a mail server because why not (lol). This article will cover the following:

  1. IMAPS/SMTPS protocols
  2. How to rent out your own virtual machine
  3. How to install an SSL certificate
  4. How to install the IMAPS / SMTPS software we’ll be using & how to configure these 2 tools together
  5. How to connect to your IMAPS server
  6. How to get removed off blocklists

I will try to explain everything clearly, and if you want to skip to a part, feel free to search via the header.

IMAPS / SMTPS protocols

Before we can get started, you should probably understand the basics about these 2 protocols and what they are.

The IMAP, or the Internet Messaging Access Protocol, is pretty much what the name implies it to be. It allows you to access your messages (or in this case your emails) from a remote server. This will be important for later when you want to access your mail.

The SMTP, or the Simple Mail Transfer Protocol, is a protocol that is used for sending mail to another server, and also receiving it. This protocol however does not cover you being able to see your own mail from a remote desktop, which is why you generally see these two together when creating mail servers.

Now that you know the basics, let’s get started!

How to rent out your own virtual machine

I’ve went over this several times in the past when it comes to creating a virtual machine on DigitalOcean, so I’ll skip to the part after you create an account.

After you’ve created an account, you’re gonna want to click “Create” at the top and select “Droplets”

Click “Droplets” at the very top

After you do this, it’ll give you some configuration options. For the purposes of this tutorial, I’ll be using SFO3 as my datacenter, Ubuntu 22.04 LTS, and the cheapest plan, that being the regular $4/month VM.

Configuration options

You can use a password for the purposes of the tutorial as well, though ssh is generally recommended for projects that require more security. You can add on more stuff if you wish, but this is just the bare bones. Now, after you specify a name, press “Create Droplet”. Once you click on your droplet, you can press “console” to login.

Now, let’s move on to setting up your server!

How to install an SSL certificate

You should already have a registered domain prior to entering this tutorial, so let’s move on to actually making the certificate. We’ll be using Let’s Encrypt for this task.

First of all, you want to add in an A record on your “mail” subdomain that points to your virtual machine’s IP address, and also an MX record that points to that subdomain so that mail can route to it, like so:

The MX record will be important for later in the tutorial when we setup our actual server and whatnot.

Now we can start installing the certificate. Open up the VM’s terminal and run the following commands to install certbot:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot

After installing it, you want to issue a new certificate for your mail server, like so:

sudo certbot certonly --standalone -d mail.[root domain]

This should issue both a private key and a full chain for your respective subdomain, assuming you setup your DNS properly.

We’ll also need to install the Let’s Encrypt CA, so click on this link in order to install it. You will want to copy the contents of the file from the file to the /etc/ssl/ca.pem file in your VM, which can easily be done with a simple nano command:

nano /etc/ssl/ca.pem

You will want to make sure nobody can edit this file also, using a simple chmod command:

chmod 600 /etc/ssl/ca.pem

Now that we got that sorted out, let’s install our actual servers.

How to install the IMAPS / SMTPS software we’ll be using & how to configure these 2 tools together

We’re gonna be using both dovecot & postfix respectively to configure these two. Let’s first start off with configuring postfix.

First, you’re gonna want to update your apt cache, and then install postfix:

sudo apt update
sudo apt install postfix

You’re now gonna get a series of prompts, so answer with the following:

Set your Mail Configuration to “Internet Site”

Set your System Mail Name to your root domain, which for this tutorial I’ll be using gdmobilewrlist.com

After the installation is complete, we’re going to have to configure some more things. Open up the postfix config file like so:

nano /etc/postfix/main.cf

And go to the line that says “mydestination”. Your config should look something like this, stating localhost.localdomain, localhost, mail.[root domain], and [root domain] like so:

Also, your host name should be wherever you plan to host your mail server, in my case being mail.gdmobilewrlist.com:

Next, you’re going to want to configure your home_mailbox to the Maildir/ directory, and for security reasons, you’re also going to have to add a number of lines to prevent anyone authenticated from entering your server:

home_mailbox = Maildir/
smtpd_sender_restrictions = reject_sender_login_mismatch
local_recipient_maps = proxy:unix:passwd.byname $alias_maps
smtpd_relay_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
smtp_sasl_auth_enable = yes
smtpd_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/password
smtpd_sender_login_maps = hash:/etc/postfix/login_maps

All of this should be at the very end of the file, and you’re going to also want to delete a previous line from up top that specifies the “smtpd_relay_restrictions”.

Afterwards, you want to go the section that says “TLS parameters”. Delete everything under it, and put these parameters instead:

smtpd_tls_chain_files =
/etc/letsencrypt/live/mail.[root domain]/privkey.pem,
/etc/letsencrypt/live/mail.[root domain]/fullchain.pem
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_tls_security_level=may
smtp_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3
smtp_tls_CApath=/etc/ssl/ca.pem

You can see our chain files, which we created earlier, and also that CA file that I told you to install as well.

After this, you’re going to want to save and exit. Create an empty password & login_maps file like so:

touch /etc/postfix/password
touch /etc/postfix/login_maps

After you create these files, you want to map them into database files so that postfix can read off of them. You can do this using the postmap command:

postmap /etc/postfix/password
postmap /etc/postfix/login_maps

Afterwards, create a Mailbox directory in the root dir:

mkdir /Mailbox

And then restart postfix now:

postfix stop && postfix start

Now we can configure dovecot. You want to first install dovecot like so:

sudo apt install dovecot-core dovecot-imapd

Go to the dovecot config file like so:

nano /etc/dovecot/dovecot.conf

and comment out all the contents in there. Replace it with these lines:

disable_plaintext_auth = no
mail_location = mbox:~/mail:INBOX=/var/mail/%u
mail_location = maildir:~/Maildir
mail_privileged_group = mail
userdb {
driver = passwd
}
passdb {
args = %s
driver = pam
}
protocols = imap

namespace inbox {
inbox = yes

mailbox Trash {
auto = subscribe # autocreate and autosubscribe the Trash mailbox
special_use = \Trash
}
mailbox Sent {
auto = subscribe # autocreate and autosubscribe the Sent mailbox
special_use = \Sent
}
}

service auth {
unix_listener /var/spool/postfix/private/auth {
group = postfix
mode = 0660
user = postfix
}
}

auth_mechanisms = plain login
disable_plaintext_auth = no
auth_username_format = %n
ssl=required
ssl_cert = </etc/letsencrypt/live/mail.[root domain]/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.[root domain]/privkey.pem
ssl_ca = </etc/ssl/ca.pem

This basically specifies what inbox you’re gonna use, the password database, the inbox namespace (Including Trash and Sent), authentication for the server, and the SSL certificates as well, which should look similar to the postfix config we had earlier. Keep in mind that your IMAP and SMTP server will both have the exact same username and password.

Now, you want to edit your other postfix config file (being /etc/postfix/master.cf) and add a “submission” & a “smtps” section below the existing smtpd section, like so:

submission      inet  n       -       y       -       -       smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_wrappermode=no
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o milter_macro_daemon_name=ORIGINATING
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_relay_restrictions=permit_sasl_authenticated,permit_mynetworks,reject
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth

These settings will enable secure authentication on your mail server, and also take mail from clients, and allow them to be sent.

Now you can restart your dovecot server & your postfix server (again):

systemctl restart dovecot
postfix stop && postfix start

Now that your servers are setup, let’s move on to actually connecting!

How to connect to your IMAPS server

Your server should be up and running by now, so we can start connecting to the actual server. I’ll be using outlook for this part of the tutorial. Firstly, you want to create a new user, which can easily be done with the adduser command, like so:

adduser [username]

Then, in the login_maps file you created earlier (/etc/postfix/login_maps), you want to add in the user to the file just like the following:

[username]@[root domain] [username]

After you save and exit, you want to map it to a database file using the postmap command:

postmap /etc/postfix/login_maps

Once that’s done, open up your mail client, and go to advanced options. When asked how you want to connect, select IMAP.

From there, you want both the SMTP server and the IMAP server to be mail.[root domain]. Your IMAP server port should be 993 (SSL connection) and your SMTP port should be either 465 or 587 (SSL connection).

Your IMAP password should just be the exact same one as the user password that you set earlier when using the adduser command. You do not have to specify an SMTP password, since both passwords are the same. From there, you can now click continue, and you should officially be logged in!

You can send an email to yourself, and it should popup in your inbox, like so:

If you have tried to send an email however, there’s a big chance it won’t work. That’s because email services nowadays have a whole bunch of checks to make sure that your email is not spam or whatever. Although this is not completely avoidable, I’ll show you 4 things you can add to make your email more secure, and some extra things at the end, like blocklists.

How to get removed off of blocklists

Nowadays, you will need to do a lot of things so that you can avoid being on multiple blocklists as much as possible. I’ve split this part of the blog up into 5 parts, those being:

  1. SPF
  2. DKIM
  3. DMARC
  4. PTR
  5. SpamHaus, UCEPROTECTL2, & UCEPROTECTL3

I’ll try my best to explain everything to you guys in each section so that your email can be very secure. So without further adieu, let’s get started with SPF!

SPF

SPF (or Sender Policy Framework) is basically an email auth standard that specifies who can send emails from your domain. This is usually specified using a DNS record, however I’ll also show you how you can make sure emails that are sent to you have this property as well.

To add SPF to your domain, all you need to do is go into your DNS settings, and at the root of your domain, add a TXT record with your SPF specifications:

For my case, I just added the default, that being “v=spf1 mx ~all”, however there are loads of other options you can specify, which you can see here.

To make sure receiving emails have this property, you want to first install this python policy checker:

sudo apt install postfix-policyd-spf-python

Then, go into your master.cf config file (/etc/postfix/master.cf), and at the very bottom add these lines:

policyd-spf  unix  -       n       n       -       0       spawn
user=policyd-spf argv=/usr/bin/policyd-spf

This will tell postfix to startup the spf policy when postfix gets started. Now once you save and exit, in your main.cf file (/etc/postfix/main.cf), you want to put these lines at the very bottom:

policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
permit_sasl_authenticated,
check_policy_service unix:private/policyd-spf,
reject_unauth_destination

This will check if the SPF record exists, and if it doesn’t, it’ll get rejected. Now you can save, exit, and restart your postfix server:

postfix stop && postfix start

You can use a tool like mxtoolbox.com to check if the SPF record is added to your domain correctly.

DKIM

DKIM (or DomainKeys Identified Mail) is a sort of email auth method that adds a digital signature to every message you sent. The client can use this information to verify if the email came from the sender, or someone impersonating them.

To start off, you’re going to want to install the linux DKIM tools, like so:

sudo apt install opendkim opendkim-tools

You want to then add the postfix user to the opendkim group, like so:

sudo gpasswd -a postfix opendkim

You want to then open up the DKIM config file (/etc/opendkim.conf) and go to the commented line that says LogWhy. You want to uncomment it, and change it to yes:

This will basically provide you extra debugging tools & more detailed logging, which could be useful if you find something went wrong.

At the very bottom of the file, you want to add in these lines:

Domain                  [root domain]
KeyFile /etc/postfix/mail.private
Selector mail
SOCKET inet:8891@localhost

We haven’t created the KeyFile yet, however we will set that up now. After you save & exit, you want to type the following command in the /etc/postfix dir:

sudo opendkim-genkey -s mail -d [root domain]

This will generate both a public and a private key for us to use. Once you do that, you want to print out the contents of the public key like so:

cat /etc/postfix/mail.txt

And you want to copy this portion of the file:

Once done, go into your DNS, and make a new DNS record at mail._domainkey. From there, add in the part that you just copied. Make sure that you remove all quotation marks before saving the record!

v=DKIM1; h=sha256; k=rsa; 
p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAptfDtanwtOQsK5UjxzrvgU9rZH1HdFhZL2R2i9Pk/V29YOnex/XmLaax2LJ1Wqs3f4KgQcnRONqr1eO8mh13EK0A1nOpdLtS6jbsVu1pleze9vvrp8QG9MIrMM6NfUU4mMiUM4NQSQWOiFOh49o52WDG/P5WTIQ2ByLBjA30eB5/eRE5h9uSa0mEDD2Ynkj8vJ2QaNwVlcm5Yy4/EWUayzXl0SuKs7bk0bt7mGLWPD3IepCvs7lcwAgTjCPEyuzWpSjU2SgK9jFB1Nt1sV4Jl9sO4ymKrRmadfDcoJP8Nl9DvlZFS0+e1Yg9Olg5F5bmure2QQvOIl3hsUOoFufbnwIDAQAB

It should look something like this. The public key should be in one whole piece, while the rest of the params are separated from it. Once done, you want to go back into your postfix main.cf file (/etc/postfix/main.cf), and add these lines at the very bottom in order to use DKIM on your server:

milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

Now, you can save & exit, and restart both services to activate DKIM. Again, you can use something like mxtoolbox.com to verify your DKIM record was inputted correctly.

DMARC

DMARC (or Domain-based Message Authentication, Reporting and Conformance) is another type of email auth that is designed to prevent email spoofing & unauthorized use of your domain.

To add DMARC to your email, all you have to do is in your DNS records, add a txt record pointing to _dmarc with the settings you wish:

I personally just added some of the more regular settings, being “v=DMARC1; p=reject; sp=reject; pct=100;”, though you can look through some more options here. You can use a tool like mxtoolbox.com to verify your DMARC record was setup correctly.

PTR

PTR (or DNS Pointer Record) provides a domain name that is associated with an IP address. This can be used to verify if the domain name & IP address are linked together, and verifying the identity of the domain.

In order to add this record, all you have to do is edit your virtual machine’s name to mail.[root domain] like so, and digitalocean will automatically add a PTR record on its own:

To verify your PTR record was added successfully, you can use mxtoolbox.com.

SpamHaus, UCEPROTECTL2, & UCEPROTECTL3

Now that you have all of the records setup, we should go over the 3 main blocklists, that being spamhaus, UCEPROTECTL2, and UCEPROTECTL3. All 3 of these are massive blocklist databases designed to prevent spam and whatnot.

To check if your server is on the SpamHaus database, you can go here to check if your domain is here. If it is, they also provide an easy way to delist it from the database, which can’t be said about the other 2.

UCEPROTECTL2 blocks multiple IPs that may be used for spam, while UCEPROTECTL3 blocks a whole range of IPs. To check if your domain is listed here, you can use something like mxtoolbox. To get removed from these, your best bet is using a watchlist. If you use the mxtoolbox link, they do provide a way to monitor your domain, so that is very easy to accomplish.

Sometimes getting removed off blocklists can take months, and clients can take a while to accept your email address as not spam. For instance, my own hpsk.me email domain took nearly 2 months just to get unblocked! So good luck figuring that out.

Conclusion

Although the process of actually creating your own mail server can be quite tedious and can certainly use up resources, there are still a couple of advantages such as:

  1. No mail quota
  2. Being able to customize your IMAP settings to add different inboxes
  3. Having any username you want

Overall, this project was very fun I’d say, and I learned a lot of things about how emailing works and the security involved in it. I hope you enjoyed my tutorial, and good luck with whatever you plan on doing with this!

--

--