
Your mail server can be “working” and still be failing. Messages leave the queue and recipients technically receive them. Yet they land in spam, get rate-limited, or sit in quiet deferrals. This email deliverability troubleshooting tutorial focuses on checks you can verify on a VPS and in DNS—no guesswork and no superstition.
The goal is predictable delivery at major inbox providers. You’ll also build a log-and-test workflow you can rerun after every change. We’ll use Postfix or Exim diagnostics, DNS lookups, TLS verification, and a short list of fixes that often help within hours.
Scope, assumptions, and a safety checkpoint
This guide assumes you send mail from a Linux VPS or dedicated server you control (Ubuntu 24.04/26.04 LTS, Debian 12/13, AlmaLinux 9/10, Rocky 9/10). You may run Postfix (common on Ubuntu/Debian) or Exim (common on cPanel).
- Outbound only: Your website or app sends transactional mail (contact forms, WooCommerce, password resets).
- Inbound optional: You may receive mail too, but deliverability work starts with outbound.
- Change control: Before you touch DNS, record current values and lower TTLs where safe.
If you’re layering mail on top of your web stack, verify time sync first. Bad time breaks TLS and DKIM validation. It can also look like “random spam.”
Use this internal guide if you suspect drift: VPS time sync troubleshooting tutorial.
Email deliverability troubleshooting tutorial: start with evidence, not settings
Before you change anything, collect three artifacts from a message that went to spam (or failed):
- Full message headers from the recipient mailbox (not just the visible “From/To”).
- Mail log entries for the queue ID.
- DNS snapshot for SPF, DKIM, DMARC, and rDNS/PTR.
1) Grab headers and locate the queue ID
Most mailbox UIs offer “Original message,” “Show source,” or similar. In the headers, focus on:
Authentication-Results:(SPF/DKIM/DMARC pass/fail)Received:chain (which host handed off to whom)Message-ID:domainReturn-Path:(envelope sender / bounce address)
You may also see an internal queue marker such as X-Postfix-Queue-ID. If it’s not there, pull the queue ID from server logs.
2) Find the message in logs (Postfix)
On Ubuntu/Debian with Postfix:
sudo grep -R "message-id" /var/log/mail.log | tail -n 20
sudo grep -R "to=<recipient@example.com>" /var/log/mail.log | tail -n 50
Once you have the queue ID (example: 3F2C012345):
sudo grep "3F2C012345" /var/log/mail.log
Look for the outcome: status=sent, status=deferred (temporary reject), or bounced (hard fail).
3) Find the message in logs (Exim / cPanel)
On cPanel servers running Exim:
sudo exim -bp | head
sudo exim -Mvh <message_id>
sudo exim -Mvl <message_id>
If you want a deeper “follow the message end-to-end” workflow, use: trace SMTP delivery failures using mail logs and queue IDs.
Checklist: the five failures that cause most spam placement
If you only have time for one pass today, do this in order. Each item is quick to verify and usually has a straightforward fix.
- PTR (reverse DNS) does not match your mail hostname
- HELO/EHLO hostname mismatch or generic hostname
- SPF passes but DMARC fails because alignment is wrong
- DKIM signs, but selector/DNS is wrong or key is too short/rotated badly
- TLS is missing, weak, or misconfigured (providers down-rank or throttle)
Step 1: Fix hostname, rDNS (PTR), and forward-confirmed reverse DNS
Mailbox providers want a clean, consistent identity for your sending IP. Aim for this chain: IP → PTR → hostname → A record → same IP.
Verify your server hostname (FQDN)
hostnamectl
hostname -f
A good example: mail.yourdomain.com. A bad example: vps-12345 or a provider-generated label.
If you need to set it properly (and verify HELO/EHLO and the banner along the way), follow: Email server hostname setup tutorial.
Set PTR (reverse DNS) for the sending IP
PTR is set at your hosting provider, not in your domain DNS zone. Point it at your mail hostname (example: mail.yourdomain.com).
Verify from anywhere:
dig -x YOUR.SERVER.IP +short
Then verify the forward record:
dig mail.yourdomain.com A +short
If these don’t resolve back to the same IP, fix your A record or request the correct PTR from your provider.
For a full walkthrough: PTR record setup tutorial.
Common pitfall: sending from the “web server” IP without rDNS control
On shared hosting, you usually can’t set rDNS. That alone can trigger throttling and spam placement, even if SPF/DKIM look fine.
If deliverability affects revenue or support, move outbound mail to a VPS where you control rDNS and logs. HostMyCode’s HostMyCode VPS plans are built for that level of control without pushing you into a full enterprise mail platform.
Step 2: Confirm HELO/EHLO and SMTP banner match the identity you publish
Providers compare the HELO/EHLO name against rDNS. If you present a certificate, they compare it against your TLS name too. A mismatch won’t always block mail, but it often reduces trust.
Quick HELO test from your workstation
openssl s_client -starttls smtp -connect mail.yourdomain.com:587 -servername mail.yourdomain.com
Check two things:
- The certificate subject/SAN includes
mail.yourdomain.com - The SMTP banner references your hostname
Postfix: set the hostname and HELO name explicitly
Edit /etc/postfix/main.cf:
myhostname = mail.yourdomain.com
mydomain = yourdomain.com
myorigin = $mydomain
smtp_helo_name = $myhostname
Reload safely:
sudo postfix check
sudo systemctl reload postfix
Step 3: Stop “DMARC fails even though SPF passes” (alignment fixes)
This is a common trap. SPF can pass for the envelope sender, while DMARC fails because the Header From domain doesn’t align. That’s how you end up with “SPF=pass, DKIM=pass, DMARC=fail” inside Authentication-Results.
Understand the three identities (fast, practical version)
- Header From: what users see (example:
From: billing@yourdomain.com) - Envelope From (Return-Path): where bounces go (example:
bounce@mailer.yourdomain.com) - DKIM d= domain: the signing domain (example:
d=yourdomain.com)
DMARC cares about alignment between Header From and either SPF (envelope) or DKIM (d=). On most VPS setups, the cleanest route is simple.
Make DKIM d= match the Header From domain.
Verify alignment from headers
In the headers, locate:
From:domain (Header From)Return-Path:domain (SPF identity)DKIM-Signature: d=(DKIM identity)
If Header From is yourdomain.com but DKIM signs as mail.yourdomain.com (or another subdomain), DMARC may fail. Whether it fails depends on your alignment mode and policy.
Fix: choose one From domain and stick to it
For transactional mail from your site:
- Set the application “From” domain to
@yourdomain.com(avoid free mailbox domains). - Ensure DKIM signs with
d=yourdomain.com. - Make SPF include only the senders you actually use.
If you run multiple senders (app mail, helpdesk, newsletter), don’t jam everything into one SPF record with a dozen includes.
Split by subdomain (for example, app.yourdomain.com and support.yourdomain.com) and give each its own SPF/DKIM/DMARC.
Step 4: Diagnose DKIM problems without rewriting your mail stack
Most DKIM failures come from one of three issues: the wrong selector in DNS, DNS typos/propagation problems, or signing the wrong domain.
Confirm the DKIM selector your server uses
OpenDKIM commonly references a KeyTable/SigningTable. On many installs:
/etc/opendkim.conf/etc/opendkim/KeyTable/etc/opendkim/SigningTable
Find the selector (often something like mail or s2026). Your public DNS record must be published at:
<selector>._domainkey.yourdomain.com
Verify the DKIM TXT record is visible publicly
dig TXT mail._domainkey.yourdomain.com +short
If your DNS is on Cloudflare, confirm it’s a TXT record (not a CNAME workaround unless you know exactly why you’re using it). Also confirm the quoting didn’t get mangled.
For a safe DNS change workflow: Cloudflare DNS setup guide tutorial.
DKIM key length and rotation notes for 2026
In 2026, use 2048-bit DKIM keys unless a specific provider limitation forces 1024-bit (rare, and discouraged).
When rotating keys, publish the new selector first. If your tooling supports it, sign with both selectors briefly.
Retire the old selector after you see consistent passes across providers.
Step 5: TLS matters for deliverability (and it’s measurable)
You don’t need exotic cipher tuning. You do need reliable STARTTLS and a certificate that matches your mail hostname. Some providers throttle or score mail lower when TLS fails or the identity looks inconsistent.
Check STARTTLS on common ports
openssl s_client -starttls smtp -connect mail.yourdomain.com:25 -servername mail.yourdomain.com < /dev/null
openssl s_client -starttls smtp -connect mail.yourdomain.com:587 -servername mail.yourdomain.com < /dev/null
Look for Verify return code: 0 (ok). If you see a name mismatch, the certificate doesn’t match the hostname you advertise.
Postfix TLS minimums (sane baseline)
In /etc/postfix/main.cf:
smtpd_tls_security_level = may
smtp_tls_security_level = may
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.yourdomain.com/privkey.pem
smtpd_tls_loglevel = 1
Reload:
sudo systemctl reload postfix
If you also need an HTTPS baseline for your sites, keep it separate from mail. Use the same “verify first, then tighten” approach: TLS hardening tutorial for Nginx/Apache.
Step 6: Check for rate limiting, blocks, and reputation signals
Sometimes your config is fine and the problem is behavior. Common causes include sending too fast, sending to weak lists, or inheriting an IP with baggage.
Good providers reduce that risk, but you still need to confirm what’s happening in logs.
Spot rate limiting in logs
Common patterns include:
451 4.7.1temporary deferrals421service not available / try again later4.7.0suspicious sending behavior / throttling
On Postfix:
sudo grep -E "(421|451|4\.7\.)" /var/log/mail.log | tail -n 100
If deferrals spike, don’t “fix” it by retrying more aggressively. Let Postfix backoff do its job.
If you previously tuned queue/retry parameters, revert to defaults until delivery stabilizes.
Queue health: you can’t debug deliverability with a clogged queue
Start with the basics:
mailq
postqueue -p | head -n 40
If the queue keeps growing, solve that first.
This guide covers safe queue triage: VPS mail queue troubleshooting tutorial.
Outbound volume and list hygiene (quick reality check)
- For transactional mail, keep bounces low and content consistent.
- Don’t send marketing blasts from the same domain/IP as password reset email.
- If your app can’t handle bounce processing, don’t run newsletter workloads on your VPS MTA.
Step 7: Content and application-layer issues that look like deliverability problems
Two patterns show up over and over: malformed headers and sketchy links.
Broken headers: duplicate From, missing Message-ID, wrong encoding
Some “DIY SMTP” libraries generate malformed headers under edge cases. In the raw headers, watch for:
- Two
From:lines - No
Message-ID: - Invalid
Date:or timezone
If you see any of these, fix the application mailer first (use a maintained library). Don’t keep tweaking DNS until the message format is clean.
Also confirm the server clock is correct—time sync still matters here.
Broken URLs: redirects, mixed content, or “wrong scheme” distrust
Transactional emails usually link back to your site. If those links bounce through redirect loops, hit HTTP first, or upgrade/downgrade oddly, filters can score the message worse.
Password reset templates are a common culprit.
If you recently changed SSL or redirect rules, run: HTTPS redirect troubleshooting tutorial.
Step 8: A repeatable test plan (15 minutes)
After each change, run the same tests in the same order. That’s how you avoid “I changed three things and it got better” guessing.
- DNS:
dig TXTfor SPF/DKIM/DMARC anddig -xfor PTR. - TLS:
openssl s_client -starttls smtpon 25 and 587. - Send: send one message to each of Gmail, Microsoft, and a custom domain inbox you control.
- Headers: confirm SPF/DKIM/DMARC results and alignment.
- Logs: verify
status=sentand track any deferrals.
Keep a small text file like deliverability-notes.txt with timestamps and exactly what you changed. You’ll thank yourself the next time something drifts.
Operational hardening that improves deliverability over time
Once the basics are correct, the long-term win is keeping them correct.
Patch cadence and predictable reboots
MTAs and TLS libraries get security fixes that can change handshake behavior. Schedule updates and reboots. That helps you avoid diagnosing a surprise deliverability shift at 2 AM.
Monitoring: alert on queue growth and repeated deferrals
Queue growth is often the earliest warning you’ll get. Even a simple daily report helps.
If you want a lightweight monitoring stack, start here: VPS monitoring setup tutorial.
Separate roles: web hosting vs mail sending
If your WordPress site gets busy, sharing resources with the MTA can spike load. That can delay SMTP deliveries.
For agencies and resellers, putting mail on a separate VPS (or moving the site to a managed plan) keeps both sides predictable.
HostMyCode’s managed VPS hosting is a good fit if you want deliverability controls (PTR/hostname/TLS/logging) but don’t want to own MTA updates and security baselines.
If you want consistent outbound email from your own server identity (rDNS, TLS, full logs), run mail on a VPS you control. Start with a HostMyCode VPS, or choose managed VPS hosting if you’d rather hand off the day-to-day server administration.
FAQ
Why does SPF pass but emails still go to spam?
SPF passing only confirms the sending IP is allowed for the envelope domain. Spam placement often comes from DMARC misalignment (Header From doesn’t align with SPF/DKIM), missing rDNS, or a weak/incorrect TLS identity.
Do I need DMARC to fix deliverability?
You can deliver without DMARC, but DMARC gives receivers a policy and a clearer way to trust your domain identity. If you publish DMARC, start with p=none and validate alignment first.
How long do deliverability fixes take to show results?
DNS and TLS fixes show up as soon as caches expire (often minutes to hours). Reputation improvements can take days if you had high bounce rates or bursts of suspicious volume.
Should I send newsletters from my VPS mail server?
Usually not. Marketing volume, unsubscribes, and list churn can damage the reputation you need for transactional mail. Split marketing to a dedicated platform, or at least a separate subdomain and IP.
Summary: the fastest path to better inbox placement
Inbox placement improves when your sending identity stays consistent and easy to verify. That means matching hostname and PTR, a clean HELO, aligned SPF/DKIM with the From domain, and reliable STARTTLS with a certificate that matches.
After that, logs and queue health tell you what’s actually happening.
If you need that level of control, run outbound mail on a VPS where you can set rDNS, audit logs, and tune safely. HostMyCode offers Affordable & Reliable Hosting that’s well-suited to mail + web workloads when configured with the checks in this tutorial.