Using Postfix DNS SRV record resolution feature

Photo by Scott Rodgerson on Unsplash (cropped)

In March 2011 Apple Inc. proposed RFC 6186 that describes how domain name system service (DNS SRV) records should be used for locating email submission and accessing services. The design presented in the RFC is now supported by Postfix since version 3.8.0. With the new functionality, you can now use DNS SRV records for load distribution and auto-configuration.

What does the DNS SRV record look like

The DNS SRV records were defined in RFC 2782 and are specified in zone files and contain the service name, transport protocol specification, priority, weight, port, and the host that provides the service.

_submission._tcp SRV 5 10 50 bruce.my-domain.com.

FieldValueMeaning
service namesubmissionservice is named submission
transport protocol specificationtcpservice is using TCP
priority5servers priority is 5 (lower gets tried first)
weight10portion of load the server should handle
port50port where server listens for connections
targetbruce.my-domain.com.name of server providing this service
Record explanation

Server selection algorithm

Clients should implement the resolution of SRV records as described in RFC 2782. That means, first contact the server with the highest priority (lowest priority field value). If the server does not respond, try to contact the next server with either the same or lower priority (higher priority field value). If there are multiple servers with the same priority, choose one randomly, but ensure the probability of choosing records conforms to the equation:

where i is the identification of SRV record and k is the count of SRV records with the same priority.

In practice, this means that if you have two servers and one is 3 times as powerful as the other one, then you should give the first weight a value 3 times higher than the other one. This ensures the more powerful server will receive ~75% of client requests and the other one ~25%.

These principles allow SRV records to work as tools to both autoconfigure clients and distribute the workload among servers.

Consider the following example of such a set of records:

_submission._tcp 	SRV 0 0 2525 server-one
_submission._tcp 	SRV 1 75 2625 server-two
_submission._tcp 	SRV 1 25 2625 server-three

Here server-one would always be contacted first. If server-one does not respond, the client will shuffle the two remaining records with priority 1, generate a random number from 0 to 100 and if the running sum of the first record is greater or equal, then try to contact it. Otherwise, the client contacts the servers in reverse order. Note that the client submits the request to the first server it successfully connects to.

Configuration example

Consider the following situation. You want to configure Postfix to relay outgoing emails through a company mail server by using SRV records for a large number of computers. To achieve this, you can configure the relayhost parameter in Postfix, which acts as a Mail User Agent (MUA) for each computer. If you set the value of the relayhost parameter to $mydomain, your machines start to look up MX records for your domain and attempt to submit mail in the order based on their priorities. While this approach works, you can encounter a problem with load balancing. Postfix uses the server with the highest priority until it becomes unresponsive and only then contacts any secondary servers. Additionally, if your environment uses dynamically assigned ports, you are not able to notify the clients what port is a particular server using. With SRV records, you can address these challenges and keep the servers running smoothly without peaks while changing the server’s port as needed.

Zone file

To configure a DNS server to provide information to clients, see the following example zone file with servers one, two and three configured as relays and server four for receiving test mail.

$TTL  3600
@  	IN SOA  example-domain.com. root.example-domain.com. (
                1571655122 ; Serial number of zone file
                1200       ; Refresh time
                180        ; Retry time in case of problem
                1209600    ; Expiry time
                10800 )    ; Maximum caching time in case of failed lookups
;
   	IN NS   ns1
   	IN A    192.168.2.0
;
ns1	IN A    192.168.2.2
server-one           IN A   192.168.2.4
server-two           IN A   192.168.2.5
server-three         IN A   192.168.2.6
server-four          IN A   192.168.2.7
_submission._tcp     SRV 0 0 2525  server-one
_submission._tcp     SRV 1 50 2625 server-two
_submission._tcp     SRV 1 50 2625 server-three
@ MX 0 server-four

Postfix MUA configuration

Configure client machines to look for SRV records:

use_srv_lookup = submission
relayhost = example-domain.com:submission

With this configuration, Postfix instances on your client machines contact the DNS server for the example-domain and request the SRV records for mail submission. In this example, server-one has the highest priority and Postfix tries it first. Postfix then randomly selects one of the two remaining servers to try. The configuration ensures that server one will be contacted first approximately 50% of the time. Note that the weight value in the SRV records does not correspond with the percentage. You can achieve the same goal with the values 1 and 1.

Postfix also has the information that server-one listens on port 2525 and server-two on port 2625. If you are caching retrieved DNS records and you change the SRV records dynamically, it is important to set a low time to live (TTL) for your records.

Complete setup

You can try this configuration with podman and compose file included here:

$ git clone https://github.com/TomasKorbar/srv_article
$ cd srv_article/environment
$ podman-compose up
$ podman exec -it article_client /bin/bash
root@client # ./senddummy.sh
root@client # exit

After completing the configuration steps, you can check the logs to monitor, that the mail passes server one and is delivered to server four.

$ podman stop article_server1
$ podman exec -it article_client /bin/bash
root@client # ./senddummy.sh
root@client # ./senddummy.sh
root@client # ./senddummy.sh
root@client # ./senddummy.sh
root@client # ./senddummy.sh
root@client # ./senddummy.sh
root@client # exit

Now that the first server is down, these six mails will be relayed by either server two or three.

Take a closer look at the Dockerfiles to understand the configuration more deeply.

Finish working with the example by executing: $ podman-compose down

For System Administrators

8 Comments

  1. Phoenix

    “That means, first contact the server with the lowest priority. If the server does not respond, try to contact the next server with either the same or lower priority.”

    From a logical point of view if you start at the lowest priority, you cannot get any lower.

    • Benjamin Menant

      @Phoenix I agree, this sentence is a little misleading. I think the author first refers to the lowest priority value (since the lower this value is, the greater the priority will be), and later refers to the lower priority rank (i.e. greater priority value).

      • Yes, that is exactly what i meant. I will try to update the misleading sentence as soon as possible. Thanks for pointing this out.

  2. Simple and self-contained example. Thank you very much. 🙂

  3. David

    I notice the most recent available version of Postfix, is 3.7.4, not 3.8.0. I’m on Fedora 38. Can anyone comment, please? Thanks.

    • That appears to be correct.

      https://koji.fedoraproject.org/koji/packageinfo?packageID=363

      It looks like Postfix 3.8.0 has been built for the Fedora Linux 39 (currently rawhide).

      “dnf update ‐‐releasever=rawhide postfix” might work to install the version built for rawhide on your Fedora Linux 38 system if you want to test it. I don’t have access to a Fedora 38 install to try it on, so I don’t know if that will work.

      Edit: Note that this forum corrupts the text in the comments with unicode characters, so copy-and-paste of the above command will not work. You’ll have to key it in manually.

    • Hi David,
      Yes that is indeed correct, Postfix in Fedora 38 is 3.7.4. Me and the maintainer of Postfix agreed that we will not do a rebase but backport the feature instead. So you should be able to use the feature also on Fedora 38.

      The update in question: https://bodhi.fedoraproject.org/updates/FEDORA-2023-6b2ae4d675

  4. betty09

    Simple and complete illustration. I sincerely appreciate it.

Comments are Closed

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat. Fedora Magazine aspires to publish all content under a Creative Commons license but may not be able to do so in all cases. You are responsible for ensuring that you have the necessary permission to reuse any work on this site. The Fedora logo is a trademark of Red Hat, Inc. Terms and Conditions