Latest News:   Nov 2025, HelionMind and CyberXNetworks began a strategic cooperation to develop the first true AI-powered Cyber Security Assistant.
πŸ’¬
βœ–

OpenDKIM Setup Guide for Sendmail on Rocky Linux 9

Configure Sendmail with OpenDKIM and use a separate DKIM key for each email domain.

Scope: This guide describes a multi-domain OpenDKIM configuration for Sendmail on Rocky Linux 9. Each domain has its own private/public DKIM key pair.

1 Install OpenDKIM

Enable EPEL and install OpenDKIM and its utilities:

dnf install epel-release -y
dnf install opendkim opendkim-tools -y

Verify the installation:

rpm -qa | grep opendkim

2 Create the DKIM Key Directories

Create a separate directory for every domain that will send email. For example:

mkdir -p /etc/opendkim/keys/cylinux.com
mkdir -p /etc/opendkim/keys/example.com
mkdir -p /etc/opendkim/keys/example.net

The resulting structure should look like:

/etc/opendkim/keys/
β”œβ”€β”€ cylinux.com/
β”œβ”€β”€ example.com/
└── example.net/

3 Generate a DKIM Key for Each Domain

Generate a separate 2048-bit RSA key pair for each domain. The selector used in this example is mail2026.

cylinux.com

opendkim-genkey -b 2048 -d cylinux.com -D /etc/opendkim/keys/cylinux.com -s mail2026

example.com

opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s mail2026

example.net

opendkim-genkey -b 2048 -d example.net -D /etc/opendkim/keys/example.net -s mail2026

Each command creates two files:

mail2026.private mail2026.txt
Important: The private key must remain on the mail server and must never be published in DNS. The mail2026.txt file contains the public key that will be published in DNS.

4 Configure the KeyTable

Edit:

vi /etc/opendkim/KeyTable

Add one entry for every domain:

mail2026._domainkey.cylinux.com cylinux.com:mail2026:/etc/opendkim/keys/cylinux.com/mail2026.private
mail2026._domainkey.example.com example.com:mail2026:/etc/opendkim/keys/example.com/mail2026.private
mail2026._domainkey.example.net example.net:mail2026:/etc/opendkim/keys/example.net/mail2026.private

The format is:

KEY-NAME DOMAIN:SELECTOR:PRIVATE-KEY

This configuration tells OpenDKIM which private key must be used for each domain.

5 Configure the SigningTable

Edit:

vi /etc/opendkim/SigningTable

Add:

*@cylinux.com mail2026._domainkey.cylinux.com
*@example.com mail2026._domainkey.example.com
*@example.net mail2026._domainkey.example.net

This determines which DKIM key is used according to the sender's domain.

6 Configure OpenDKIM

Edit:

vi /etc/opendkim.conf

Make sure the following settings are present:

Mode sv
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts

Mode sv enables both DKIM signing and verification.

Important: If an older single-domain configuration contains directives such as KeyFile, Selector, or Domain, review them carefully. They may conflict with the multi-domain KeyTable/SigningTable configuration.

7 Configure TrustedHosts

Edit:

vi /etc/opendkim/TrustedHosts

At minimum, include:

127.0.0.1
localhost

If mail is submitted from a trusted internal network, the appropriate internal subnet can also be added. For example:

192.168.1.0/24
Security note: Do not add arbitrary public IP ranges to TrustedHosts. Only trusted systems that are permitted to submit mail through your server should be included.

8 Set File Permissions

OpenDKIM needs permission to read the private keys, while the private keys themselves should be protected from other users.

chown -R opendkim:opendkim /etc/opendkim/keys
chmod 700 /etc/opendkim/keys
find /etc/opendkim/keys -type d -exec chmod 750 {} \;
find /etc/opendkim/keys -name "*.private" -exec chmod 600 {} \;
find /etc/opendkim/keys -name "*.txt" -exec chmod 644 {} \;

Verify:

ls -lR /etc/opendkim/keys

9 Publish the DKIM Public Keys in DNS

Display the generated public key for a domain:

cat /etc/opendkim/keys/cylinux.com/mail2026.txt

The output will contain a TXT record similar to:

mail2026._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A..." )

Create a DNS TXT record for:

mail2026._domainkey.cylinux.com
Example TXT value (one line): "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCA234234234kjshdfljkhler84rlhfklsjdfhldkfhgsldkfghsldfgh5hkhgdklfjghdkjfghIdeQMA7DZS71rkpTXEr/oz9Cd6pFNQhGEvRyBSbQjTO0vdHqVH4vF5iLeBDehXIVE74W+E/TmnvxFxOmbNdHGcluj4+cMRVy0kdDBoLZhqgGyc79eUqAek7eG9XkkZ6M4TP5zq1Rd07e+b7i//AXnBAYygfOwH1IP3LEetrpot+DjfcSmFpivKzjin2wU2wvu7a8Lk1SmaGR8Q7/H974jjxLbxShEhppU9AL/SMkUl8WjNrJYZj01s8bVTmaKVTQviPHRRMnKzshrC/m0G4495hnviUY0Cwk2GXe9RQIDAQAB"

Repeat the process for every domain:

mail2026._domainkey.example.com
mail2026._domainkey.example.net
DNS record: The public DKIM key belongs in DNS. Never publish the contents of a .private file.

10 Verify the DNS Record

Use:

dig TXT mail2026._domainkey.cylinux.com

or:

nslookup -type=TXT mail2026._domainkey.cylinux.com

The response should contain a value beginning with:

v=DKIM1; k=rsa; p=...

11 Test the DKIM Key

Before connecting OpenDKIM to Sendmail, test the DNS record and private key:

opendkim-testkey -d cylinux.com -s mail2026 -vvv

A successful test should report:

key OK

Repeat for the other domains:

opendkim-testkey -d example.com -s mail2026 -vvv
opendkim-testkey -d example.net -s mail2026 -vvv

12 Connect OpenDKIM to Sendmail

Edit:

vi /etc/mail/sendmail.mc

Add the OpenDKIM milter configuration:

INPUT_MAIL_FILTER(`opendkim', `S=local:/run/opendkim/opendkim.sock')

This tells Sendmail to pass outgoing messages through the OpenDKIM milter local socket.

13 Rebuild Sendmail Configuration

Rebuild the Sendmail configuration:

cd /etc/mail make

Alternatively, the configuration can be generated directly with:

m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf

14 Start and Enable OpenDKIM

systemctl enable --now opendkim
systemctl restart sendmail

Check the services:

systemctl status opendkim
systemctl status sendmail

15 Send a Test Email

Send an email using one of your configured domains:

echo "DKIM test from cylinux.com" | mail -s "DKIM TEST" recipient@example.com

Inspect the headers of the received message. You should see a header similar to:

DKIM-Signature: v=1; a=rsa-sha256; d=cylinux.com; s=mail2026; ...

For an email sent from another configured domain, the d= and s= values should correspond to that domain and selector.

Multi-Domain Configuration

Domain Selector Private Key DNS Record
cylinux.com mail2026 /etc/opendkim/keys/cylinux.com/mail2026.private mail2026._domainkey.cylinux.com
example.com mail2026 /etc/opendkim/keys/example.com/mail2026.private mail2026._domainkey.example.com
example.net mail2026 /etc/opendkim/keys/example.net/mail2026.private mail2026._domainkey.example.net

Using the same selector name for different domains is acceptable because the selector is evaluated within the domain. Each domain should still have its own key pair.

DKIM Key Rotation

DKIM keys do not have a built-in expiration date. Nevertheless, periodic key rotation is recommended as a security practice.

For example, a future selector can be introduced:

mail2027._domainkey.cylinux.com

The general rotation process is:

  1. Generate a new key pair with a new selector.
  2. Publish the new public key in DNS.
  3. Change OpenDKIM to use the new selector.
  4. Keep the old public key in DNS temporarily.
  5. Remove the old DNS record after the transition period.
Do not remove the old DNS key immediately. Messages signed using the old selector may still need the old public key for verification.

Important: DKIM DNS Record vs. DKIM Signing

A DKIM TXT record in DNS does not force a mail server to sign messages. It only publishes the public key used to verify messages signed with that selector.

If OpenDKIM is temporarily unavailable, outgoing mail may be sent without a DKIM-Signature header. Whether that affects delivery depends on the receiving system and the domain's SPF and DMARC configuration.

Check DMARC carefully. If your domain uses a strict DMARC policy such as p=reject, ensure that SPF and/or DKIM authentication and alignment are working correctly before relying on the configuration in production.

Recommended Final Configuration

A clean multi-domain installation should have a structure similar to:

/etc/opendkim/
β”œβ”€β”€ opendkim.conf
β”œβ”€β”€ KeyTable
β”œβ”€β”€ SigningTable
β”œβ”€β”€ TrustedHosts
└── keys/
  β”œβ”€β”€ cylinux.com/
  β”‚ └── mail2026.private
  β”œβ”€β”€ example.com/
  β”‚ └── mail2026.private
  β””── example.net/
   β””── mail2026.private
Configuration checklist:
  • OpenDKIM installed and running.
  • Separate 2048-bit key generated for each domain.
  • Private keys protected and stored locally.
  • Public keys published in DNS.
  • KeyTable correctly maps domains to private keys.
  • SigningTable correctly maps sender domains to selectors.
  • Sendmail connected to the OpenDKIM milter.
  • DNS records verified with dig.
  • Keys verified with opendkim-testkey.
  • Test email contains a valid DKIM-Signature.
  • Final message passes DKIM, SPF and DMARC checks.

OpenDKIM Setup Guide for Sendmail on Rocky Linux 9

Configure Sendmail with OpenDKIM and use a separate DKIM key for each email domain.

Scope: This guide describes a multi-domain OpenDKIM configuration for Sendmail on Rocky Linux 9. Each domain has its own private/public DKIM key pair.

1 Install OpenDKIM

Enable EPEL and install OpenDKIM and its utilities:

dnf install epel-release -y
dnf install opendkim opendkim-tools -y

Verify the installation:

rpm -qa | grep opendkim

2 Create the DKIM Key Directories

Create a separate directory for every domain that will send email. For example:

mkdir -p /etc/opendkim/keys/cylinux.com
mkdir -p /etc/opendkim/keys/example.com
mkdir -p /etc/opendkim/keys/example.net

The resulting structure should look like:

/etc/opendkim/keys/
β”œβ”€β”€ cylinux.com/
β”œβ”€β”€ example.com/
└── example.net/

3 Generate a DKIM Key for Each Domain

Generate a separate 2048-bit RSA key pair for each domain. The selector used in this example is mail2026.

cylinux.com

opendkim-genkey -b 2048 -d cylinux.com -D /etc/opendkim/keys/cylinux.com -s mail2026

example.com

opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s mail2026

example.net

opendkim-genkey -b 2048 -d example.net -D /etc/opendkim/keys/example.net -s mail2026

Each command creates two files:

mail2026.private mail2026.txt
Important: The private key must remain on the mail server and must never be published in DNS. The mail2026.txt file contains the public key that will be published in DNS.

4 Configure the KeyTable

Edit:

vi /etc/opendkim/KeyTable

Add one entry for every domain:

mail2026._domainkey.cylinux.com cylinux.com:mail2026:/etc/opendkim/keys/cylinux.com/mail2026.private
mail2026._domainkey.example.com example.com:mail2026:/etc/opendkim/keys/example.com/mail2026.private
mail2026._domainkey.example.net example.net:mail2026:/etc/opendkim/keys/example.net/mail2026.private

The format is:

KEY-NAME DOMAIN:SELECTOR:PRIVATE-KEY

This configuration tells OpenDKIM which private key must be used for each domain.

5 Configure the SigningTable

Edit:

vi /etc/opendkim/SigningTable

Add:

*@cylinux.com mail2026._domainkey.cylinux.com
*@example.com mail2026._domainkey.example.com
*@example.net mail2026._domainkey.example.net

This determines which DKIM key is used according to the sender's domain.

6 Configure OpenDKIM

Edit:

vi /etc/opendkim.conf

Make sure the following settings are present:

Mode sv
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts

Mode sv enables both DKIM signing and verification.

Important: If an older single-domain configuration contains directives such as KeyFile, Selector, or Domain, review them carefully. They may conflict with the multi-domain KeyTable/SigningTable configuration.

7 Configure TrustedHosts

Edit:

vi /etc/opendkim/TrustedHosts

At minimum, include:

127.0.0.1
localhost

If mail is submitted from a trusted internal network, the appropriate internal subnet can also be added. For example:

192.168.1.0/24
Security note: Do not add arbitrary public IP ranges to TrustedHosts. Only trusted systems that are permitted to submit mail through your server should be included.

8 Set File Permissions

OpenDKIM needs permission to read the private keys, while the private keys themselves should be protected from other users.

chown -R opendkim:opendkim /etc/opendkim/keys
chmod 700 /etc/opendkim/keys
find /etc/opendkim/keys -type d -exec chmod 750 {} \;
find /etc/opendkim/keys -name "*.private" -exec chmod 600 {} \;
find /etc/opendkim/keys -name "*.txt" -exec chmod 644 {} \;

Verify:

ls -lR /etc/opendkim/keys

9 Publish the DKIM Public Keys in DNS

Display the generated public key for a domain:

cat /etc/opendkim/keys/cylinux.com/mail2026.txt

The output will contain a TXT record similar to:

mail2026._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A..." )

Create a DNS TXT record for:

mail2026._domainkey.cylinux.com
Example TXT value (one line): "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCA234234234kjshdfljkhler84rlhfklsjdfhldkfhgsldkfghsldfgh5hkhgdklfjghdkjfghIdeQMA7DZS71rkpTXEr/oz9Cd6pFNQhGEvRyBSbQjTO0vdHqVH4vF5iLeBDehXIVE74W+E/TmnvxFxOmbNdHGcluj4+cMRVy0kdDBoLZhqgGyc79eUqAek7eG9XkkZ6M4TP5zq1Rd07e+b7i//AXnBAYygfOwH1IP3LEetrpot+DjfcSmFpivKzjin2wU2wvu7a8Lk1SmaGR8Q7/H974jjxLbxShEhppU9AL/SMkUl8WjNrJYZj01s8bVTmaKVTQviPHRRMnKzshrC/m0G4495hnviUY0Cwk2GXe9RQIDAQAB"

Repeat the process for every domain:

mail2026._domainkey.example.com
mail2026._domainkey.example.net
DNS record: The public DKIM key belongs in DNS. Never publish the contents of a .private file.

10 Verify the DNS Record

Use:

dig TXT mail2026._domainkey.cylinux.com

or:

nslookup -type=TXT mail2026._domainkey.cylinux.com

The response should contain a value beginning with:

v=DKIM1; k=rsa; p=...

11 Test the DKIM Key

Before connecting OpenDKIM to Sendmail, test the DNS record and private key:

opendkim-testkey -d cylinux.com -s mail2026 -vvv

A successful test should report:

key OK

Repeat for the other domains:

opendkim-testkey -d example.com -s mail2026 -vvv
opendkim-testkey -d example.net -s mail2026 -vvv

12 Connect OpenDKIM to Sendmail

Edit:

vi /etc/mail/sendmail.mc

Add the OpenDKIM milter configuration:

INPUT_MAIL_FILTER(`opendkim', `S=local:/run/opendkim/opendkim.sock')

This tells Sendmail to pass outgoing messages through the OpenDKIM milter local socket.

13 Rebuild Sendmail Configuration

Rebuild the Sendmail configuration:

cd /etc/mail make

Alternatively, the configuration can be generated directly with:

m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf

14 Start and Enable OpenDKIM

systemctl enable --now opendkim
systemctl restart sendmail

Check the services:

systemctl status opendkim
systemctl status sendmail

15 Send a Test Email

Send an email using one of your configured domains:

echo "DKIM test from cylinux.com" | mail -s "DKIM TEST" recipient@example.com

Inspect the headers of the received message. You should see a header similar to:

DKIM-Signature: v=1; a=rsa-sha256; d=cylinux.com; s=mail2026; ...

For an email sent from another configured domain, the d= and s= values should correspond to that domain and selector.

Multi-Domain Configuration

Domain Selector Private Key DNS Record
cylinux.com mail2026 /etc/opendkim/keys/cylinux.com/mail2026.private mail2026._domainkey.cylinux.com
example.com mail2026 /etc/opendkim/keys/example.com/mail2026.private mail2026._domainkey.example.com
example.net mail2026 /etc/opendkim/keys/example.net/mail2026.private mail2026._domainkey.example.net

Using the same selector name for different domains is acceptable because the selector is evaluated within the domain. Each domain should still have its own key pair.

DKIM Key Rotation

DKIM keys do not have a built-in expiration date. Nevertheless, periodic key rotation is recommended as a security practice.

For example, a future selector can be introduced:

mail2027._domainkey.cylinux.com

The general rotation process is:

  1. Generate a new key pair with a new selector.
  2. Publish the new public key in DNS.
  3. Change OpenDKIM to use the new selector.
  4. Keep the old public key in DNS temporarily.
  5. Remove the old DNS record after the transition period.
Do not remove the old DNS key immediately. Messages signed using the old selector may still need the old public key for verification.

Important: DKIM DNS Record vs. DKIM Signing

A DKIM TXT record in DNS does not force a mail server to sign messages. It only publishes the public key used to verify messages signed with that selector.

If OpenDKIM is temporarily unavailable, outgoing mail may be sent without a DKIM-Signature header. Whether that affects delivery depends on the receiving system and the domain's SPF and DMARC configuration.

Check DMARC carefully. If your domain uses a strict DMARC policy such as p=reject, ensure that SPF and/or DKIM authentication and alignment are working correctly before relying on the configuration in production.

Recommended Final Configuration

A clean multi-domain installation should have a structure similar to:

/etc/opendkim/
β”œβ”€β”€ opendkim.conf
β”œβ”€β”€ KeyTable
β”œβ”€β”€ SigningTable
β”œβ”€β”€ TrustedHosts
└── keys/
  β”œβ”€β”€ cylinux.com/
  β”‚ └── mail2026.private
  β”œβ”€β”€ example.com/
  β”‚ └── mail2026.private
  β””── example.net/
   β””── mail2026.private
Configuration checklist:
  • OpenDKIM installed and running.
  • Separate 2048-bit key generated for each domain.
  • Private keys protected and stored locally.
  • Public keys published in DNS.
  • KeyTable correctly maps domains to private keys.
  • SigningTable correctly maps sender domains to selectors.
  • Sendmail connected to the OpenDKIM milter.
  • DNS records verified with dig.
  • Keys verified with opendkim-testkey.
  • Test email contains a valid DKIM-Signature.
  • Final message passes DKIM, SPF and DMARC checks.