This draft comes from a real send-only mail setup note. I cleaned it up heavily before putting it here because the original working log included real domains, DNS values, and implementation details that should never be published as-is.

The core lesson, though, is highly reusable: if a server only sends mail and does not receive it, you still need to treat deliverability seriously. Without SPF and DKIM, send-only mail is much more likely to be flagged, filtered, or sent straight to spam.

The Goal

The goal was to improve the reputation and authenticity of outgoing mail from a send-only server by doing three things well:

  • publish a valid SPF record
  • configure OpenDKIM to sign outbound mail
  • wire Postfix to the DKIM milter correctly

Why This Matters

Plenty of infrastructure sends mail without being a full mail server:

  • application alerts
  • contact form relays
  • system notifications
  • backup and cron reports

Even in those cases, receiving systems still judge the messages. If you skip the basics, deliverability suffers.

1. Start with SPF

A representative SPF record for a send-only server looks like this:

1
v=spf1 ip4:203.0.113.10 include:mail-provider.example ~all

The exact content depends on who is allowed to send for the domain. The important thing is that the sending IPs and providers are explicitly represented.

2. Install OpenDKIM

On a Debian or Ubuntu host:

1
2
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt install -y opendkim opendkim-tools

3. Wire Postfix to OpenDKIM

In the original note, I also stripped the X-Originating-IP header and connected Postfix to the local milter socket:

1
2
3
4
5
6
printf '/^X-Originating-IP:/ IGNORE\n' | sudo tee /etc/postfix/smtp_header_checks
sudo postconf -e 'smtp_header_checks = regexp:/etc/postfix/smtp_header_checks'
sudo postconf -e 'milter_default_action = accept'
sudo postconf -e 'milter_protocol = 6'
sudo postconf -e 'smtpd_milters = local:/var/spool/postfix/opendkim/opendkim.sock'
sudo postconf -e 'non_smtpd_milters = $smtpd_milters'

4. Prepare OpenDKIM Directories

1
2
sudo install -d -o opendkim -g opendkim -m 0750 /etc/opendkim/keys
sudo install -d -o opendkim -g postfix -m 0750 /var/spool/postfix/opendkim

5. Create a Minimal OpenDKIM Config

Example /etc/opendkim.conf:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Syslog yes
UMask 002
Canonicalization relaxed/simple
Mode sv
OversignHeaders From
UserID opendkim
PidFile /run/opendkim/opendkim.pid
Socket local:/var/spool/postfix/opendkim/opendkim.sock
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts

Trusted hosts example:

1
2
3
4
5
127.0.0.1
localhost
::1
mailhost.example.com
203.0.113.10

6. Map Domains to Signing Keys

If the server sends for multiple domains, keep the mapping explicit.

/etc/opendkim/SigningTable

1
2
3
*@example.com example.com
*@example.net example.net
*@example.org example.org

/etc/opendkim/KeyTable

1
2
3
example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private
example.net example.net:mail:/etc/opendkim/keys/example.net/mail.private
example.org example.org:mail:/etc/opendkim/keys/example.org/mail.private

7. Generate DKIM Keys

For each domain:

1
2
3
4
5
sudo mkdir -p /etc/opendkim/keys/example.com
sudo opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s mail -v
sudo chown -R opendkim:opendkim /etc/opendkim/keys/example.com
sudo chmod 700 /etc/opendkim/keys/example.com
sudo chmod 600 /etc/opendkim/keys/example.com/mail.private

That generates:

  • mail.private for the server
  • mail.txt for DNS publication

8. Publish the DNS Record

The selector typically looks like:

1
mail._domainkey

The published record itself will resemble:

1
mail._domainkey.example.com IN TXT "v=DKIM1; h=sha256; k=rsa; p=<public-key>"

9. Restart and Verify

1
2
3
4
5
sudo postfix check
sudo systemctl restart opendkim postfix
sudo systemctl enable opendkim postfix

sudo opendkim-testkey -d example.com -s mail -k /etc/opendkim/keys/example.com/mail.private -vvv

Then send a test mail:

1
2
3
4
5
6
7
sendmail -f [email protected] [email protected] <<'EOF'
Subject: DKIM test
From: [email protected]
To: [email protected]

DKIM test body
EOF

When reviewing the raw message, I want to see:

  • a DKIM-Signature header
  • DKIM: PASS
  • ideally SPF: PASS
  • ideally DMARC: PASS

One Important Postfix Note

For send-only hosts, I do not treat all sending domains as local receiving domains. mydestination should stay limited to the host’s actual local identity unless the server is also meant to receive mail for those domains.

That distinction matters because send-only mail is simpler and safer when you avoid pretending the box is also a full inbound mail server.

What This Note Shows

This is the kind of systems work that often looks small from the outside. But when mail is part of business operations, deliverability is infrastructure, not decoration.

A send-only host still needs:

  • correct DNS
  • correct signing
  • correct Postfix wiring
  • correct verification after deployment

Closing Thought

I keep notes like this because mail problems are easy to underestimate until they quietly affect alerts, onboarding messages, resets, receipts, or system notifications. Once rewritten and sanitized, a note like this becomes a good reusable checklist for any future send-only host.