Run Your Own Email Server on CentOS/RHEL – Postfix SMTP Server

Why run your own email server? Perhaps you have a website, which needs to send emails to users, or maybe you want to store your emails on your own server to protect your privacy. However, building your own email server from scratch can be a pain in the butt because there are so many software components you need to install and configure properly. To make this journey easy for you, I’m creating a tutorial series on how to build your own email server on CentOS.

I’m confident to say that this will be the best tutorial series about building email server from scratch on the Internet. Not only will you have a working email server, but also you will have a much better understanding about how email works. This tutorial series is divided into 9 parts:

  1. Setting up a basic Postfix SMTP server
  2. Set up Dovecot IMAP server and TLS encryption
  3. Create Virtual Mailboxes with PostfixAdmin
  4. Creating SPF and DKIM record to get through spam filters
  5. Setting up DMARC to protect your domain reputation
  6. How to Stop Your Emails From Being Marked as Spam
  7. How to Host Multiple Mail Domains in PostfixAdmin
  8. Blocking Email Spam with Postfix
  9. Blocking Email Spam with SpamAssassin

I know this seems to be a very daunting task. However, based on what you want to achieve, you might not need to follow all of them. My articles are easy to follow, so if you dedicate sometime to it, you will have a working email server.

This article is part 1 of this tutorial series. In this article, I will show you how to set up a basic Postfix SMTP server, also known as an MTA (message transport agent). Once you finish this article, you should be able to send and receive emails with your own email domain on your own email server. This tutorial is tested on CentOS 8/RHEL 8.

About Postfix

Postfix is a state-of-the-art message transport agent (MTA), aka SMTP server, which serves two purposes.

  • It’s responsible for transporting email messages from a mail client/mail user agent (MUA) to a remote SMTP server.
  • It’s also used to accept emails from other SMTP servers.

Postfix was built by Wietse Venema who is a Unix and security expert. It’s easy to use, designed with security and modularity in mind, with each module running at the lowest possible privilege level required to get the job done. Postfix integrates tightly with Unix/Linux and does not provide functionalities that Unix/Linux already provides. It’s reliable in both simple and stressful conditions.

Postfix was originally designed as a replacement for Sendmail – the traditional SMTP server on Unix. In comparison, Postfix is more secure and easier to configure. It is compatible with Sendmail, so if you uninstall Sendmail and replace it with Postfix, your existing scripts and programs will continue to work seamlessly.

In this tutorial, you will learn how to configure Postfix for a single domain.

Prerequisites

In order to send emails from your server, port 25 (outbound) must be open. Many ISPs and hosting providers such as DigitalOcean block port 25 to control spam and they would not unblock it. I recommend using Hostwinds VPS (virtual private server), because it doesn’t block port 25 (outbound), so you can send unlimited emails with no extra cost. Before you buy a VPS, you can ask them if port 25 is blocked. Here’s a transcript of a live chat with hostwinds.

hostwinds live chat transcript

Once you have a hostwinds server, install CentOS/RHEL on it and follow the instructions below.

Note: If your VPS provider doesn’t offer one-click install for CentOS 8, read the following article to install CentOS 8 on VPS in VNC mode.

You also need a domain name. I registered my domain name from NameCheap because the price is low and they give you whois privacy protection free for life.

Things To Do Before Installing Postfix

To make Postfix perform better and get the most out of Postfix, you need to properly set up your CentOS/RHEL Server.

Set A Correct Hostname for CentOS/RHEL Server

By default, Postfix uses your server’s hostname to identify itself when communicating with other MTAs. Hostname can have two forms: a single word and FQDN.

The single word form is used mostly on personal computers. Your Linux home computer might be named linux, debian, ubuntu etc. FQDN (Fully Qualified Domain Name) is commonly used on Internet-facing servers and we should use FQDN on our mail servers. It consists of two parts: a node name and a domain name. For example:

mail.linuxbabe.com

is an FQDN. mail is the nodename, linuxbabe.com is the domain name. FQDN will appear in the smtpd banner. Some MTAs reject messages if your Postfix does not provide FQDN in smtpd banner. Some MTAs even query DNS to see if FQDN in the smtpd banner resolves to the IP of your mail server.

Enter the following command to see the FQDN form of your hostname.

hostname -f

If your CentOS/RHEL server doesn’t have an FQDN yet, you can use hostnamectl to set one.

sudo hostnamectl set-hostname mail.yourdomain.com

A common FQDN for mail server is mail.yourdomain.com. You need to log out and log back in to see this change at the command prompt. Also note that FQDN can be overridden by Postfix with myhostname parameter in the Postfix configuration file. I will show you how to do it later in the article.

Create DNS Records for Your Mail Server

You need to go to your DNS hosting service (usually your domain registrar) to create DNS records.

MX record

An MX record tells other MTAs that your mail server mail.yourdomain.com is responsible for email delivery for your domain name.

MX record    @           mail.linuxbabe.com

A common name for the MX host is mail.yourdomain.com. You can specify more than one MX record and set priority for your mail servers. A lower number means higher priority. Here we only use one MX record and set 0 as the priority value. (0 – 65355)

A record

An A record maps a FQDN to an IP address.

mail.linuxbabe.com        <IP-address>

AAAA record

If your server uses IPv6 address, it’s also a good idea to add AAAA record for mail.yourdomain.com.

mail.linuxbabe.com        <IPv6-address>

PTR record

A pointer record, or PTR record, maps an IP address to an FQDN. It’s the counterpart to the A record and is used for reverse DNS lookup.

Reverse resolution of IP address with PTR record can help with blocking spammers. Many MTAs accept email only if the server is really responsible for a certain domain. You should definitely set a PTR record for your email server so your emails have a better chance of landing in recipient’s inbox instead of spam folder.

To check the PTR record for an IP address, you can use the following command.

dig -x <IP> +short

or

host <IP>

Because you get IP address from your hosting provider, not from your domain registrar, so you must set PTR record for your IP address in your hosting provider’s control panel. If your server uses IPv6 address, then add PTR record for your IPv6 address as well.

After all of the above is done, let’s play with Postfix.

Installing Postfix

On your CentOS/RHEL server, run the following two commands.

sudo dnf update

sudo dnf install postfix -y

Once it’s installed, start Postfix SMTP server.

sudo systemctl start postfix

And enable auto-start at boot time.

sudo systemctl enable postfix

Now you can check its status with:

systemctl status postfix

centos postfix

As you can see, Postfix is now active (running) and auto-start at boot time is enabled. You can check Postfix version with this command:

postconf mail_version

CentOS 8/RHEL 8 ships with Postfix v3.3.1.

mail_version = 3.3.1

Postfix ships with many binaries under the /usr/sbin/ directory, as can be seen with the following command.

rpm -ql postfix | grep /usr/sbin/

Output:

/usr/sbin/postalias
/usr/sbin/postcat
/usr/sbin/postconf
/usr/sbin/postdrop
/usr/sbin/postfix
/usr/sbin/postkick
/usr/sbin/postlock
/usr/sbin/postlog
/usr/sbin/postmap
/usr/sbin/postmulti
/usr/sbin/postqueue
/usr/sbin/postsuper
/usr/sbin/sendmail
/usr/sbin/sendmail.postfix
/usr/sbin/smtp-sink
/usr/sbin/smtp-source

The netstat utility tells us that the Postfix master process is listening on TCP port 25 of localhost. (If your CentOS/RHEL server doesn’t have the netstat command, you can run sudo dnf install net-tools command to install it.)

sudo netstat -lnpt | grep master

centos mail server

Configuring Postfix

Listening on the public IP address

We can also use the following command to see which interface Postfix is listening on. Postconf is a Postfix configuration utility that can display the value of parameters in Postfix main configuration file (/etc/postfix/main.cf).

postconf inet_interfaces

Output:

inet_interfaces = localhost

We need to run the following command to configure Postfix to listen on the public IP address so it will be able to receive emails from other SMTP servers. The -e option enables postconf to edit the Postfix main configuration file.

sudo postconf -e "inet_interfaces = all"

Setting the Postfix hostname

By default, Postfix SMTP server uses the OS’s hostname. You can display the current Postfix hostname with the following command.

postconf myhostname

Postfix uses this hostname to identify itself when communicating with other SMTP server. However, the OS hostname might change, so it’s a good practice to set the hostname directly in Postfix configuration file with the following command.

sudo postconf -e "myhostname = mail.yourdomain.com"

Setting $mydomain Parameter

The $mydomain parameter specifies the local internet domain name. The default is to use $myhostname minus the first component. You can display the current value of $mydomain with:

postconf mydomain

It should be your apex domain name, like

linuxbabe.com

If it’s not displaying your apex domain name, then set the $mydomain parameter with:

sudo postconf -e "mydomain = yourdomain.com"

Setting $myorigin Parameter

The $myorigin parameter specifies the default domain name that is appended to sender and recipient addresses that have no @domain part. The default is to use the value of $myhostname, as can be seen with:

postconf myorigin

Output:

myorigin = $myhostname

You can change its value to yourdomain.com.

sudo postconf -e "myorigin = yourdomain.com"

Setting $mydestination Parameter

The $mydestination parameter specifies the list of domains that your server considers itself the final destination for. You can display the current value of $mydestination with:

postconf mydestination

Output

mydestination = $myhostname, localhost.$mydomain, localhost

The default value allows your Postfix SMTP server to receive emails coming for [email protected], [email protected] and [email protected], but it won’t allow you Postfix SMTP server to receive emails coming for [email protected]. In order to achieve that, add yourdomain.com to the list of domains.

sudo postconf -e "mydestination = yourdomain.com, \$myhostname, localhost.\$mydomain, localhost"

Restarting Postfix

Finally, we need to restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Open Port 25 (inbound) in Firewall

Run the following commands to open port 25 (inbound), so Postfix can receive emails from other SMTP servers.

sudo firewall-cmd --permanent --zone=public --add-port=25/tcp

sudo systemctl reload firewalld

Then we can use nmap to scan open ports on our server. Run the following command on a separate computer such as your personal computer. (I assume you are reading this tutorial on a Linux computer.) Replace your-server-ip with actual IP.

sudo nmap your-server-ip

build your own email server

You can see  from the above screenshot that TCP port 25 is open on my server.

nmap can be installed on Linux with one of the following commands, depending on your Linux distro.

sudo apt install nmap

sudo dnf install nmap

sudo zypper install nmap

sudo pacman -S nmap

Checking If Port 25 (outbound) is blocked

Install the telnet utility.

sudo dnf install telnet

Run the following command on your mail server to check if port 25 (outbound) is blocked.

telnet gmail-smtp-in.l.google.com 25

If it’s not blocked, you would see messages like below, which indicates a connection is successfully established. (Hint: Type in quit and press Enter to close the connection.)

Trying 74.125.68.26...
Connected to gmail-smtp-in.l.google.com.
Escape character is '^]'.
220 mx.google.com ESMTP y22si1641751pll.208 - gsmtp

If port 25 (outbound) is blocked, you would see something like:

Trying 2607:f8b0:400e:c06::1a...
Trying 74.125.195.27...
telnet: Unable to connect to remote host: Connection timed out

In this case, your Postfix can’t send emails to other SMTP servers. Ask your ISP/hosting provider to open it for you. If they refuse your request, you need to set up SMTP relay to bypass port 25 blocking.

Sending Test Email

As a matter of fact, we can now send and receive email from the command line. If your CentOS/RHEL server has a user account called user1, then the email address for this user is [email protected]. You can send an email to root user [email protected]. You can also send emails to Gmail, yahoo mail or any other email service.

When installing Postfix, a sendmail binary is placed at /usr/sbin/sendmail, which is compatible with the traditional Sendmail SMTP server. You can use Postfix’s sendmail binary to send a test email to your Gmail account like this:

echo "test email" | sendmail [email protected]

In this simple command, sendmail reads a message from standard input and make “test email” as the message body, then send this message to your Gmail account.

You should be able to receive this test email in your Gmail inbox (or spam folder). You can see that although we didn’t specify the from address, Postfix automatically append a domain name for the from address. That’s because we have set the $myorigin parameter.

Also, you can try to reply to this test email to see if Postfix can receive email messages. It’s likely that emails sent from your domain are labeled as spam. Don’t worry, we will tackle it in part 3 of this tutorial series.

The inbox for each user is located at /var/spool/mail/<username> or /var/mail/<username> file. If you are unsure where to look for the inbox, use this command.

postconf mail_spool_directory

The Postfix mail log is stored at /var/log/maillog.

Using the mail program to Send and Read Email On the Command Line

Now let’s install a command-line MUA (mail user agent).

sudo dnf install mailx

To send email, type

mail [email protected]
[email protected]:~$ mail [email protected]
Cc: 
Subject: 2nd test email
I'm sending this email using the mail program.

Enter the subject line and the body text. To tell mail that you have finished writing, press Ctrl+D and mail will send this email message for you.

To read incoming emails, just type mail.

mail

Here’s how to use the mail program to manage your mailbox.

  • To read the first email message, type 1. You will see both the email headers and email body. If only parts of the message is displayed, press Enter to show the remaining part of the message.
  • To display message headers starting from message 1, type h.
  • To show the last screenful of messages, type h$ or z.
  • To read the next email message, type n.
  • To delete message 1, type d 1.
  • To delete message 1, 2 and 3, type d 1 2 3.
  • To delete messages from 1 to 10, type d 1-10.
  • To replay to message 1, type reply 1.
  • To exit out of mail, type q.

Messages that have been opened will be moved from /var/mail/<username> to /home/<username>/mbox file. That means other mail clients can’t read those messages. To prevent this from happening, type x instead of q to exit out of the mail.

How To Increase Attachment Size Limit

By default, the attachment cannot be larger than 10MB, which is indicated by the message_size_limit parameter.

postconf message_size_limit

Output:

message_size_limit = 10240000

This parameter defines the size limit for emails originating from your own mail server and for emails coming to your mail server. To allow attachment of 50MB in size, run the following command.

sudo postconf -e message_size_limit=52428800

Note that the message_size_limit should not be larger than the mailbox_size_limit, whose default value is 51200000 bytes (about 48MB), as can be seen with

postconf mailbox_size_limit

Output:

mailbox_size_limit = 51200000

If you want no size limit for the mailbox, set the value to 0.

sudo postconf -e mailbox_size_limit=0

Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

When sending an email with large attachments from your mail server, you should also beware of the receiving server’s attachment size limit. For example, You can not send an attachment larger than 25MB to a Gmail address.

Creating Email Alias

There are certain required aliases that you should configure when operating your mail server in a production environment. You can add email alias in the /etc/aliases file, which is a special Postfix lookup table file using a Sendmail-compatible format.

sudo nano /etc/aliases

By default, the Postfix package on CentOS defines many aliases, such as

postmaster: root

The left-hand side is the alias name. The right-hand side is the final destination of the email message. So emails for [email protected] will be delivered to [email protected]. The postmaster email address is required by RFC 2142.

Normally we don’t use the root email address. Instead, the postmaster can use a normal login name to access emails. So you can add the following line. Replace username with your real username.

root:   username

This way, emails for [email protected] will be delivered to [email protected].  Now you can save and close the file. Then rebuild the alias database with the newaliases command

sudo newaliases

Wrapping Up

Congrats! Now you have a basic Postfix email server up and running. You can send plain text emails and read incoming emails using the command line. In the next part of this tutorial series, we will see how to install Dovecot IMAP server and enable TLS encryption. Stay tuned!

Rate this tutorial
[Total: 1 Average: 5]

10 Responses to “Run Your Own Email Server on CentOS/RHEL – Postfix SMTP Server

  • One small ‘error’ in the guide I found was that I had to escape the ‘$’ characters when setting up the mydestination parameter as follows

    sudo postconf -e “mydestination = mydomain, \$myhostname, localhost.\$mydomain, localhost”

    Otherwise (as usual) a great guide. Thank you.

  • Piter yong
    1 month ago

    First, thanks for great tutorial…
    I have one quick question, I have successfully configured postfix server to follow this tutorial, now I have others servers in my infrastructure like nagios core, gitlab and big data cluster how they will send email notification to an email address???

    • Most web applications provide SMTP settings. Check each application’s documentation to find where’s the SMTP settings.

      In the SMTP setting, normally you need to enter

      mail server address:   mail.example.com
      username:              [email protected]
      password:              your_password
      port number:           587
      Encryption:            STARTTLS (or SSL, TLS)
      
      • Piter yong
        1 month ago

        Okay, I have minimal CentOS installed and it takes backup of several applications based on crontab scheduled and I would like to get a notification when backup get completed so where I need to set SMTP setting to get the notification.

    • If you have two servers:

      A is your standard mail server.
      B is server for other stuff.

      Then you can install Postfix on server B, so server B will be able to send email notifications to an email address on server A.

      Add the server B’s IP address to the Postfix mynetworks parameter on server A, so server B won’t have to go through server A’s spam filter.

      You don’t need to install other mail server components like IMAP server on server B.

  • Aleksandr
    21 hours ago

    still mail does not leave my site – help me please
    here maillog

    Apr 3 20:20:35 mail postfix/cleanup[5540]: 9A440E80090: message-id=
    Apr 3 20:20:35 mail opendkim[1871]: 9A440E80090: no signing table match for ‘[email protected]
    Apr 3 20:20:35 mail opendkim[1871]: 9A440E80090: no signature data
    Apr 3 20:20:35 mail postfix/qmgr[5527]: 9A440E80090: from=, size=710, nrcpt=1 (queue active)
    Apr 3 20:20:35 mail postfix/submission/smtpd[5529]: disconnect from unknown[77.79.135.68] ehlo=2 starttls=1 auth=1 mail=1 rcpt=1 data=1 quit=1 commands=8
    Apr 3 20:20:39 mail postfix/smtp[5541]: 9A440E80090: to=, relay=mx01.mail.com[74.208.5.22]:25, delay=3.6, delays=0.15/0.04/2.1/1.4, dsn=2.0.0, status=sent (250 Requested mail action okay, completed: id=0Ma1hh-1jcCUL1o2J-00LkvM)
    Apr 3 20:20:39 mail postfix/qmgr[5527]: 9A440E80090: removed
    Apr 3 20:23:55 mail postfix/anvil[5532]: statistics: max connection rate 1/60s for (submission:77.79.135.68) at Apr 3 20:20:35
    Apr 3 20:23:55 mail postfix/anvil[5532]: statistics: max connection count 1 for (submission:77.79.135.68) at Apr 3 20:20:35
    Apr 3 20:23:55 mail postfix/anvil[5532]: statistics: max cache size 1 at Apr 3 20:20:35

  • Aleksandr
    2 hours ago

    my happiness knows no bounds – everything worked out

    last question – for some reason there are no incoming letters – only logs

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.