Set Up Postfix Send-Only SMTP Server on CentOS 8

In this article, I will show you how to set up Postfix as a send-only SMTP server on CentOS 8. I will first show you how to do it for a single domain, then you can apply the steps for multiple domains if you need to.

Set Up Postfix Send-Only SMTP Server on CentOS 8

Use Case

You have a website/web application that needs to send transactional emails to users (such as password-reset email). Most likely, there’s no need for users to reply to these emails, or if they reply, the reply emails will be sent to your dedicated mail server. In this case, you can set up a send-only SMTP server on the web server using Postfix, which is a popular SMTP server software.

Prerequisites

In order to send emails from your server, port 25 (outbound) must be open. Many ISPs and hosting companies such as DigitalOcean block port 25 to control spam. I recommend using Hostwinds, because it doesn’t block port 25 (outbound). Once you have a Hostwinds server, install CentOS 8 on it, and follow the instructions below.

Setting up Postfix send-only SMTP server for multiple domains isn’t difficult actually. First, we need to configure it for one domain, then set it up for multiple domains.

Step 1: Set Hostname and PTR Record

By default, Postfix uses your server’s hostname to identify itself when communicating with other SMTP Servers. Some SMTP servers will reject your email if your hostname isn’t valid. You should set a full-qualified domain name (FQDN) like below.

sudo hostnamectl set-hostname mta1.yourdomain.com

To check the hostname of your server, run

hostname -f

You need to log out and log back in to see hostname change at the command prompt. This hostname should have a DNS A record pointing to the IP address of your server.

Also, you need to set a PTR record (aka, pointer record), which maps an IP address to an FQDN. It’s the counterpart to the A record. Many SMTP server will reject your email if your server’s IP address doesn’t have PTR record.

Because you get IP address from your hosting provider or ISP, not from your domain registrar, so you must set PTR record for your IP in the control panel of your hosting provider, or ask your ISP. For example, in Hostwinds, you can set PTR record by clicking the Domains tab and clicking the Manage rDNS link. Although you can set PTR record to any hostname, for best practice, you should use the FQDN you just set.

To see if your PTR record is set properly, run the following command. Replace 12.34.56.78 with your own IP address.

host 12.34.56.78

Note that if your server uses IPv6 address, it’s also a good idea to add AAAA record for your FQDN and set PTR record for your IPv6 address.

Step 2: Install Postfix on CentOS 8

Run the following commands to install Postfix from the default CentOS 8 repository.

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

Step 3: Configure Postfix

Setting the Postfix hostname

By default, Postfix SMTP server uses the OS’s 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 = mta1.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"

Restarting Postfix

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

sudo systemctl restart postfix

Step 4: Install and Configure OpenDKIM on CentOS 8

DKIM stands for DomainKeys Identified Mail. You can install OpenDKIM on your server and use it to add signatures to emails sent from your domain, with your private key. Receiving SMTP servers verify the signature by using the corresponding public key, which is published by you in the DNS. Adding DKIM signature is a must if you want your emails to get into the recipient’s inbox.

Install OpenDKIM from the EPEL (Extra Packages for Enterprise Linux) repository.

sudo dnf install epel-release

sudo dnf install opendkim perl-Getopt-Long

Edit OpenDKIM main configuration file.

sudo nano /etc/opendkim.conf

Find the following line.

Mode     v

By default, OpenDKIM runs in verification mode (v), which will verify the DKIM signature of incoming email messages. We need to sign outgoing emails, so change this line to the following to enable signing mode.

Mode           sv

Find the following line and comment it out, because we will use separate keys for each domain name.

KeyFile   /etc/opendkim/keys/default.private

Next, find the following 4 lines and uncomment them.

# KeyTable            /etc/opendkim/KeyTable

# SigningTable        refile:/etc/opendkim/SigningTable

# ExternalIgnoreList  refile:/etc/opendkim/TrustedHosts

# InternalHosts       refile:/etc/opendkim/TrustedHosts

Save and close the file.

Create Signing Table, Key Table and Trusted Hosts File

Edit the signing table file.

sudo nano /etc/opendkim/SigningTable

Add the following line at the end of this file. This tells OpenDKIM that if a sender on your server is using a @your-domain.com address, then it should be signed with the private key identified by mta1._domainkey.your-domain.com.

*@your-domain.com    mta1._domainkey.your-domain.com

mta1 is the DKIM selector. A domain name might have multiple DKIM keys. The DKIM selector allows you to choose a particular DKIM key. You can use whatever name for the DKIM selector. I think it’s convenient to use the leftmost part of the hostname as the DKIM selector. Save and close the file. Then edit the key table file.

sudo nano /etc/opendkim/KeyTable

Add the following line, which specifies the location of the DKIM private key.

mta1._domainkey.your-domain.com     your-domain.com:mta1:/etc/opendkim/keys/your-domain.com/mta1.private

Save and close the file. Next, edit the trusted hosts file.

sudo nano /etc/opendkim/TrustedHosts

127.0.0.0.1 and ::1 are included in this file by default. Now add the following line. This tells OpenDKIM that if an email is coming from your own domain name, then OpenDKIM should not perform DKIM verification on the email.

*.your-domain.com

Save and close the file.

Generate Private/Public Keypair

Since DKIM is used to sign outgoing messages and verify incoming messages, you need to generate a private key to sign outgoing emails and a public key for receiving SMTP servers to verify the DKIM signature of your email. Public key will be published in DNS.

Create a separate folder for the domain.

sudo mkdir /etc/opendkim/keys/your-domain.com

Generate keys using opendkim-genkey tool.

sudo opendkim-genkey -b 2048 -d your-domain.com -D /etc/opendkim/keys/your-domain.com -s mta1 -v

The above command will create 2048 bits keys. -d (domain) specifies the domain. -D (directory) specifies the directory where the keys will be stored. I use mta1 as the DKIM selector. Once the command is executed, the private key will be written to mta1.private file and the public key will be written to mta1.txt file.

centos 8 send-only smtp server opendkim

By default, only root can read and write to the key files. Make opendkim as the owner of the private key.

sudo chown opendkim:opendkim /etc/opendkim/keys/ -R

Publish Your Public Key in DNS Records

Display the public key

sudo cat /etc/opendkim/keys/your-domain.com/mta1.txt

The string after the p parameter is the public key.

centos-8-send-only-smtp-server-dkim-key

In you DNS manager, create a TXT record, enter mta1._domainkey in the name field. Then go back to the terminal window, copy everything in the parentheses and paste it into the value field of the DNS record. You need to delete all double quotes and line breaks in the value field. If you don’t delete them, then key test in the next step will probably fail.

centos 8 send only smtp postfix dkim record

Test DKIM Key

Enter the following command on your CentOS 8 server to test your key.

sudo opendkim-testkey -d your-domain.com -s mta1 -vvv

If everything is OK, you will see the key OK message.

opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key 'mta1._domainkey.linuxbabe.com'
opendkim-testkey: key OK

If you see “Key not secure”, don’t panic. This is because DNSSEC isn’t enabled on your domain name. DNSSEC is a security standard for secure DNS query. Most domain names haven’t enabled DNSSEC. You can continue to follow this guide.

Now we can start the opendkim service.

sudo systemctl start opendkim

And enable auto-start at boot time.

sudo systemctl enable opendkim

OpenDKIM listens on 127.0.0.1:8891.

Step 5: Connect Postfix to OpenDKIM

Edit Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Add the following lines at the end of this file, so Postfix will be able to call OpenDKIM via the milter protocol. Note that you should use 127.0.0.1 as the address. Don’t use localhost.

# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters

Save and close the file. Then add postfix user to opendkim group.

sudo gpasswd -a postfix opendkim

Restart postfix service.

sudo systemctl restart postfix

Step 6: Create SPF DNS Record

SPF (Sender Policy Framework) record specifies which hosts or IP addresses are allowed to send emails on behalf of a domain. In your DNS management interface, create a new TXT record like below. Use your own IPv4 address and IPv6 address of your server.

TXT  @   v=spf1 mx ip4:12.34.56.78 ip6:2600:3c01::f03c:93d8:f2c6:78ad ~all

Step 7: Set the From Address, From Name and Return-Path

You can set custom From address, From name and Return-Path in your website/web application. Let’s use WordPress as an example. You can add the following lines in your WordPress theme’s functions.php file to override the default From address, From name and return-path. Replace the red text as necessary.

// Function to change From email address
function wpb_sender_email( $original_email_address ) {
    return 'notifications@linuxbabe.com';
}

// Function to change sender name
function wpb_sender_name( $original_email_from ) {
    return 'LinuxBabe';
}

// Set return-path the same as From address
function fix_my_email_return_path( $phpmailer ) {
    $phpmailer->Sender = $phpmailer->From;
}

// Hooking up our functions to WordPress filters
add_filter( 'wp_mail_from', 'wpb_sender_email' );
add_filter( 'wp_mail_from_name', 'wpb_sender_name' );
add_action( 'phpmailer_init', 'fix_my_email_return_path' );

Save the file and you are done.

Step 8: Enable TLS Encryption for Outgoing Emails

By default, Postfix doesn’t use TLS encryption when sending outgoing emails. To enable TLS encryption, open the /etc/postfix/main.cf file and add the following two lines at the end of this file.

smtp_tls_security_level = may
smtp_tls_loglevel = 1

The first line enables TLS encryption for the Postfix SMTP client. The second line will log the TLS connection in /var/log/maillog file, so you can check if TLS encryption is working. Save and close the file. Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Since Postfix doesn’t receive incoming emails, there’s no need to configure a valid TLS certificate for the Postfix SMTP daemon.

Step 9: Testing Sender Score

Now go to https://www.mail-tester.com. You will see a unique email address. Send an email from your website on the Postfix SMTP server to this address and then check your score. As you can see, I got a perfect score. In the test result, you should check if your PTR record, SPF and DKIM record is valid.

Testing Email Score and Placement

You can also open the /var/log/maillog file to check if TLS encryption is used. For example, the following line shows the connection to mail-tester.com is encrypted.

Anonymous TLS connection established to mail-tester.com[94.23.206.89]:25: TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)

What if Your Emails Are Still Being Marked as Spam?

I have more tips on email deliverability for you in this article: How to stop your emails being marked as spam. Although it will take some time and effort, your emails will eventually be placed in the inbox after applying these tips.

How to Configure Postfix Send-only SMTP Server For Multiple Domains

By default, Postfix allows you to use any domain name in the From header and return path address to send outgoing emails. If your server hosts multiple websites, you just need to create SPF DNS record for your other domains, which is very easy to do, and configure OpenDKIM for your other domains.

To configure OpenDKIM for other domains, you need to add the other domains in the signing table, key table and trusted hosts file like below.

Signing table:

*@example.com       mta1._domainkey.example.com
*@example.net       mta1._domainkey.example.net

Key table:

mta1._domainkey.example.com     example.com:mta1:/etc/opendkim/keys/example.com/mta1.private
mta1._domainkey.example.net     example.net:mta1:/etc/opendkim/keys/example.net/mta1.private

Trusted hosts:

127.0.0.1
localhost

*.example.com
*.example.net

Then generate the DKIM Private/Public keypair by following the same steps as mentioned above for other domains and add the DKIM public key in DNS. Restart OpenDKIM and you are done. Don’t forget to test your sender score.

Troubleshooting

If your message is not signed and DKIM check failed, you may want to check postfix log (/var/log/maillog) to see what’s wrong in your configuration.

Sending Emails From Another Server

There are two ways to allow other servers to send emails through your send-only Postfix SMTP server.

  • Use port 25 without SMTP authentication: This method requires the other server doesn’t block port 25 (outbound).
  • Use port 587 with SMTP authentication: If the other server blocks port 25 (outbound), you can use port 587.

Port 25 without SMTP Authentication

By default, Postfix on CentOS 8 listens on localhost only. You need to configure Postfix to listen on 0.0.0.0, so other servers can connect to the send-only Postfix SMTP server.

sudo postconf "inet_interfaces = all"

Then you need to add the IP address of the other server to the Postfix mynetworks parameter. Replace 12.34.56.78 with the real IP address.

sudo postconf "$(postconf mynetworks) 12.34.56.78"

Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Run the following commands to open port 25 (inbound).

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

sudo systemctl reload firewalld

Now you can configure SMTP clients to use mta1.yourdomain.com and port 25 to send emails. You don’t need to specify username/password in the SMTP client.

Port 587 with SMTP Authentication

Open port 587 and 80 in firewall.

sudo firewall-cmd --permanent --add-service={smtp-submission,http}

sudo systemctl reload firewalld

By default, Postfix on CentOS 8 listens on localhost only. You need to configure Postfix to listen on 0.0.0.0, so other servers can connect to the send-only Postfix SMTP server.

sudo postconf "inet_interfaces = all"

Then you need to enable the submission service of Postfix so that the email client can submit emails to Postfix SMTP server. Edit the master.cf file.

sudo nano /etc/postfix/master.cf

In submission section, uncomment or add the following lines. Please allow at least one whitespace (tab or spacebar) before each -o.  In postfix configurations, a preceding whitespace character means that this line is continuation of the previous line. (By default the submission section is commented out. You can copy the following lines and paste them into the file, so you don’t have to manually uncomment or add new text.)

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

The above configuration enables the submission daemon of Postfix and requires TLS encryption on SMTP authentication. Plain text authentication will be rejected. Save and close the file. To enable SMTP authentication, we need to install Dovecot on CentOS 8/RHEL 8 server.

sudo dnf install dovecot

Start Dovecot and enable auto-start at boot time.

sudo systemctl start dovecot

sudo systemctl enable dovecot

Edit the authentication config file.

sudo nano /etc/dovecot/conf.d/10-auth.conf

Uncomment the following line.

disable_plaintext_auth = yes

It will disable plaintext authentication when there’s no SSL/TLS encryption. And if you want to use full email address (username@your-domain.com) to login, add the following line in the file.

auth_username_format = %n

Otherwise, you are able to login with username only (without @your-domain.com). Next, find the following line.

auth_mechanisms = plain

This line only enables the PLAIN authentication mechanism. LOGIN is another authentication mechanism you probably want to add to support older email clients.

auth_mechanisms = plain login

Save and close the file. Then edit the following file.

sudo nano /etc/dovecot/conf.d/10-master.conf

Change service auth section to the following so that Postfix can find the Dovecot authentication server.

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

Postfix-SMTP-Auth-centos8

Save and close the file. Restart Dovecot for the changes to take effect.

sudo systemctl restart dovecot

Next, we need to obtain a valid TLS certificate. We can easily obtain a free TLS certificate from Let’s Encrypt. Issue the following commands to install Let’s Encrypt client (certbot) on CentOS 8/RHEL 8 from the EPEL repository.

sudo dnf install certbot

Then use the standalone plugin to obtain TLS certificate (assuming there’s no web server running on the Postfix SMTP server).

sudo certbot certonly --standalone --agree-tos --email you@example.com -d mta1.yourdomain.com

After a while, you should see the following lines which means the certificate is successfully obtained. You can also see the directory under which your cert is stored.

centos 8 postfix send-only tls certificate

Next, we need to run the following two commands to specify the location of TLS certificate and private key in Postfix configuration file. Your Let’s Encrypt certificate and private key are stored under /etc/letsencrypt/live/mta1.your-domain.com/ directory.

sudo postconf "smtpd_tls_cert_file = /etc/letsencrypt/live/mta1.your-domain.com/fullchain.pem"

sudo postconf "smtpd_tls_key_file = /etc/letsencrypt/live/mta1.your-domain.com/privkey.pem"

Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Now you can configure SMTP clients to use mta1.yourdomain.com and port 587 to send emails. Use TLS encryption type and plain as authentication mode. You need to create email account on the SMTP server. That’s very simple. Use the adduser command to add a user.

sudo adduser user1

Then set a password for this user.

sudo passwd user1

The email address will be user1@yourdomain.com.

Removing Sensitive Information from Email Headers

By default, Postfix SMTP server will add a Received: email header, recording the IP address of the client, which can leak the IP address of your website (If it’s behind CDN). You can tell Postfix to ignore it. Create a header check file.

sudo nano /etc/postfix/smtp_header_checks

Put the following lines into the file.

/^Received:/            IGNORE

Save and close the file. Then edit the Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Add the following line at the end of the file.

smtp_header_checks = regexp:/etc/postfix/smtp_header_checks

Save and close the file. Then run the following command to rebuild hash table.

sudo postmap /etc/postfix/smtp_header_checks

Reload Postfix for the change to take effect.

sudo systemctl reload postfix

Now Postfix won’t include that sensitive information in email headers.

Auto-Renew TLS Certificate

You can create Cron job to automatically renew TLS certificate. Simply open root user’s crontab file.

sudo crontab -e

Then add the following line.

@daily certbot renew --quiet

Save and close the file.

Conclusion

I hope this tutorial helped you set up a Postfix send-only SMTP server on CentOS 8 for multiple domains. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial
[Total: 2 Average: 5]

2 Responses to “Set Up Postfix Send-Only SMTP Server on CentOS 8

  • Amishtechie
    4 weeks ago

    Thank you! The section on smtp header checks was very helpful.

  • great tutorial, very usefull. Can you maybe do another tutorial about bounce handling on mail servers with postfix / dovecot and bounce templates?
    I got an email server up and running, but the bounce part is not fully working yet. I get empty reply messages or just a icon with an question mark, when using my google mail as sender. If I send the message again to a non existing address, the bounce message is working. So not sure, what’s wrong or what to look for.

    Cheers

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.


The maximum upload file size: 2 MB.
You can upload: image.