# Emails going to spam? Fix SPF, DKIM and DMARC step by step

> Emails going to spam usually means missing SPF, DKIM or DMARC, bad reverse DNS or a blocklisted IP. Check and fix each one, with dig commands and Gmail's rules.

Source: https://zopanel.net/blog/email-going-to-spam  
Updated: 2026-10-21

## Key takeaways

- Gmail, Yahoo and Outlook.com require SPF or DKIM from every sender, and SPF, DKIM and DMARC from anyone sending over 5,000 messages a day.
- A domain may have only one SPF record, and SPF must stay within 10 DNS lookups.
- DMARC passes only when the From domain matches a domain that passed SPF or DKIM.
- Reverse DNS (PTR) and a clean IP matter as much as the DNS records.

When your emails are going to spam, the cause is usually one of four things: the domain's **SPF, DKIM and DMARC** records are missing or wrong; the server IP has no reverse DNS (PTR) matching its hostname; the IP is on a blocklist because it sent spam before; or recipients are marking your mail as spam. On a self-managed server, getting the three DNS records and the PTR right fixes most cases. The rest is keeping the IP clean and complaint rates low.

This guide walks through each cause, how to check it with commands and with real message headers, correct records for common setups (sending only from your VPS, adding Google Workspace, adding a sending service), what Gmail, Yahoo and Outlook.com currently require, and how to do it in ZoPanel.

## Why do emails go to spam?

Gmail's and Outlook's filters do not rely on one signal. They weigh:

1. **Authentication:** did this message really come from the domain it claims? That is what SPF, DKIM and DMARC answer.
2. **Infrastructure:** does the sending IP have valid reverse DNS, is TLS used, is the message correctly formatted?
3. **Reputation:** does the IP or domain have a spam history, is it on a list such as Spamhaus?
4. **Recipient behaviour:** how many people open, reply, or click "Report spam".
5. **Content:** suspicious short links, image-only mail, salesy subject lines.

On a self-managed hosting server, cause number one is almost always incomplete authentication. Number two is **a hacked website using the server to send spam**, which gets the IP blocklisted and drags every customer's mail into spam with it.

## What do Gmail, Yahoo and Outlook require?

Since February 1, 2024, [Google requires every sender to Gmail](https://support.google.com/a/answer/81126) to have SPF or DKIM, valid reverse DNS for sending IPs, TLS, and a spam rate in Postmaster Tools below 0.3%. Senders of more than 5,000 messages a day to Gmail need **both SPF and DKIM**, a **DMARC** record (`p=none` is enough), a From domain **aligned** with the SPF or DKIM domain, and one-click unsubscribe for marketing mail. Google recommends keeping the spam rate below 0.1%.

[Yahoo's requirements](https://senders.yahooinc.com/best-practices/) are nearly identical, with the same 0.3% ceiling. Outlook.com started applying SPF, DKIM and DMARC requirements to domains sending over 5,000 messages a day in May 2025.

In short: even if you send a few dozen messages a day, set up all three. It costs nothing, and it is the baseline in 2026.

## What is SPF and how do you write it correctly?

SPF ([RFC 7208](https://www.rfc-editor.org/rfc/rfc7208)) is a TXT record at the domain apex listing the servers allowed to send mail for that domain.

If you send only from your VPS, and the VPS is also your MX:

```text
example.com.  TXT  "v=spf1 mx a ~all"
```

- `mx`: servers in the MX records may send.
- `a`: the IP in the domain's A record may send.
- `~all`: everything else is suspicious (softfail). `-all` means reject, which is stricter.

If you also use Google Workspace for some mailboxes, or a sending service such as Amazon SES, Mailgun or Brevo, **merge them into the same record**:

```text
example.com.  TXT  "v=spf1 mx a include:_spf.google.com ~all"
```

The three most common SPF mistakes:

- **Two SPF records.** A domain may have exactly one record starting with `v=spf1`. Two cause a permanent error, which is as bad as none.
- **More than 10 DNS lookups.** Each `include`, `a` and `mx` costs at least one lookup, and nested includes add up. Over 10, SPF fails.
- **A forgotten sender.** The contact form that sends through a third-party SMTP, the accounting tool that emails invoices, the CRM: every source sending as your domain must be in SPF or sign with DKIM itself.

## What is DKIM and why does it matter?

DKIM signs each message with a private key on the sending server. The public key sits in DNS under a "selector":

```text
zp._domainkey.example.com.  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
```

The receiver fetches the public key, verifies the signature, and knows the message was not altered and was sent by a server holding the private key. Unlike SPF, a DKIM signature survives forwarding, so DKIM is often what decides whether DMARC passes.

Notes:

- Use 2048-bit RSA keys. 1024-bit keys are still accepted but no longer recommended.
- A 2048-bit key is longer than 255 characters, so the TXT record is split into several strings. Most DNS interfaces handle this; if you paste by hand, do not add spaces or line breaks inside the key.
- **Each sending service has its own selector.** Google Workspace, SES and your own server can coexist, one selector each.
- When you move to a new server, it signs with a new key: update the DKIM record.

## What is DMARC and which policy should you use?

DMARC tells receivers what to do with mail that fails authentication, and sends you reports. The original specification was RFC 7489; in 2026 the IETF published [RFC 9989](https://www.rfc-editor.org/info/rfc9989) to replace it, but records still start with `v=DMARC1` and existing records keep working.

```text
_dmarc.example.com.  TXT  "v=DMARC1; p=quarantine; rua=mailto:postmaster@example.com"
```

The key idea is **alignment**: DMARC passes only when SPF or DKIM passes *for the domain in the From header*. A message from `sales@example.com` signed with the sending provider's own domain passes DKIM, but not DMARC.

A safe path for a domain that already sends from several places:

1. **`p=none`** with `rua`: monitor only, and read reports for 2 to 4 weeks to find every legitimate sender.
2. **`p=quarantine`**: failing mail goes to spam.
3. **`p=reject`**: failing mail is refused, the strongest protection against spoofing.

For a new domain that sends only from a server you control, you can start at `p=quarantine`.

## Reverse DNS (PTR): the step everyone forgets

PTR maps an IP back to a name. Receivers look up the sending IP and expect a hostname that in turn resolves to that same IP. The PTR record is **not** set at your domain's DNS provider but at your **VPS provider**, because they own the IP range. Most providers let you set it in the VPS dashboard; some need a ticket.

Set the PTR to your mail hostname, for example `mail.example.com`, and make sure `mail.example.com` has an A record pointing to that IP.

## How to check each record

On Ubuntu or Debian, install `dig` (package `dnsutils`) and check:

```bash
sudo apt install dnsutils
dig +short MX example.com
dig +short TXT example.com | grep spf1
dig +short TXT zp._domainkey.example.com
dig +short TXT _dmarc.example.com
dig +short -x 203.0.113.10
```

Replace `zp` with your DKIM selector and `203.0.113.10` with your server IP. The last command should return your mail hostname.

The most reliable check is **reading the headers of a real message**. Send one to a Gmail address, open it and choose **Show original** from the three-dot menu. Gmail states whether SPF, DKIM and DMARC `PASS` or `FAIL`. In the headers, look for `Authentication-Results`:

```text
Authentication-Results: mx.google.com;
       dkim=pass header.i=@example.com header.s=zp;
       spf=pass smtp.mailfrom=example.com;
       dmarc=pass (p=QUARANTINE) header.from=example.com
```

If you send in volume to Gmail, sign up for [Google Postmaster Tools](https://postmaster.google.com/) to watch your spam rate and domain reputation.

## When the IP is already blocklisted

If all three records pass and mail still goes to spam or bounces, check the IP on lists such as Spamhaus, SpamCop and Barracuda. In this order:

1. **Find and stop the source first.** Usually a hacked site, an abused contact form or a mailbox with a leaked password. Request delisting before you stop it and the IP will be listed again quickly.
2. Delete the spam waiting in the queue.
3. Request removal on each list's website.
4. If your provider blocks outbound port 25, or the IP has a long-term poor reputation, consider sending through a relay (smarthost) such as Amazon SES, Mailgun, SendGrid or Brevo.

## How to do it in ZoPanel

ZoPanel uses Postfix, Dovecot and Rspamd, and DKIM-signs every domain with email enabled. The steps:

1. On the **Email** page, set the **Mail hostname** (for example `mail.example.com`) and install the mail server. Ask your VPS provider to set the IP's PTR to that hostname.
2. **Enable email for a domain.** The **DNS records** card shows exactly the four records you need: MX, SPF (`v=spf1 mx a ~all`), DKIM at `zp._domainkey` and DMARC (`p=quarantine` with `rua`). If the domain's DNS is hosted on the same server, a new zone is created with these records already in it.
3. Click **Run check** in **Mail delivery check**. It compares public DNS with the expected MX, SPF, DKIM and DMARC, checks PTR and outbound port 25, looks up the IP on Spamhaus, SpamCop and Barracuda, and gives a hint for each problem.
4. If your provider blocks port 25, configure **Outgoing mail relay (smarthost)**. Add the relay's sending sources to SPF and enable DKIM as the relay's documentation describes.

To stop one customer from getting the IP blocklisted, ZoPanel counts the recipients each account sends per hour (500 by default) and temporarily refuses mail over the limit, blocks website code from connecting directly to other servers on port 25, alerts you when the mail queue builds up, and checks daily whether the IP is on a blocklist. See the [Email](/docs/email) and [DNS](/docs/dns) docs.

## Quick checklist

- [ ] One SPF record only, listing every sender, within 10 DNS lookups.
- [ ] DKIM signing for every sender, 2048-bit keys.
- [ ] DMARC with `rua`, moving up to `quarantine` or `reject`.
- [ ] PTR matches the mail hostname, and the hostname resolves back to the IP.
- [ ] IP not on any blocklist.
- [ ] TLS on, one-click unsubscribe in marketing mail.
- [ ] Per-account sending limits, so one hacked site cannot sink the whole server.

## Conclusion

Most cases of mail landing in spam on a self-managed VPS are solved with three DNS records and one PTR record, set correctly once. The harder part is keeping the IP clean over time when a server has many customers, which is why per-account sending limits and blocklist alerts matter.

If you are about to set up domain email on a VPS, ZoPanel's Free plan includes the full mail server, DKIM and the delivery check. See [pricing](/pricing) or our guide to [running an email server on a VPS](/blog/email-server-on-vps).

## Frequently asked questions

### Why are my emails still going to spam with SPF, DKIM and DMARC set up?

Check the IP's PTR record, whether the IP is blocklisted, and the headers of a real message to confirm all three `pass` for the domain in the From header. If authentication passes, the cause is usually a new or poor IP or domain reputation, or recipients reporting your mail. Send consistently, ramp volume gradually and only mail people who opted in.

### Can a domain have two SPF records?

No. Two records starting with `v=spf1` cause a permanent error and are treated as no SPF at all. Merge every source into one record, for example `v=spf1 mx a include:_spf.google.com ~all`.

### Should I use ~all or -all in SPF?

`~all` (softfail) is safe while you are not sure you have listed every sender. Once DMARC is at `quarantine` or `reject`, the DMARC policy decides what happens to failing mail, so `~all` is still fine. `-all` suits domains where you fully control every sending source.

### Where do I set the PTR record?

At your VPS or IP provider, not where your domain's DNS is hosted. Look for reverse DNS or rDNS in the VPS dashboard, or open a ticket asking them to set the PTR to your mail hostname.

### Does DMARC p=none do anything?

Yes. `p=none` does not block spoofed mail, but it gets you reports on every source sending as your domain and meets Gmail's and Yahoo's minimum DMARC requirement. After a few weeks of reports, move to `quarantine`.
