Skip to main content
Published on September 24, 2026 Since February 2024, Gmail has required every sender to its personal accounts to authenticate with SPF or DKIM, to have valid forward and reverse DNS for the sending address, and to use TLS. Above 5,000 messages a day, it takes SPF and DKIM, plus DMARC. Yahoo published rules along the same lines. Since November 2025, Google no longer just files non-compliant mail as spam: it applies temporary and permanent rejections. A mail server on a VPS is no exception. Here are the four records that make the difference, in the order to set them, and how to check each one.

What the receiving server checks

The examples below use example.com, the server mail.example.com and the address 203.0.113.42. Substitute your own.

0. First: outbound port 25

None of this matters if your server cannot reach anyone else. Many providers block outbound port 25 by default. We do: outbound ports 25, 465 and 587 are closed on every new VPS, and open on request for reasonable use (a personal mail server, application notifications), never for bulk sending. The details are in the network documentation. Test from the VPS:

1. Hostname, A record and reverse DNS

Three values must agree: the name your server announces in its HELO, the A record for that name, and the reverse DNS (PTR) of the IP address.
If it is wrong, fix it:
On the DNS side you need an A for mail.example.com pointing to 203.0.113.42, and the domain’s MX pointing to mail.example.com. The reverse DNS does not live in your zone: the IP belongs to your provider, and only they can set it. With us, it is set from the console; the steps are in the Reverse DNS documentation.
If we host your domain’s DNS zone, the Domain tab on your instance, profile A website and email, writes the mail A record, the MX (priority 10 to mail.example.com), the SPF and DMARC records described below, and sets the IP’s reverse DNS. A preview shows everything before it is written, including your current MX records if they are about to be replaced. See the announcement and the documentation. Only DKIM is left to you: section 3.
Check that forward and reverse agree:

2. SPF: who may send

A single TXT record at the root of the domain. For a server that is both the website and the mail server:
a authorises the address in example.com’s A record, mx those of the MX hosts, and -all states that nothing else sends for this domain. This is the record the console’s email profile writes. If another service also sends on your behalf (hosted mailbox, newsletter tool), add its include: mechanism to the same record, not a second one.
SPF checks the envelope address (MAIL FROM), not the From: header your recipient reads. DMARC, section 4, is what ties the two together.

3. DKIM: sign what leaves

DKIM is the one of the four the console cannot write for you: the private key is generated on your server and must never leave it. You only publish the public key. On Debian or Ubuntu with Postfix, OpenDKIM does the job:
This produces s2026.private (the private key) and s2026.txt (the DNS record to publish). The selector is any name you like; putting the year in it makes rotation easier later. In /etc/opendkim.conf, set the domain, selector and key, and replace the existing Socket line with a local port, which Postfix can reach even from its chroot:
Then plug Postfix into the milter:
Publish the contents of s2026.txt as a TXT record on s2026._domainkey.example.com:
A 2048-bit key exceeds the 255 characters a single TXT string allows, so the file splits it into several quoted strings. Together they form one record, not several. Once published, check that it comes back whole and matches the private key:
A key not secure line before it only means the zone is not DNSSEC-signed. It does not stop DKIM from working.

4. DMARC: tie it together and say what to do on failure

DMARC requires the domain in the From: header to align with the one that passed SPF or DKIM, publishes what the receiver should do otherwise, and says where to send you reports.
  • p=quarantine: a failing message goes to spam. p=none asks for nothing; p=reject has it refused.
  • rua=: the address that receives daily aggregate reports (compressed XML) from the large providers. That mailbox must exist.
This is the record the console’s email profile sets. It assumes everything sending as you already passes SPF or DKIM. If other services send for your domain and you are not sure of them, start with p=none, read the reports for a week or two, then move up.

5. Check end to end

The records can be right and the message still fail. Send a real message to a Gmail address, through your own Postfix so it gets signed:
In Gmail, open the message, the menu, Show original. You should see PASS on all three lines: SPF, DKIM and DMARC. The detail is in the Authentication-Results header:
On the server, OpenDKIM’s log confirms the signature:

Common pitfalls

Two SPF records. A domain must carry exactly one. With two TXT records starting with v=spf1, the result is a permanent error and SPF fails for everyone. Merge them. More than ten DNS lookups. Every include, a, mx, ptr, exists and redirect costs one query, and nested includes count too. Past ten, SPF returns a permanent error. Three or four third-party services are enough to get there. -all or ~all. -all (fail) says nothing else sends; ~all (softfail) says it without insisting. Some receivers reject on an SPF fail before even evaluating DKIM, which penalises forwarded mail. If your domain’s messages are often forwarded, ~all with DKIM and DMARC in place is a common compromise. DMARC at p=none forever. p=none is for watching. It meets the letter of the requirements but does nothing to stop someone spoofing your domain. Set yourself a date to move to quarantine. Reverse DNS and HELO that disagree. A generic provider PTR, a PTR pointing to a name with no matching A record, or a myhostname left at localhost or the install-time name: any one of them is enough to make the receiver suspicious. Forgotten IPv6. If your VPS has an IPv6 address, Postfix will happily use it to reach Gmail, and that address then needs its own PTR and must be covered by SPF (the a mechanism includes the domain’s AAAA records). Check with dig -x on the IPv6 address. Failing that, tell Postfix to prefer IPv4:
The mail host with no SPF. Receivers may also check SPF against the name announced in HELO. A TXT record "v=spf1 a -all" on mail.example.com covers it.

Going further

Need port 25 opened, or a hand with the setup? Our team is available from your client area.