Have you ever thought about owning a dedicated email system for your business or personal project? No more relying on Gmail, Outlook, or other third-party services—instead, you’ll have a professional mail server that carries your very own brand.
In this guide, I’ll walk you through setting up and configuring a fully functional Mail Server with Postfix Dovecot on Ubuntu/Debian. We’ll use Postfix (SMTP) for sending emails and Dovecot (IMAP/POP3) for receiving them, with users logging in through their regular system accounts. On top of that, we’ll integrate SSL/TLS with Let’s Encrypt to ensure every outgoing email is encrypted, preventing those annoying “not secure” warnings from browsers or mail clients.
The end result? A secure, professional, and flexible email system that puts you in full control of your communications.
Requirements Before You Begin
Before proceeding with the installation, make sure you have:
- A VPS running Ubuntu/Debian (it is recommended to use the latest version to ensure both security and compatibility).
- A properly configured Hostname (FQDN).
How to Change Hostname and FQDN/Fullname on Linux - Required DNS records: A, MX, PTR, SPF, DMARC.
Essential DNS Records for a Mail Server - Port 25 (SMTP) is open.
Note: Many VPS providers block port 25 by default. You will need to request it to be opened in order to send emails. Vultr offers good support for this – you can check them out and register via the banner on the right. - Root account or sudo privileges to carry out the installation process.
- In this article, I will use the following assumptions:
- Domain:
totatcaz.xyz
- Hostname:
mail
- Fullname (FQDN):
mail.totatcaz.xyz
- Domain:
Read more
- Mail Server Ports Explained – SMTP, POP3, IMAP, and Security
- How to Install NextCloud Server on Ubuntu/Debian
- Top Essential Linux Commands List with Examples
Update the System
Before installing, update your system to ensure the latest security patches and software versions. We’ll also install some basic admin tools.
sudo apt update && sudo apt upgrade -y
- curl: transfer data over HTTP/HTTPS.
- vim: text editor for configuration files.
- telnet: check service connectivity (SMTP/IMAP/POP3).
- ufw: simple firewall management.
Install Postfix, Dovecot, Certbot, and Required Tools
Next, install the core packages for the Mail Server:
sudo apt install -y postfix dovecot-core dovecot-imapd dovecot-pop3d certbot python3-certbot-nginx curl vim telnet ufw
- Postfix: Mail Transfer Agent (MTA) for sending/receiving mail via SMTP.
- Dovecot: IMAP/POP3 service so users can read emails with clients like Outlook or Thunderbird.
- Certbot: obtain free SSL certificates from Let’s Encrypt.
- Supporting tools: curl, vim, telnet, ufw.
During the Postfix installation, you will be prompted to choose a configuration type. Select Internet Site and enter your FQDN (e.g., mail.totatcaz.xyz).
Configure UFW Firewall
After installing the necessary services, configure your firewall (UFW) to make sure the required ports are allowed. You should open the following ports:
- 443 (HTTPS) and 80 (HTTP) – if you use webmail or need SSL/TLS certificate issuance
- 25 (SMTP) – for sending emails between mail servers
- 587 (Submission) – for sending emails from mail clients (Outlook, Thunderbird, etc.) over TLS
- 143 (IMAP) and 993 (IMAPS) – for receiving emails via IMAP (993 with SSL/TLS recommended)
- 110 (POP3) and 995 (POP3S) – for receiving emails via POP3 (995 with SSL/TLS recommended)
- Read more: Mail Server Ports Explained – SMTP, POP3, IMAP, and Security
UFW commands:
sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 25
sudo ufw allow 587
sudo ufw allow 465
sudo ufw allow 993
sudo ufw allow 995
sudo ufw enable
sudo ufw status

Obtain SSL Certificate with Let’s Encrypt
Securing your email server with SSL/TLS is mandatory. Without it, most clients will mark your emails as insecure. Use Certbot to generate certificates:
sudo certbot certonly --nginx -d mail.totatcaz.xyz
If successful, the certificates are stored in:
- /etc/letsencrypt/live/mail.totatcaz.xyz/fullchain.pem
- /etc/letsencrypt/live/mail.totatcaz.xyz/privkey.pem
These files will be used in Postfix and Dovecot configuration.

Configure Postfix
Backup Default Configuration
Before making any configuration changes, be sure to back up the original configuration file so that it can be restored in case of any issues.
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.bak sudo cp /etc/postfix/master.cf /etc/postfix/master.cf.bak
Edit main.cf
Next, open the Postfix configuration file (main.cf). This is the primary file that contains the essential settings required for the mail server to function properly
sudo vim /etc/postfix/main.cf
In Vim, press Esc
, then type the command :1,$d
and press Enter to delete the entire content of the file, and then enter the new content below
# Core
smtpd_banner = $myhostname ESMTP
biff = no
append_dot_mydomain = no
readme_directory = no
compatibility_level = 3.6
home_mailbox = Maildir/
# Access / relay
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = mail.totatcaz.xyz
mydomain = totatcaz.xyz
myorigin = $mydomain
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = ipv4
# TLS inbound (smtpd)
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.totatcaz.xyz/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.totatcaz.xyz/privkey.pem
smtpd_tls_auth_only = yes
smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
# TLS outbound (smtp client)
smtp_tls_security_level = may
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtp_tls_loglevel = 1
smtp_tls_note_starttls_offer = yes
smtp_tls_protocols = !SSLv2, !SSLv3
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
# SASL (submit qua Dovecot)
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname
Then, save and exit the file by pressing Esc, typing the command :x
, and pressing Enter.
Edit master.cf
Next, open the master.cf configuration file. This file defines how Postfix manages and runs its related services.
sudo vim /etc/postfix/master.cf
Delete the entire content of the file and enter the new content shown below:
#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line: http://www.postfix.org/master.5.html).
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - y - - smtpd
#smtp inet n - y - 1 postscreen
#smtpd pass - - y - - smtpd
#dnsblog unix - - y - 0 dnsblog
#tlsproxy unix - - y - 0 tlsproxy
# Choose one: enable submission for loopback clients only, or for any client.
#127.0.0.1:submission inet n - y - - smtpd
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
# -o smtpd_tls_auth_only=yes
# -o smtpd_reject_unlisted_recipient=no
# Instead of specifying complex smtpd_<xxx>_restrictions here,
# specify "smtpd_<xxx>_restrictions=$mua_<xxx>_restrictions"
# here, and specify mua_<xxx>_restrictions in main.cf (where
# "<xxx>" is "client", "helo", "sender", "relay", or "recipient").
# -o smtpd_client_restrictions=
# -o smtpd_helo_restrictions=
# -o smtpd_sender_restrictions=
# -o smtpd_relay_restrictions=
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
# Choose one: enable submissions for loopback clients only, or for any client.
#127.0.0.1:submissions inet n - y - - smtpd
#submissions inet n - y - - smtpd
# -o syslog_name=postfix/submissions
# -o smtpd_tls_wrappermode=yes
# -o smtpd_sasl_auth_enable=yes
# -o smtpd_reject_unlisted_recipient=no
# Instead of specifying complex smtpd_<xxx>_restrictions here,
# specify "smtpd_<xxx>_restrictions=$mua_<xxx>_restrictions"
# here, and specify mua_<xxx>_restrictions in main.cf (where
# "<xxx>" is "client", "helo", "sender", "relay", or "recipient").
# -o smtpd_client_restrictions=
# -o smtpd_helo_restrictions=
# -o smtpd_sender_restrictions=
# -o smtpd_relay_restrictions=
# -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
### 465
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
#628 inet n - y - - qmqpd
pickup unix n - y 60 1 pickup
cleanup unix n - y - 0 cleanup
qmgr unix n - n 300 1 qmgr
#qmgr unix n - n 300 1 oqmgr
tlsmgr unix - - y 1000? 1 tlsmgr
rewrite unix - - y - - trivial-rewrite
bounce unix - - y - 0 bounce
defer unix - - y - 0 bounce
trace unix - - y - 0 bounce
verify unix - - y - 1 verify
flush unix n - y 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - y - - smtp
relay unix - - y - - smtp
-o syslog_name=postfix/$service_name
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq unix n - y - - showq
error unix - - y - - error
retry unix - - y - - error
discard unix - - y - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - y - - lmtp
anvil unix - - y - 1 anvil
scache unix - - y - 1 scache
postlog unix-dgram n - n - 1 postlogd
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent. See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop unix - n n - - pipe
flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# ====================================================================
#
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
#
# Specify in cyrus.conf:
# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
#
# Specify in main.cf one or more of the following:
# mailbox_transport = lmtp:inet:localhost
# virtual_transport = lmtp:inet:localhost
#
# ====================================================================
#
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#
#cyrus unix - n n - - pipe
# flags=DRX user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
#
# ====================================================================
# Old example of delivery via Cyrus.
#
#old-cyrus unix - n n - - pipe
# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
#
# ====================================================================
#
# See the Postfix UUCP_README file for configuration details.
#
uucp unix - n n - - pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
ifmail unix - n n - - pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp unix - n n - - pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix - n n - 2 pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman unix - n n - - pipe
flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}
Then, save and exit the file
Restart Postfix
After completing the setup, start and enable Postfix so that the service runs automatically whenever the system boots.
sudo systemctl restart postfix
sudo systemctl enable postfix
Finally, check the status of the Postfix service to ensure that it is running smoothly and functioning as expected:
sudo systemctl status postfix

Test Postfix
At this point, Postfix is ready to send emails externally. First, create a test account by using the command below:
sudo adduser totatca

Now, use Telnet to connect to the server via port 25 and send a test email to verify that Postfix is working properly:
telnet mail.totatcaz.xyz 25
Then type:
ehlo mail.totatcaz.xyz
mail from: [email protected]
rcpt to: [email protected]
DATA
Subject: Mail Test
This is a test email.
.
quit

If everything works correctly, you can check your Gmail inbox. Note that the test email may appear in the Spam folder.
Configure Dovecot
Next, after completing the Postfix configuration, we will configure Dovecot to manage mailboxes and enable email access via protocols such as IMAP and POP3.
Backup Config
Similar to Postfix, back up the original Dovecot configuration file so that you can restore it if needed or in case any issues occur
sudo cp /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.bak
sudo cp -a /etc/dovecot/conf.d /etc/dovecot/conf.d.bak
Edit dovecot.conf
Next, open the dovecot.conf configuration file. This is the main file that contains the essential settings of Dovecot, and you can open it using the command below:
sudo vim /etc/dovecot/dovecot.conf
Locate, modify, or add the highlighted lines below to configure Dovecot properly according to the requirements
# A comma separated list of IPs or hosts where to listen in for connections.
# "*" listens in all IPv4 interfaces, "::" listens in all IPv6 interfaces.
# If you want to specify non-default ports or anything more complex,
# edit conf.d/master.conf.
listen = *
protocols = imap pop3
# Base directory where to store runtime data.
#base_dir = /var/run/dovecot/
Edit 10-mail.conf
Next, open the 10-mail.conf file. This file is used to define how mailboxes are stored and managed in Dovecot:
sudo vim /etc/dovecot/conf.d/10-mail.conf
Uncomment or comment the highlighted lines below to adjust the configuration accordingly
# See doc/wiki/Variables.txt for full list. Some examples:
#
mail_location = maildir:~/Maildir
# mail_location = mbox:~/mail:INBOX=/var/mail/%u
# mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n
#
# <doc/wiki/MailLocation.txt>
#
#mail_location = mbox:~/mail:INBOX=/var/mail/%u
# If you need to set multiple mailbox locations or want to change default
# namespace settings, you can do it by defining namespace sections.
Edit 10-ssl.conf
Next, open the 10-ssl.conf file. This file contains the configuration for setting up SSL/TLS to secure Dovecot connections:
sudo vim /etc/dovecot/conf.d/10-ssl.conf
Edit the file as shown below. Pay special attention to the declaration of the SSL key and certificate that you created in the previous step:
# SSL/TLS support: yes, no, required. <doc/wiki/SSL.txt>
ssl = required
# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
#ssl_cert = </etc/dovecot/private/dovecot.pem
#ssl_key = </etc/dovecot/private/dovecot.key
ssl_cert = </etc/letsencrypt/live/mail.totatcaz.xyz/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.totatcaz.xyz/privkey.pem
# If key file is password protected, give the password here. Alternatively
# give it when starting dovecot with -p parameter. Since this file is often
# world-readable, you may want to place this setting instead to a different
# root owned 0600 file by using ssl_key_password = <path.
Edit 10-auth.conf
Next, open the 10-auth.conf file. This is the configuration file used to manage authentication settings for the service, and you need to edit it as required
sudo vim /etc/dovecot/conf.d/10-auth.conf
Uncomment the line containing the parameter disable_plaintext_auth = yes to enable the feature that rejects plaintext authentication methods, thereby enhancing the system’s security.
disable_plaintext_auth = yes
6. Edit 10-master.conf
Next, open the 10-master.conf file. This is the configuration file used to manage the system’s services and processes, where you can modify the settings related to the authentication service and its associated components:
sudo vim /etc/dovecot/conf.d/10-master.conf
Edit the highlighted information as shown below to match your system configuration:
#default_internal_user = dovecot
service imap-login {
inet_listener imap {
#port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
# Number of connections to handle before starting a new process. Typically
# the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0
# is faster. <doc/wiki/LoginProcess.txt>
#service_count = 1
# Number of processes to always keep waiting for more connections.
#process_min_avail = 0
# If you set service_count=0, you probably need to grow this.
#vsz_limit = $default_vsz_limit
}
service pop3-login {
#inet_listener pop3 {
#port = 110
}
inet_listener pop3s {
port = 995
ssl = yes
}
}
service submission-login {
inet_listener submission {
#port = 587
}
}
service lmtp {
unix_listener lmtp {
#mode = 0666
}
# Create inet listener only if you can't use the above UNIX socket
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =
#}
}
service imap {
# Most of the memory goes to mmap()ing files. You may need to increase this
# limit if you have huge mailboxes.
#vsz_limit = $default_vsz_limit
# Max. number of IMAP processes (connections)
#process_limit = 1024
}
service pop3 {
# Max. number of POP3 processes (connections)
#process_limit = 1024
}
service submission {
# Max. number of SMTP Submission processes (connections)
#process_limit = 1024
}
service auth {
# auth_socket_path points to this userdb socket by default. It's typically
# used by dovecot-lda, doveadm, possibly imap process, etc. Users that have
# full permissions to this socket are able to get a list of all usernames and
# get the results of everyone's userdb lookups.
#
# The default 0666 mode allows anyone to connect to the socket, but the
# userdb lookups will succeed only if the userdb returns an "uid" field that
# matches the caller process's UID. Also if caller's uid or gid matches the
# socket's uid or gid the lookup succeeds. Anything else causes a failure.
#
# To give the caller full permissions to lookup all users, set the mode to
# something else than 0666 and Dovecot lets the kernel enforce the
# permissions (e.g. 0777 allows everyone full permissions).
unix_listener auth-userdb {
#mode = 0666
#user =
#group =
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
# Auth process is run as this user.
#user = $default_internal_user
}
service auth-worker {
# Auth worker process is run as root by default, so that it can access
# /etc/shadow. If this isn't necessary, the user should be changed to
# $default_internal_user.
#user = root
}
Restart Dovecot
Everything is done. Now, restart the Dovecot service to apply the changes, and enable it so that it will start automatically on system boot.
sudo systemctl restart dovecot
sudo systemctl enable dovecot
After that, check the status of Dovecot to make sure the service is running properly and no errors have occurred:
sudo systemctl status dovecot
If everything is working correctly, you will see the Dovecot status displayed as active (running).
Test with Outlook/Thunderbird
At this point, you already have a fairly complete mail server. Now, open Outlook or any mail client application to start using it. In this example, I will be using Outlook.
In the Auto Account Setup window, select Manual setup or additional server types and then click Next to continue.

Next, in the Choose Service window, select POP or IMAP and then click Next to continue.

Next, in the POP and IMAP Account Settings window, configure the following information:
- Your Name: Enter the display name for your outgoing emails
- Email Address: Enter your email address
- Account Type: Select POP3 (recommended) or IMAP
- Incoming mail server: The IMAP/POP server address (e.g., mail.totatcaz.xyz)
- Outgoing mail server (SMTP): The SMTP server address (e.g., mail.totatcaz.xyz)
- User Name: Enter your user (without @domain. e.g., totatca)
- Password: Enter your user password

- Click on More settings
- In the Outgoing Server tab, check My outgoing server (SMTP) requires authentication and select Use same settings as my incoming mail server.

- In the Advanced tab:
- Check This server requires an encrypted connection (SSL) to use port 995 for IMAP/POP3.
- For the Outgoing server (SMTP), enter 587 for TLS or 465 for SSL.

Finally, click OK to close the configuration windows.
Now, try sending an email to test the setup. If everything is configured correctly, the email will be sent successfully, and you will also be able to receive messages in your inbox.
Conclusion
You have successfully completed the installation and configuration of a Mail Server with Postfix + Dovecot + SSL/TLS on Ubuntu/Debian. Your server is now ready to securely send and receive emails.
As the next step, you should configure DKIM to improve email deliverability, enhance your domain’s reputation, and reduce the risk of your emails being marked as spam.
Video