// Own your inbox. Escape the surveillance economy.
// WHAT WE'RE BUILDING
In this project, you'll build a complete mail server from scratch using Postfix (SMTP), Dovecot (IMAP/POP3), and Roundcube (webmail). You'll have full control over your email - no Gmail, no Outlook, no tracking.
// WHY THIS MATTERS
Email is the backbone of digital communication, yet most people trust tech giants with their inbox. Self-hosted email means: no scanning of your emails for ads, no "sorry, you can't send that" restrictions, complete control over your data, and true privacy.
This project combines multiple skills into a production-ready mail system:
Understanding the email architecture:
Prerequisites
Before starting, make sure you've completed:
Your mail system will use these components:
Before installing mail software, we need to set up our domain and server.
You'll need a domain for email. Let's use example.com as our example. You'll need:
$ sudo hostnamectl set-hostname mail.example.com # Set the hostname $ echo "127.0.1.1 mail.example.com mail" | sudo tee -a /etc/hosts # Add to hosts file
$ sudo apt update $ sudo apt install -y postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql mariadb-server nginx certbot python3-certbot-nginx # Install mail stack
$ sudo certbot certonly --standalone -d mail.example.com # Get SSL certificate
$ sudo mysql -u root -p # Connect to MariaDB
mysql> CREATE DATABASE mailserver; mysql> CREATE USER 'mailuser'@'localhost' IDENTIFIED BY 'strong_password_here'; mysql> GRANT ALL PRIVILEGES ON mailserver.* TO 'mailuser'@'localhost'; mysql> FLUSH PRIVILEGES; mysql> USE mailserver;
mysql> CREATE TABLE virtual_domains ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; mysql> CREATE TABLE virtual_users ( id INT NOT NULL AUTO_INCREMENT, domain_id INT NOT NULL, email VARCHAR(100) NOT NULL, password VARCHAR(150) NOT NULL, PRIMARY KEY (id), UNIQUE KEY email (email), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; mysql> CREATE TABLE virtual_aliases ( id INT NOT NULL AUTO_INCREMENT, domain_id INT NOT NULL, source VARCHAR(100) NOT NULL, destination VARCHAR(100) NOT NULL, PRIMARY KEY (id), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
mysql> INSERT INTO virtual_domains (name) VALUES ('example.com'); mysql> INSERT INTO virtual_users (domain_id, email, password) VALUES (1, 'admin@example.com', ENCRYPT('your_secure_password')); mysql> EXIT;
Postfix is the MTA (Mail Transfer Agent) that handles sending and receiving emails.
$ sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup $ sudo cp /etc/postfix/master.cf /etc/postfix/master.cf.backup
$ sudo nano /etc/postfix/main.cf
Replace the file with this configuration:
# Host and domain settings myhostname = mail.example.com mydomain = example.com myorigin = $mydomain mydestination = $myhostname, localhost, localhost.localdomain mynetworks = 127.0.0.0/8 inet_interfaces = all inet_protocols = all # Mailbox settings home_mailbox = Maildir/ mailbox_command = # Virtual mail settings virtual_alias_domains = virtual_alias_maps = proxy:mysql:/etc/postfix/mysql/virtual_alias_maps.cf virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql/virtual_mailbox_domains.cf virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql/virtual_mailbox_maps.cf virtual_mailbox_base = /var/vmail virtual_uid_maps = static:5000 virtual_gid_maps = static:5000 # SASL authentication smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes smtpd_sasl_security_options = noanonymous smtpd_sasl_tls_security_options = $smtpd_sasl_security_options smtpd_tls_auth_only = yes # TLS/SSL settings smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem smtpd_use_tls = yes # Restrictions smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_rbl_client zen.spamhaus.org smtpd_relay_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
$ sudo mkdir -p /etc/postfix/mysql
$ sudo nano /etc/postfix/mysql/virtual_mailbox_domains.cf
$ sudo nano /etc/postfix/mysql/virtual_mailbox_maps.cf
$ sudo nano /etc/postfix/mysql/virtual_alias_maps.cf
$ sudo useradd -r -u 5000 -g mail -s /sbin/nologin -d /var/vmail vmail $ sudo mkdir -p /var/vmail $ sudo chown vmail:mail /var/vmail
$ sudo nano /etc/postfix/master.cf
Make sure these lines exist (uncomment if needed):
$ sudo postfix check # Check for errors $ sudo systemctl restart postfix
Dovecot handles IMAP and POP3 - how you retrieve your emails.
$ sudo nano /etc/dovecot/dovecot.conf
$ sudo nano /etc/dovecot/conf.d/10-auth.conf
$ sudo nano /etc/dovecot/conf.d/10-mail.conf
$ sudo nano /etc/dovecot/dovecot-sql.conf.ext
$ sudo nano /etc/dovecot/conf.d/10-ssl.conf
$ sudo nano /etc/dovecot/conf.d/10-master.conf
$ sudo systemctl restart dovecot
$ openssl s_client -connect mail.example.com:993 # Test SSL connection
Roundcube gives you a beautiful web interface to check your email.
$ sudo apt install roundcube roundcube-mysql roundcube-php
$ sudo nano /etc/nginx/sites-available/mail.example.com
$ sudo ln -s /etc/nginx/sites-available/mail.example.com /etc/nginx/sites-enabled/ $ sudo nginx -t $ sudo systemctl reload nginx
$ sudo mysql -u root -p < /usr/share/roundcube/SQL/mysql.initial.sql
$ sudo nano /var/lib/roundcube/config/config.inc.php
Important: Generate a random des_key using: openssl rand -base64 24
These DNS records prove your server is authorized to send email for your domain.
Add this TXT record to your domain's DNS:
$ sudo apt install opendkim opendkim-tools
$ sudo nano /etc/opendkim.conf
$ sudo mkdir -p /etc/opendkim/keys $ sudo opendkim-genkey -s default -d example.com -D /etc/opendkim/keys $ sudo chown -R opendkim:opendkim /etc/opendkim/keys
$ sudo nano /etc/opendkim/signing.table
$ sudo nano /etc/opendkim/key.table
$ sudo nano /etc/opendkim/trusted.hosts
$ sudo nano /etc/postfix/main.cf
$ sudo systemctl restart opendkim postfix
Get your public key:
$ sudo cat /etc/opendkim/keys/default.txt
Add this TXT record to your DNS:
Add this TXT record to your DNS:
Your domain's DNS tells the world how to deliver email to your server.
Add this record to point mail to your server:
Set your server's reverse DNS to mail.example.com. This must be done through your hosting provider.
$ dig MX example.com # Check MX record $ dig TXT example.com # Check SPF record $ dig TXT default._domainkey.example.com # Check DKIM record $ dig TXT _dmarc.example.com # Check DMARC record
$ mail-tester.com # Test your email deliverability
$ openssl s_client -connect mail.example.com:465 -starttls smtp
$ swaks --to test@example.com --from admin@example.com --server mail.example.com --port 587 --tls --auth-user admin@example.com --auth-password your_password
Open in your browser:
Login with:
Connect your desktop or mobile email client:
Congratulations! You now have a fully functional mail server. Here's what you can add:
Remember: Running a mail server requires ongoing maintenance. Monitor your logs, keep your system updated, and watch your sender reputation.