How to set up self-hosted email

Hello, World,

Apologies for such a long break from posting. I am currently dealing with burnout and therefore don't really have the motivation or energy to do anything I would consider formidable, which includes writing quality long-form blog posts :(

In the past few days I received a few inquiries about self-hosted email (ironically, through email). Given that I often provide gratis one-on-one support in regards to self-hosted email, I decided to write a blog post giving general tips on how to set up self-hosted email well :)

(important!) Before we start, TAKE EVERYTHING I SAY WITH A GRAIN OF SALT. This post is, at its core, a TL;DR of various email knowledge and experience I've picked up over my time hosting an email server. Do not blindly make technical choices, do not blindly paste in DNS records, do not blindly run commands, etc. without doing any further research or trying to understand what it implies. This is not a 1:1 guide that will get you from 0 to 100 in half an hour; just like my recipes, this guide is meant to be adapted on rather than followed like a gospel.

Without further ado, let's dive in :D

# Choosing a hosting provider

For the love of Flying Spaghetti Monster, if you want your email to be actually delivered and not immediately rejected or placed in recipient's spam folder, do not use dynamic DNS (dDNS) or host your email on a residential IP address. It ought to be a disaster for you if you do not follow these directions as most block lists take dDNS and residential IPs into account by instantly blocking them.

Furthermore, avoid any providers with generally low reputation in their IP ranges. One such example is Contabo - I would recommend avoiding Contabo for self-hosting email (trust me, I tried - I mean, I did pretty good, but not without a plethora of issues that took months to only half-mitigate).

This leaves us with mid-to-high-end hosting providers with acceptable IP reputation. High-end hosting providers are often more reliable, but can result in higher costs. I would recommend sticking to mid-range providers to ensure a balance between economic burden and quality.

# Hosting provider recommendations

Two hosting providers I can recommend first-hand would be HostHatch and ETH-Services. Both of them are affordable, have mid-range plans, give out IPs in IP ranges with acceptable reputation, and provide (in my experience) helpful support :) Please note that HostHatch does not provide DDoS protection, therefore it may not be a viable option for some individuals that value maximum stability.

Another hosting provider popular in indietech spaces is Hetzner - one of my friends uses it to self-host email and their experience (from my understanding) has been adequate thus far, although I cannot recommend Hetzner first-hand as I have not used it.

Honestly, just scroll through LowEndTalk, and I'm sure you'll find something! However, note that most providers block port 25 (SMTP) by default, which is required for email. You MUST request the port to be unblocked in most cases.

# Choosing a software

The software you shall choose depends on your hardware, requirements, technical ability, and desire to maintain your system. A couple popular choices include Mailcow and Stalwart.

Mailcow is a docker-based email stack combining various popular email software components (such as Postfix, rSpamD, Dovecot, ...) in a centralised Docker image. It allows one to easily set email up, manage data using a "standard" software stack (allowing easy future migration), provides a powerful API, all while staying up-to-date, not having to deal with the annoyance of setting up tens of components and making them work coherently with one another. The main downside of Mailcow is that it tends to be pretty heavy (the minimum requirements alone are 6GB of RAM + 1GB swap and 20 GiB of storage (not including email storage)) and that it mainly natively supports a limited set of Linux distributions (server-side, of course) without needing to install any compatibility layers or patching in major modifications.

Stalwart is an integrated from-scratch open-source all-in-one lightweight email server software focused on flexibility and scalability. It is a great choice for lower-end systems. The main downside of Stalwart is that it lacks maturity (Mailcow combines standard time-tested components whereas Stalwart is written by the Stalwart team and the open source community from scratch in Rust), provides weaker spam protection, and lacks complete protocol standard compliance due to the lack of maturity.

There is always the option of rolling out your own stack (combining your own components together), but this will require a lot of maintenance - something similar to Emailwiz maybe?; a few years ago I heard of Luke Smith's emailwiz script, which natively installs and configures Postfix, Dovecot, SpamAssasin, OpenDKIM, Certbot, and fail2ban by means of a centralised shell script. I personally prefer the two aforementioned options, but if you're simply looking for a lightweight "just works" option, Emailwiz or a custom stack may be your best bet.

# Hosting vs. Virtual Hosting

Email has two types of "servers" - well, not directly servers, but let's call them "servers" for the sake of brevity.

  1. The first type is the authoritative email (hosted) server (what we will call mail.example.com all throughout this post) - this is the server that process all mail and "delivers" it to the users. This is the server that, for example, goes into the MX record of domains.
  2. The second type is a virtually hosted (vHosted) domain - it is a domain that has an MX record pointing to an email server (mail.example.com), which accepts emails to and from that domain. All throughout the post we will refer this concept as either example.com or your.domain - the latter will be used where the distinction matters more for technical rigour.

# Setting up your software

Firstly, ensure port 25 is unblocked on your hosting provider (most hosting providers block port 25 by default), then simply follow the documentation:

Regarding DNS (email has A LOT of DNS records if you want a bullet-proof configuration), Mailcow has beautiful and robust documentation for it (Mailcow documentation: prerequisite DNS). I would recommend the following configuration for DNS (consider mail.example.com to be your mail server) based on the Mailcow suggestions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
(in namespace example.com)

mail                  IN A       ... (your server's public IPv4 address, most definitely required)
mail                  IN AAAA    ... (your server's public IPv6 address, optional but useful!)
mail                  IN CAA     0 issue "letsencrypt.org" (see note 7 about CAA records)
autodiscover          IN CNAME   mail.example.com. (see note 1 about record values)
autoconfig            IN CNAME   mail.example.com.
_autodiscover._tcp    IN SRV     0 1 443 mail.example.com. (see note 5 about SRV records)
_caldavs._tcp         IN SRV     0 1 443 mail.example.com.
_caldavs._tcp         IN TXT     "path=/SOGo/dav/" (see note 6 about SOGo)
_carddavs._tcp        IN SRV     0 1 443 mail.example.com.
_carddavs._tcp        IN TXT     "path=/SOGo/dav/"
_imap._tcp            IN SRV     0 1 143  mail.example.com.
_imaps._tcp           IN SRV     0 1 993  mail.example.com.
_pop3._tcp            IN SRV     0 1 110  mail.example.com.
_pop3s._tcp           IN SRV     0 1 995  mail.example.com.
_sieve._tcp           IN SRV     0 1 4190 mail.example.com.
_smtps._tcp           IN SRV     0 1 465  mail.example.com.
_submission._tcp      IN SRV     0 1 587  mail.example.com.
_submissions._tcp     IN SRV     0 1 465  mail.example.com.

After creating all DNS records, add the following aliases/mailboxes:

P.S. If possible also enable DNSSEC and the TLSA DNS record (also known as DANE) - this will improve security, reduce the risk of spoofing, and likely improve deliverability.

CLOUDFLARE USERS (!!!): For all hostname/IP values, you MUST turn off the DNS Cloudflare proxy, else it won't work. The orange cloud must be grey (simply click on it).

# DKIM, DMARC, and SPF

For virtually hosted domains, additional records for DKIM, DMARC, and SPF get added (+ an MX for linking to mail server):

1
2
3
4
5
6
(in namespace your.domain)

@                     IN MX      0 mail.example.com.
dkim._domainkey       IN TXT     "v=DKIM1; k=rsa; t=s; s=email; p=..." (see note 3 regarding DKIM)
_dmarc                IN TXT     "v=DMARC1;p=reject;rua=mailto:dmarc@example.com;adkim=s;aspf=s;sp=reject;pct=100" (see note 4 regarding DMARC)
@                     IN TXT     "v=spf1 mx a -all" (see note 2 below regarding SPF)

Of course add the basic boilerplate as well:

1
2
3
4
5
(in namespace your.domain)

@                     IN A       ...
@                     IN AAAA    ...
@                     IN CAA     0 issue "letsencrypt.org"

# DNS syntax

In some DNS panels . gets automatically appended to hostname values and also the TXT records can get automatically quoted. Try everything until it works.

# Reverse DNS

Your mail server's IP addresses (v4 and v6) should have a reverse DNS resolving to mail.example.com (of course, your domain, not example.com). If you don't do this step, you will likely face considerable deliverability issues, thereby making your email server less reliable.

# DNS notes

  1. Wherever you see a . at the end of records, it is required - not a typo.
  2. This is your Sender Policy Framework (SPF). It ensures the sending mail server is authorised to originate mail from the email sender's domain. The "v=spf1 mx a -all" SPF means "only your domain's own mail servers (MX records) and main server IPs (A and AAAA records) are allowed to send emails".
  3. DKIM is handled more or less the same, but generally it is <selector>._domainkey.example.com in TXT. In Mailcow it is only RSA, but in Stalwart there are multiple keys you will have to add, simply follow the documentation.
  4. DMARC is hardly optional, but DMARC reports are - they are simply useful for server administrators. I recommend you create a separate dmarc@example.com (where example.com is your own domain, of course - replace the example.com in the record as well) mailbox or alias and keep an eye on it as you will likely receive a lot of DMARC security reports. DMARC also prevents domain spoofing.
  5. SRV records are optional and allow to explicitly delegate email components if it is not hosted on the same server - it is recommended to do this. Before adding SRV records verify that the port you are adding is open and being listened to (on Mailcow all of the listed ones are).
  6. If you don't have the /SOGo/dav/ path on HTTPS, don't add the SOGo DAV record. This is just a Mailcow thing which comes with SOGo preshipped.
  7. CAA records are technically optional, but they improve security. The issuer has to be, well, your certificate issuer - in many self-hosted cases, it is Let's Encrypt. For further HTTPS security insurance, you can submit your domain to the HSTS preload list, but I don't think this affects email too much, just improves security.

# MTA-STS

MTA-STS (Mail Transfer Agent Strict Transport Security) allows to ensure the security of email transmission of over an encrypted SMTP connection. It is considered less secure than DANE+DNSSEC, but setting up MTA-STS as a fallback is a good practice to not only ensure all email is delivered to you and it is done so securely, but also gives you a better chance at being not allowed through spam filters.

To set up MTA-STS, you can either use your mail stack's built-in tooling (say, Mailcow supports MTA-STS since 2025-09) or do it manually:

  1. Create a text file:

    1
    2
    3
    4
    version: STSv1
    mode: enforce
    max_age: 86400
    mx: mail.example.com
    

    For testing purposes, you can also try out mode: testing, but for production uses enforce is preferred. You can read more about MTA-STS online if you want to tailor your configuration further.

  2. Place this file at https://mta-sts.your.domain/.well-known/mta-sts.txt (where your.domain is your main email vHosted domain (e.g., ari.lt (your.domain) vs. mail.ari.lt (mail.example.com)), not mail server)

    • This path must enforce HTTPS, not redirect, and have a valid TLS certificate
  3. Add a TXT record: _mta-sts.your.domain with the value "v=STSv1; id=YYYYMMDDHHMMSS;". In reality, YYYYMMDDHHMMSS can be any identifier, but the most common versioning schema for MTA-STS policies is dates. You can generate it using this command:

    1
    date '+%Y%m%d%H%M%S'
    
  4. Set up TLS reporting by adding a TXT record _smtp._tls.your.domain with value "v=TLSRPTv1;rua=mailto:tlsrpt@..." (see # External domain authorisation)

  5. Set up a tlsrpt@... mailbox/alias on your email server.

If you're using MTA-STS, it is highly recommended that you set up DNSSEC+DANE (so DANE is prioritised over the less secure MTA-STS), have CAA records, and have HSTS (and maybe even a part of the HSTS preload list), considering MTA-STS works on the basis of HTTPS requests.

Harden your reverse proxy to ensure best security. Refer to https://git.ari.lt/ari.lt/nginx.conf for production deploys.

# Informational: what are DMARC and TLS reports?

# DMARC reports

DMARC (Domain-based Message Authentication, Reporting, and Conformance) reports tell you who is sending email on behalf of your domain and whether those emails are "authentic."

When you send an email, the receiving server checks your SPF and DKIM records to verify you are who you say you are. The DMARC report is the feedback loop the receiver sends back to you to show how those checks went.

There are two types of DMARC reports:

RUA reports are generally preferred for privacy assurance. Unless you completely control the domain, I would suggest against collecting RUF reports. It is important to note that most providers nowadays don't even send RUF reports anymore.

Read more about DMARC: https://dmarc.org/.

# TLS reports

TLS-RPT (SMTP TLS Reporting) is a newer standard that focuses on the "tunnel" your email travels through. While DMARC checks the sender's identity, TLS reports check if the connection between servers is encrypted and secure. TLS reports notify domain owners when an email fails to deliver because of a problem with encryption. This usually happens if:

Without these reports, you might never know why your emails are suddenly bouncing or "disappearing" if the issue is strictly related to the encrypted handshake.

Read the TLS-RPT RFC here: https://datatracker.ietf.org/doc/html/rfc8460

# External domain authorisation

External domain authorisation allows email reporting mechanisms to report to external domains via rua.

Consider that mail.ari.lt (which is also vHosting ari.lt) wants to receive DMARC and TLS reports to an @ari.lt email from example.com. So:

# Testing

Okay, so you set up your email server - how to test it?

First and foremost, use static tools that don't require much setup and fix issues by means of dynamic analysis:

After you ensure all or most things are well, test basic features of your email server: ask someone to converse with you via email for a couple of messages, and, if all is well, proceed further.

# Microsoft Outlook

Microsoft Outlook is awfully strict with independent email servers, and it is somewhat of a pain to get yourself unblocked on their network.

Before sending email to any Outlook addresses, let your email server age (give it a few months), then try to send an email to an Outlook address. You will likely be met with the following error:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Final-Recipient: rfc822; ...@outlook.com
Original-Recipient: rfc822;...@outlook.com
Action: failed
Status: 5.7.1
Remote-MTA: dns; outlook-com.olc.protection.outlook.com
Diagnostic-Code: smtp; 550 5.7.1 Unfortunately, messages from [...IP address..]
    weren't sent. Please contact your Internet service provider since part of
    their network is on our block list (...). You can also refer your
    provider to http://mail.live.com/mail/troubleshooting.aspx#errors.
    [<...>.namprd03.prod.outlook.com ...date...
    ...]

This error essentially means: "Sorry, you're blocked." and this has been a reoccurring issue to many independent individuals trying to host their own email servers on VPSes.

To resolve this issue you will need to sign up for Outlook SNDS, request access to your IP address on the Live network, and then ask for IP delegation. The UI is insanely convoluted and confusing, but the general process is described at https://sendersupport.olc.protection.outlook.com/snds/index and my memory:

  1. Log into SNDS: https://sendersupport.olc.protection.outlook.com/snds/addnetwork
  2. Request access to your IP address(es): https://sendersupport.olc.protection.outlook.com/snds/addnetwork
  3. Verify by email.
  4. Request a delegation (I don't quite remember how, but the UI was awful last time I used it, so good luck...)
  5. Wait a few hours to a couple of days.
  6. You will receive a response whether your IP has been delegated (unblocked) on their network from the Outlook Deliverability Support Team.
  7. If they refuse (which is likely from what I've seen), keep pushing if you think the block is most definitely unreasonable.

# Deliverability

Deliverability comes with time and organic outbound and inbound traffic. You can test your deliverability using various online tools, sending email one-on-one, etc. For a couple of months you will end up in spam relatively frequently, but do not fret, this tends to get better with time.

There are services called "mailbox warmup tools" but honestly, unless you're a business, not worth it.

Lastly, you should also be aware of Google Postmaster Tools which can help to diagnose issues on Google :)

To check where you stand immediately you can try one of those deliverability tester tools, but they often tend to be skewed. Still can give some pseudouseful insight.

# End-to-End Encryption (E2EE)

End-to-End Encryption (E2EE) is an integral part of private email communication. To achieve this, I recommend using OpenPGP or S/MIME certificates. I personally prefer OpenPGP due to its decentralised nature without a need for some arbitrary authority locked behind 10 paywalls.

To achieve best E2EE availability using OpenPGP, I recommend:

  1. Publishing your OpenPGP key on various HKPS', such as:
  2. Setting up OPENPGPKEY DNS records: https://blog.ari.lt/b/openpgpkey-records-are-cool/
  3. Setting up a Web-Key-Directory: https://docs.keyoxide.org/wiki/web-key-directory/
  4. Adding an Autocrypt header to all your emails: https://docs.autocrypt.org/level1.html#the-autocrypt-header
  5. Signing all your messages and/or attaching your public OpenPGP key.

This will ensure that your key is never missed by the ones that have the ability to encrypt communications.

# Maintenance

# Eventual migration and next steps

By self-hosting you are taking first baby steps towards fully migrating to private, ethical, and autonomous infrastructure. Don't let big tech crush you and use you as a lab rat for their sick corporate games.

You can take further steps by updating your email everywhere and setting up email forwarding from your old mailbox to your new, self-hosted one. For example, Google makes this very easy: https://support.google.com/mail/answer/10957. If your provider does not support forwarding, your only option left is to keep the old mailbox until it eventually dies out, and, if you care about your old emails, use imapsync to sync your mailboxes - you can even make it a daemon.

To improve your experience you can also install an email web client, such as Roundcube.

# What if I fail after a while?

Happens. You forget to pay your bills and... It's gone. I understand this, but this is where responsible backing up and a fallback solution comes in.

Cloudflare provides free email routing: https://www.cloudflare.com/en-gb/developer-platform/products/email-routing/. If you cannot lose access to your self-hosted mailbox, you can at least route your domain using Cloudflare to a hosted solution to migrate data and accounts over to a mailbox you can access.

This is a risk you take by liberating.

# Further exploring

Might be worth exploring/referencing:

# Closing

That's about it. It's mainly nerve-wracking to set up, but once you get it, it's generally pretty smooth-sailing.

And... If you're facing issues, you can always contact me at https://ari.lt/contact - I provide free support for most (well, I try to), but do consider donating at https://ari.lt/donate <3 I hope I was helpful.

'til next time!! :D