Server — Mail — MX and SPF

Posted on 10 2026

The Postfix article completed February’s mail stack at the application layer. The remaining work is in DNS. Without the right DNS records, inbound mail cannot find February, outbound mail will be rejected or marked as spam, and the reputation February builds as a sender is meaningless.

This article covers two records: MX, which tells the internet where to deliver mail for your domain, and SPF, which tells the internet which servers are authorised to send mail from your domain. Both go into PowerDNS via pdnsutil and, since DNSSEC is enabled on the zone, are automatically signed.

Before adding records

Confirm the zone exists in PowerDNS and DNSSEC is active:

sudo pdnsutil list-zone yourdomain.com
sudo pdnsutil zone check yourdomain.com

If the zone does not exist, create it following the PowerDNS article in this series. If DNSSEC is not enabled, enable it before adding mail records; it is much simpler to sign everything at once than to add signing later.

Also confirm February’s public IP address is what you expect:

curl -s ifconfig.me

The MX record will point to a hostname, and that hostname needs an A record pointing to this IP. If February does not have a stable public IP, the Fastmail relay article noted that a static IP is in use. Confirm this before proceeding.

The A record for the mail hostname

MX records point to hostnames, not IP addresses directly. The hostname needs an A record. The convention is mail.yourdomain.com as the mail exchanger hostname.

sudo pdnsutil add-record yourdomain.com mail A 3600 "your.public.ip.address"

Confirm it resolves:

dig mail.yourdomain.com @127.0.0.1

The response should return February’s public IP. If you are using PowerDNS only for internal DNS and your domain’s public DNS is managed elsewhere (at a registrar or external provider), this A record needs to be added there instead. The MX record setup is the same regardless of where the DNS is hosted.

The MX record

The MX record specifies which server accepts inbound mail for the domain. It has a priority value: lower numbers are preferred. With a single mail server, the priority is arbitrary; 10 is conventional.

sudo pdnsutil add-record yourdomain.com @ MX 3600 "10 mail.yourdomain.com."

The trailing dot on mail.yourdomain.com. indicates a fully-qualified domain name. Without it, PowerDNS may append the zone name, producing mail.yourdomain.com.yourdomain.com which is incorrect. Always include the trailing dot in MX record values.

The @ symbol represents the zone apex, meaning the record applies to yourdomain.com itself, not a subdomain.

Rectify the zone after adding records to update DNSSEC signatures:

sudo pdnsutil zone rectify yourdomain.com

Verify the MX record:

dig MX yourdomain.com @127.0.0.1

The response should show:

;; ANSWER SECTION:
yourdomain.com.    3600    IN    MX    10 mail.yourdomain.com.

With DNSSEC enabled, the ad flag should be present in the flags section confirming the record is signed and validated.

For multiple domains

Every domain listed in /etc/postfix/virtual_domains needs its own MX record. The MX records for all domains can point to the same mail.yourdomain.com hostname. Repeat the add-record command for each domain:

sudo pdnsutil add-record seconddomain.com @ MX 3600 "10 mail.yourdomain.com."
sudo pdnsutil zone rectify seconddomain.com

Reverse DNS

MX records tell the world where to send mail. Reverse DNS (PTR records) tell the world what February’s IP address is called. Most mail servers check PTR records when deciding whether to accept mail, and many will reject or heavily penalise mail from servers without a matching PTR record.

PTR records for a public IP address are managed by the IP’s owner, which is your ISP or hosting provider, not by February’s PowerDNS. Contact your provider and request that the PTR record for February’s IP be set to mail.yourdomain.com.

Confirm the PTR record once it is set:

dig -x your.public.ip.address

The response should show mail.yourdomain.com in the answer section. The PTR record must match the hostname in the MX record exactly. A mismatch is a common cause of mail being rejected or flagged as suspicious.

SPF

SPF, Sender Policy Framework, is a DNS TXT record that lists the servers authorised to send mail from your domain. When a receiving server gets mail claiming to be from yourdomain.com, it looks up the SPF record and checks whether the sending server’s IP is on the authorised list. A message from an unauthorised server fails SPF, which contributes to spam scoring or rejection depending on the receiving server’s policy.

What to include

February’s SPF record needs to authorise two things:

February’s own IP address for any mail sent directly from Postfix. Even though most outbound mail goes through Fastmail, system-generated mail that bypasses the relay (which should be minimal) comes from February’s IP.

Fastmail’s sending infrastructure for all mail relayed through Fastmail. Fastmail publishes its authorised sending IPs via a mechanism called an SPF include. The include record to use is include:spf.messagingengine.com. This tells receiving servers to also check Fastmail’s published list of authorised senders.

The record

sudo pdnsutil add-record yourdomain.com @ TXT 3600   "v=spf1 ip4:your.public.ip.address include:spf.messagingengine.com ~all"

Breaking down the record content:

v=spf1                          SPF version
ip4:your.public.ip.address      Authorise February's public IP directly
include:spf.messagingengine.com Authorise Fastmail's sending IPs
~all                            Softfail for anything else

The final ~all mechanism is the policy for mail from unauthorised sources. ~all (softfail) marks such mail as suspicious but does not instruct the receiving server to reject it. -all (hardfail) instructs rejection. +all authorises everything, which is never the right choice.

Starting with ~all is the safer approach while the mail setup is new. Once the configuration is verified to be correct and there are no legitimate sending sources that are being missed, switching to -all provides stronger protection against spoofing.

Rectify the zone:

sudo pdnsutil zone rectify yourdomain.com

Verify the SPF record:

dig TXT yourdomain.com @127.0.0.1

The response should include the SPF record in the answer section.

Testing SPF

Check that the record parses correctly

SPF records have a lookup limit of ten DNS lookups during evaluation. Each include: mechanism counts as one lookup, and any nested lookups within the included record also count. Exceeding ten lookups causes SPF evaluation to fail with a permerror, which is treated as a failed check by many receiving servers.

Fastmail’s include:spf.messagingengine.com uses a small number of lookups internally. For February’s simple setup with one direct IP and one include, the total is well within the limit. If additional relay services are ever added, check the cumulative lookup count before publishing.

Check the record using an online SPF checker such as MXToolbox’s SPF lookup tool, or from the command line using pyspf if installed. The key things to verify: the record parses without errors, February’s IP is authorised, and Fastmail’s IP range is included.

Send a test message and check the headers

Send a message from February to a Gmail address. In Gmail, view the original message (the three-dot menu on the message, then Show original). The authentication results section should show:

spf=pass (google.com: domain of you@yourdomain.com designates X.X.X.X as permitted sender)

An spf=pass result confirms the SPF record is correct and the sending IP is authorised. An spf=softfail result means the sending IP is not in the authorised list, which usually means either the record is not yet propagated, or a sending path was missed in the record.

One record per domain

Like MX records, SPF records apply per domain. Each domain in virtual_domains that sends mail needs its own SPF record. If seconddomain.com only receives mail and never sends it, an SPF record of v=spf1 -all (authorising no senders) is appropriate. If it also sends mail through Fastmail, it needs the same SPF record as the primary domain.

# Domain that sends via Fastmail
sudo pdnsutil add-record seconddomain.com @ TXT 3600   "v=spf1 ip4:your.public.ip.address include:spf.messagingengine.com ~all"

# Receive-only domain
sudo pdnsutil add-record receiveonly.com @ TXT 3600   "v=spf1 -all"

What is still missing

With MX and SPF in place, inbound mail can find February, and outbound mail from February or Fastmail will pass SPF checks. Two more authentication mechanisms are still needed before the mail setup is complete:

DKIM cryptographically signs outbound mail. Without DKIM, some receiving servers will score mail from new senders more harshly, and DMARC cannot be configured meaningfully. The next article covers DKIM.

DMARC tells receiving servers what to do when mail fails SPF or DKIM. It also provides reporting, which is how you find out whether any mail is being sent from your domain by unauthorised sources. The article after DKIM covers DMARC.

Until both are in place, do not send high-volume mail or mail to strict providers. The MX and SPF records are enough to establish basic mail flow, but the full authentication chain requires all three.