Back to tutorials
Tutorial

Email Deliverability Troubleshooting Tutorial (2026): Fix SPF, DKIM, DMARC, rDNS, and HELO Issues on a VPS

Email deliverability troubleshooting tutorial: fix SPF, DKIM, DMARC, rDNS, and HELO problems on a VPS and reduce bounces fast.

By Anurag Singh
Updated on Jun 22, 2026
Category: Tutorial
Share article
Email Deliverability Troubleshooting Tutorial (2026): Fix SPF, DKIM, DMARC, rDNS, and HELO Issues on a VPS

Most “email problems” on a VPS aren’t caused by Postfix being down. They usually come from identity not lining up. Your hostname doesn’t match rDNS, your HELO looks like a default, or your SPF/DKIM/DMARC setup contradicts itself.

This email deliverability troubleshooting tutorial gives you a repeatable way to find the mismatch, fix it, and confirm the result on a production VPS.

The workflow assumes Ubuntu 24.04/26.04 LTS or Debian 12/13 with Postfix (or a control panel built on Postfix). You’ll pull evidence from logs, verify DNS, correct server identity, and retest with real recipients and real headers.

What you’ll fix (and why mailboxes reject you)

Mailbox providers score your message before a person ever sees it. If the receiver can’t trust who you are, you lose fast.

  • SPF: confirms the sending IP is authorized for the domain used in the From/Return-Path chain.
  • DKIM: confirms the message content was signed using your domain’s key.
  • DMARC: enforces alignment between the visible From domain and SPF/DKIM, and publishes a policy.
  • rDNS (PTR): links your sending IP to a hostname; providers treat it as a basic trust signal.
  • HELO/EHLO: the name your server announces during SMTP; generic or invalid names stand out.

In 2026, these aren’t “nice to have” settings. You need them for reliable inbox placement for business mail, password resets, or WooCommerce order notifications.

Prereqs: confirm your DNS authority and server role

Before you touch DNS or Postfix, confirm you’re fixing the system that actually sends. Many “VPS email” stacks route outbound mail through a third-party relay.

  1. Identify the outbound SMTP host from your app/cPanel/WordPress settings.
  2. Confirm your authoritative DNS (Cloudflare, registrar DNS, cPanel DNS cluster, etc.).
  3. Confirm your public IP on the sending VPS.
curl -4s ifconfig.me
hostname -f
postconf -n | egrep 'myhostname|mydomain|myorigin|inet_interfaces|mydestination'

If mail flow is business-critical, run on infrastructure you can audit end to end. A HostMyCode VPS gives you stable IPs, DNS control, and the access you need to diagnose issues quickly.

If you don’t want to own the mail stack day to day, managed VPS hosting is the safer choice for production deliverability.

Step 1: reproduce a failure and capture the exact SMTP response

Start with one message and one set of logs. Guessing wastes time.

  1. Send a message from the domain you’re fixing (not a different domain “just to test”).
  2. Watch the mail log and capture the recipient domain’s response code and text.
sudo tail -f /var/log/mail.log

Look for status=bounced, status=deferred, or SMTP codes like 550, 554, or 451. Copy the entire reason string.

The reason text is usually the most accurate checklist of what to fix next.

If your real problem is a growing queue or repeated deferrals, separate throughput from authentication. This companion guide focuses on queue mechanics: mail delays, bounces, and queue backlogs with Postfix.

Step 2: verify your outbound IP reputation signals (quick checks)

These checks are fast and low risk. They also catch the most common VPS mail mistakes.

Confirm your PTR (rDNS) points to a real hostname

IP="YOUR_VPS_IP"
dig +short -x $IP

You’re looking for a single hostname like mail.example.com. If it’s empty, generic, or doesn’t match what your server uses, fix it before anything else.

Next, confirm forward DNS points back to the same IP:

HOST="mail.example.com"
dig +short A $HOST

This forward-confirmed reverse DNS (FCrDNS) consistency matters.

If dig -x returns mail.example.com but mail.example.com resolves to a different IP, receivers see an easy trust failure.

For a step-by-step walkthrough, see: PTR record troubleshooting.

Check your server’s HELO/EHLO name

Many rejections spell it out: “HELO hostname invalid” or “HELO does not resolve.” Check what Postfix will announce:

postconf -h myhostname

myhostname should match the FQDN used for PTR. In most setups, that’s mail.example.com.

Don’t use localhost, a provider default like vps-12345, or a bare domain with no A record.

Step 3: correct the server identity (hostname, Postfix, and DNS)

Get identity right once. You’ll eliminate a large class of deliverability failures.

Set the system hostname (Ubuntu/Debian)

sudo hostnamectl set-hostname mail.example.com

Then update /etc/hosts so the hostname resolves locally.

This prevents odd HELO and TLS behavior later.

sudo nano /etc/hosts
127.0.0.1   localhost
127.0.1.1   mail.example.com mail

Set Postfix to use that hostname

sudo postconf -e "myhostname = mail.example.com"
sudo postconf -e "mydomain = example.com"
sudo postconf -e "myorigin = \$mydomain"
sudo systemctl restart postfix

Now confirm the DNS pieces exist and match:

  • A record: mail.example.com → your VPS IP
  • MX record (if receiving mail): example.commail.example.com
  • PTR record: your IP → mail.example.com (set at your hosting provider control panel)

Need the “where do I set PTR” part? Use: rDNS setup tutorial.

Step 4: fix SPF so it matches how you actually send mail

SPF usually fails for two reasons. Your record doesn’t include the sending IP. Or you published a strict policy while some mail still goes out through another system.

Read the current SPF record

DOMAIN="example.com"
dig +short TXT $DOMAIN | tr -d '"' | grep -i spf

Common SPF patterns (choose one)

  • Only this VPS sends (IPv4 example):
    v=spf1 ip4:YOUR_VPS_IP -all
  • Your VPS + a vendor (include):
    v=spf1 ip4:YOUR_VPS_IP include:_spf.vendor.com -all
  • Temporary soft fail while migrating:
    v=spf1 ip4:YOUR_VPS_IP ~all

Use -all only when you’re sure every legitimate sender is listed. During a migration, ~all buys time. It also avoids hard rejects while you find “forgotten” senders.

SPF pitfall: multiple TXT records

Two separate SPF TXT records often trigger a permerror. Combine everything into one SPF record for the domain.

Step 5: fix DKIM alignment (verify signing, not just key existence)

A DKIM key in DNS only proves you published a key. It does not prove your outgoing mail is signed.

Confirm the signature header on real messages.

Check for DKIM signatures in a delivered message

Send a message to an external mailbox you control. Then open “Show original” and confirm:

  • DKIM-Signature: header exists
  • d=example.com matches the domain in your visible From address
  • s=selector matches your DNS selector record

Confirm the DKIM TXT record exists (selector)

SELECTOR="default"
dig +short TXT ${SELECTOR}._domainkey.example.com

If your signature uses s=mail, query mail._domainkey.example.com instead.

If you’re setting DKIM up from zero on Ubuntu with Postfix, follow: DKIM setup tutorial. This article stays focused on troubleshooting and alignment.

Step 6: DMARC troubleshooting that actually stops “p=reject” pain

DMARC is where strict policies hurt the most. A classic failure looks like this: SPF passes for a bounce domain you don’t control. DKIM isn’t aligned. DMARC fails even though someone tells you “SPF passed.”

Read your DMARC record

dig +short TXT _dmarc.example.com | tr -d '"'

A safe baseline DMARC record for most small businesses

If you’re stabilizing deliverability, start with reporting and a non-destructive policy:

v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; adkim=s; aspf=s; pct=100

Move to p=quarantine after you confirm DKIM signing and full SPF coverage across every sender.

Switch to p=reject only once reports show consistent alignment.

Alignment rule that surprises people

DMARC aligns to the visible From: domain.

If your app sends From orders@shop.example.com but DKIM signs as example.net, DMARC fails. That can happen even if some messages still get through.

Step 7: validate TLS and SMTP banner correctness (quick but high impact)

Some servers get penalized because they look unfinished. Receivers use your SMTP banner/hostname and TLS certificate as quick trust signals.

Test the SMTP greeting and STARTTLS

openssl s_client -starttls smtp -connect mail.example.com:587 -servername mail.example.com -crlf

You want:

  • A banner that references mail.example.com
  • A valid certificate for mail.example.com (not self-signed)

If you’re using cPanel, cert management is simpler. But Let’s Encrypt can still fail at renewal time.

Keep this nearby: SSL renewal troubleshooting.

Step 8: check your sending volume, rate limits, and queue behavior

Throttling often looks like “random bounces.” A provider defers a burst, your queue grows, and retries stack up.

Inspect the queue

mailq
postqueue -p

If you see many deferred messages to the same domain with “rate limited” or “try again later,” reduce the send rate.

On WordPress, that may mean spacing campaign sends. It can also mean switching to a setup that queues properly.

Find top recipients causing backlog

postqueue -p | awk 'BEGIN{RS=""} /@/{print $0}' | head

For deeper queue cleanup, use: fix a stuck Postfix mail queue.

Step 9: WordPress-specific checks (the mistakes that break order emails)

WordPress adds its own failure modes. Common ones include sloppy From addresses, plugin collisions, and cron delays.

These issues can make delivery feel broken even when SMTP is fine.

  • From address: use a real mailbox on your domain, not wordpress@localhost.
  • Envelope sender: if your SMTP plugin supports it, keep Return-Path consistent.
  • WP-Cron delays: scheduled mail can be late even with perfect deliverability settings.

If messages lag during traffic spikes or on low-traffic sites, fix cron reliability first: WordPress cron troubleshooting.

Step 10: run a clean re-test and document the final state

After each change, retest with a single message and review the headers.

Avoid changing SPF, DKIM, DMARC, hostname, and TLS all at once unless you can roll back quickly.

Final verification checklist

  • PTR points to mail.example.com
  • A record for mail.example.com points to the same IP
  • myhostname is mail.example.com
  • HELO/EHLO matches mail.example.com and resolves
  • SPF includes the actual sender(s), single record only
  • DKIM-Signature present, d= aligns with From domain
  • DMARC policy set appropriately (start at p=none if stabilizing)
  • STARTTLS works with a valid certificate for the mail hostname
  • Logs show remote acceptance, not repeated deferrals

Summary: the fastest path to fewer bounces in 2026

Fix identity first. A correct PTR + hostname + HELO pairing removes a lot of instant distrust.

Then align SPF, DKIM, and DMARC so the visible From domain matches what your server can prove.

Once that foundation is solid, rate limits, volume spikes, and application quirks are much easier to diagnose.

If you want a stable base for outbound mail and website workflows, run it on a VPS you can control and verify.

HostMyCode’s HostMyCode VPS is a good fit when you need predictable IP identity, and managed VPS hosting works well if you want deliverability fixes without living in mail logs.

If you’re troubleshooting bounces during a migration or after moving WordPress to a new server, start with stable DNS and a dedicated mail hostname on a VPS. HostMyCode can provision an HostMyCode VPS quickly, and our managed VPS hosting option helps you keep SPF/DKIM/rDNS and TLS consistent as your sending grows.

FAQ

Why does SPF show “pass” but DMARC still fails?

DMARC requires alignment with the visible From domain. SPF can pass for the Return-Path domain and still fail DMARC if From is different and DKIM isn’t aligned.

Do I need rDNS (PTR) if SPF/DKIM/DMARC are correct?

For consistent deliverability, yes. Many receivers treat missing or generic PTR as a negative trust signal even when authentication passes.

What’s the best HELO name for a VPS mail server?

Use a real FQDN that resolves to your sending IP, typically the same hostname used for PTR, like mail.example.com.

Should I set DMARC to p=reject right away?

Not if you’re still troubleshooting. Start with p=none while you confirm alignment across all senders, then move to quarantine and reject based on reports.

Where do I look first on the VPS when mail bounces?

Check /var/log/mail.log for the remote server’s exact SMTP response and your queue state (mailq). The response text usually points to the failing control (SPF, rDNS, HELO, or policy).