Many organizations have a requirement to configure a mail transfer agent (MTA) on Red Hat Enterprise Linux (RHEL) servers. This is frequently done to enable servers to send out notifications or reports over email. For example, you might configure a script to email out a notification after an event occurs, or you might have a script to email out a monthly report after it is generated.  

RHEL 7, 8 and 9 provide two options for MTAs: Postfix and Sendmail. Sendmail has been deprecated, and this post will be focusing on Postfix.

It is possible to install and configure Postfix on RHEL systems manually, following the documentation, however this can be time-consuming and prone to error. Red Hat introduced the postfix RHEL System Role to provide an automated solution to install and configure Postfix.  The postfix RHEL System Role was introduced in RHEL 7.6 as a technology preview feature.  With the release of RHEL 8.5, the postfix RHEL System Role is now fully supported.  

RHEL System Roles are a collection of Ansible roles and modules that are included in RHEL to help provide consistent workflows and streamline the execution of manual tasks. 

Environment overview

In my example environment, I have a control node system named controlnode running RHEL 8 and four managed nodes: rhel8-server1, rhel8-server2, rhel7-server1, and rhel7-server2 (the first two running RHEL 8, and the other two running RHEL 7).   I would like to configure Postfix on each of the four managed nodes with the following configuration:

  • rhel8-server1 should be configured with a basic Postfix configuration to accept mail from the local subnet (which contains the other managed nodes).  

  • rhel8-server2, rhel7-server1, and rhel7-server2 should be configured as forward-only null clients, and should forward mail to rhel8-server1.  

I’ve already set up an Ansible service account on the five servers, named ansible, and have SSH key authentication set up so that the ansible account on controlnode can log in to each of the systems. In addition, the ansible service account has been configured with access to the root account via sudo on each host. 

I’ve also installed the rhel-system-roles and ansible packages on controlnode. For more information on these tasks, refer to the Introduction to RHEL System Roles post.  

In this environment, I’m using a RHEL 8 control node, but you can also use Ansible automation controller or Red Hat Satellite as your RHEL system roles control node. Ansible automation controller provides many advanced automation features and capabilities that are not available when using a RHEL control node. 

For more information on Ansible automation controller and its functionality, refer to this overview page.  For more information on using Satellite as your RHEL System Roles control node, refer to Automating host configuration with Red Hat Satellite and RHEL System Roles.

Defining the inventory file and role variables

From the controlnode system, the first step is to create a new directory structure:

[ansible@controlnode ~]$ mkdir -p postfix/group_vars

These directories will be used as follows:

  • The postfix directory will contain the playbook and the inventory file.

  • The postfix/group_vars file will contain variable files for inventory groups that will apply to hosts in the respective Ansible inventory groups.  

I need to define an Ansible inventory file to list and group the hosts that I want the postfix System Role to configure. I’ll create the inventory file at postfix/inventory.yml with the following content:

all:
  children:
    postfix_server:
      hosts:
        rhel8-server1.example.com:
    postfix_null_client:
      hosts:
        rhel8-server2.example.com:
        rhel7-server1.example.com:
        rhel7-server2.example.com:

This inventory defines two inventory groups:

  • postfix_server inventory group contains the rhel8-server1 host.

  • postfix_null_client inventory group contains the rhel8-server2, rhel7-server1 and rhel7-server2 hosts.

image If using Ansible automation controller as your control node, this Inventory can be imported into Red Hat Ansible Automation Platform via an SCM project (example GitHub or GitLab) or using the awx-manage Utility as specified in the documentation.

Next, I’ll define the role variables that will control the behavior of the postfix System Role when it runs. The README.md file for the postfix role, available at /usr/share/doc/rhel-system-roles/postfix/README.md, contains important information about the role including a list of available role variables and how to use them.  

I’ll create a file that will define variables for my managed node listed in the postfix_server inventory group by creating a file at postfix/group_vars/postfix_server.yml with the following content:

postfix_conf:
  mydomain: "example.com"
  myorigin: "$mydomain"
  myhostname: "{{ inventory_hostname }}"
  mydestination: "$myhostname, localhost.$mydomain"
  mynetworks: "192.168.0.0/24"
  inet_interfaces: "all"

This will cause the postfix role to configure the host in postfix_server inventory group (rhel8-server1) with a basic Postfix configuration that will accept connections from the 192.168.0.0/24 subnet, which is the network that contains all of the managed nodes.  

I’ll also create a file to define variables for my managed nodes listed in the postfix_null_client inventory group by creating a file at postfix/group_vars/postfix_null_client.yml with the following content:

postfix_conf:
  myhostname: "{{ inventory_hostname }}"
  myorigin: "$mydomain"
  relayhost: "rhel8-server1.example.com"
  inet_interfaces: "loopback-only"
  mydestination: ""

This will cause the postfix role to configure the hosts in the postfix_null_client inventory group (rhel8-server2, rhel7-server1, rhel7-server) as forward only null clients which will use rhel8-server1 as their relayhost.  

Creating the playbook

The next step is creating the playbook file at postfix/postfix.yml with the following content:

- name: Open firewall for smtp on postfix_server group
  hosts: postfix_server
  tasks:
    - firewalld:
        service: smtp
        permanent: yes
        immediate: yes
        state: enabled

- name: Run postfix role
  hosts: all
  roles:
    - rhel-system-roles.postfix

The first task, Open firewall for smtp on postfix_server group, will only be run on the rhel8-server1 host that is in the postfix_server inventory group, and this task will open the firewall for the smtp service. 

The second task, Run postfix role, will run on all four of the managed nodes, and will cause Postfix to be installed and configured on each host, utilizing the previously defined variables.

imageIf you are using Ansible automation controller as your control node, you can import this Ansible playbook into Red Hat Ansible Automation Platform by creating a Project, following the documentation provided here. It is very common to use Git repos to store Ansible playbooks. Ansible Automation Platform stores automation in units called Jobs which contain the playbook, credentials and inventory. Create a Job Template following the documentation here

Running the playbook

At this point, everything is in place, and I’m ready to run the playbook. For this demonstration, I’m using a RHEL control node and will run the playbook from the command line. I’ll use the cd command to move into the postfix directory, and then use the ansible-playbook command to run the playbook. 

[ansible@controlnode ~]$ cd postfix
[ansible@controlnode postfix]$ ansible-playbook postfix.yml -b -i inventory.yml

I specify that the postfix.yml playbook should be run, that it should escalate to root (the -b flag), and that the inventory.yml file should be used as my Ansible inventory (the -i flag). 

After the playbook completes, I verified that there were no failed tasks:

imageIf you are using Ansible automation controller as your control node, you can launch the job from the automation controller web interface. 

Validating the configuration

To validate the configuration, I’ll log in to each of the three forward-only null clients (rhel8-server2, rhel7-server1, rhel7-server2) and send an email to the brian@rhel8-server1.example.com email address.  I’ll then verify the emails were received by the brian account on the rhel8-server1.example.com host. 

I’ll start on rhel8-server2 by sending the email:

[root@rhel8-server2 ~]# mail brian@rhel8-server1.example.com
Subject: Test email from rhel8-server2
EOT 
Null message body; hope that's ok

Press Ctrl-d to send the test message. I’ll repeat this step on rhel7-server1 and rhel7-server2 to send emails from them as well.  

Next, I’ll login to rhel8-server1 as the brian account and verify the emails were received:

[brian@rhel8-server1 ~]$ mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/brian": 3 messages 3 new
>N  1 root                  Wed Nov 24 10:01  21/870   "Test email from rhel8-server2"
 N  2 root                  Wed Nov 24 10:03  21/861   "Test email from rhel7-server1"
 N  3 root                  Wed Nov 24 10:03  21/863   "Test email from rhel7-server2"
& 

Conclusion

The postfix RHEL System Role can help you quickly and consistently implement the Postfix MTA across your RHEL environment in an automated manner.  

We offer many RHEL System Roles that can help automate other important aspects of your RHEL environment. To explore additional roles, review the list of available RHEL System Roles and start managing your RHEL servers in a more efficient, consistent and automated manner today.


Sull'autore

Brian Smith is a Product Manager at Red Hat focused on RHEL automation and management.  He has been at Red Hat since 2018, previously working with Public Sector customers as a Technical Account Manager (TAM).  

Read full bio