VPS Tutorials
VPS Self-Hosted Email Going to Spam (2026): Troubleshooting SPF, DKIM, DMARC, PTR, and Bounce Logs
Just because your VPS self-hosted mail server can send email doesn't mean it lands in the inbox. Gmail, Outlook, and Yahoo look at SPF, DKIM, DMARC, PTR/rDNS, HELO, IP reputation, bounce rates, and sending cadence all at once. This article follows a real troubleshooting order: check bounce logs first, then DNS authentication, then confirm PTR and port 25, and finally decide whether it's a configuration problem, an IP reputation problem, or time to switch to an SMTP relay.

The most frustrating thing about self-hosted email isn't "can't send" — it's when SMTP reports the message as sent, but the recipient never gets it, or it goes straight to spam.
Many people have already set up Docker Mailserver, Postfix/Dovecot, Mailcow, or Poste.io following tutorials, and have configured SPF, DKIM, and DMARC, yet delivery to Gmail and Outlook is still unreliable. The problem is that email delivery doesn't end with "can connect to port 25" — the receiving side also looks at your identity, IP reputation, reverse DNS, sending behavior, and complaint history.
This article won't cover how to install a mail server. For installation, see:
This article addresses only one question: why do emails sent from a self-hosted mailbox go to spam or get bounced, and in what order should you troubleshoot.
Don't start by changing SPF. First confirm which situation you're in:
- Direct bounce: you receive a bounce containing
550,5.7.1,policy,SPF fail,PTR required, and similar strings; - Recipient accepted it, but it went to spam: SMTP logs look successful, Gmail/Outlook received it, but it doesn't land in the inbox;
- Delayed delivery: the logs show
deferred,temporarily rejected,rate limited, and it may succeed later.
These three have different causes.
Bounces are usually hard errors — prioritize DNS authentication, PTR, and blacklists; spam placement is usually a reputation and content issue; delayed delivery is usually rate, reputation, greylisting, or temporary policy limits.
Start by checking the mail logs. Common paths on Debian/Ubuntu:
sudo tail -n 200 /var/log/mail.log
If you're using Docker Mailserver:
docker logs mailserver --tail=200
Postfix queue:
postqueue -p
View queue details for a specific message:
postcat -vq QUEUE_ID
Act only after you see the specific error code — don't fix blindly.
SPF tells the recipient which servers are allowed to send mail on behalf of your domain.
First check DNS:
dig TXT example.com +short
A minimal self-hosted mail SPF might look like this:
v=spf1 mx -all
Or explicitly list the IP:
v=spf1 ip4:203.0.113.10 -all
Common mistakes:
- Two
v=spf1records exist for the same domain; - Forgetting to add the VPS IP;
- Adding many
includeentries, exceeding the SPF 10 DNS lookup limit; - Always using
~alland never tightening it; - The application actually sends via a third-party service, but SPF doesn't include that service.
Note: SPF looks at the envelope sender / Return-Path, not necessarily the From the user sees. Many DMARC failures are actually cases where SPF passed but didn't align with the From domain.
DKIM adds a signature to the email. The recipient uses the public key in DNS to verify the message hasn't been altered.
Find DKIM-Signature in the raw email, and you'll see something like:
s=mail; d=example.com;
Here s=mail is the selector. Check DNS:
dig TXT mail._domainkey.example.com +short
Common mistakes:
- The selector in the email is
mail, but DNS publishes it underdefault._domainkey; - The DKIM public key was copied incompletely;
- The DNS provider truncates long TXT records;
- The server's DKIM key was changed, but DNS still has the old public key;
- DKIM isn't enabled for all sending services.
After sending to Gmail, click "Show original" and check whether Authentication-Results contains:
dkim=pass
spf=pass
dmarc=pass
If DKIM fails, don't worry about the content copy yet — the identity hasn't been verified, so the chance of landing in the inbox is very low.
DMARC builds on SPF and DKIM. It cares about whether the From domain the user sees aligns with a domain that passed SPF or DKIM verification.
Check DMARC:
dig TXT _dmarc.example.com +short
When you first start troubleshooting, use:
v=DMARC1; p=none; rua=mailto:[email protected]
Once you've confirmed all sending sources are working properly, gradually upgrade to:
v=DMARC1; p=quarantine; rua=mailto:[email protected]
Only then consider:
v=DMARC1; p=reject; rua=mailto:[email protected]
Don't jump straight to p=reject. If you still have website forms, monitoring systems, third-party email services, or Git service notifications sending mail, rejecting before you've mapped them out can easily knock out your own legitimate email.
PTR reverse DNS is one of the hard requirements for self-hosted email.
Check your VPS IP:
dig -x 203.0.113.10 +short
The ideal result should return your mail hostname, for example:
mail.example.com.
Then check forward resolution:
dig A mail.example.com +short
It should resolve back to the same IP.
This is called forward-confirmed reverse DNS. Many recipients look at this signal.
PTR is not set in Cloudflare DNS, nor in your domain's DNS panel. It must be set in the VPS provider's console, or via a support ticket asking the provider to change it.
Common mistakes:
- PTR is empty;
- PTR points to the provider's default hostname;
- PTR points to
mail.example.com, butmail.example.comhas no A record; - The HELO/EHLO hostname doesn't match the PTR;
- Multiple domains share one mail server, but identities aren't unified.
Check the hostname in Postfix:
postconf myhostname
postconf myorigin
If your server announces itself as vps123.provider.com but the email From is example.com, your reputation will suffer badly.
Many cloud providers block outbound port 25 by default. Being able to log in to your mailbox client locally doesn't mean the server can deliver outbound.
Test against Gmail MX:
nc -vz gmail-smtp-in.l.google.com 25
If it times out or is refused, the provider may have blocked port 25.
You can also use telnet:
telnet gmail-smtp-in.l.google.com 25
If port 25 is blocked, there are usually only three options:
- Open a ticket to request unblocking;
- Switch to a VPS provider that allows outbound email;
- Use an SMTP relay, such as Amazon SES, Mailgun, SendGrid, or Postmark.
Don't use 587/465 as a substitute for server-to-server delivery on port 25. 587/465 are for client submission, not a replacement for normal MTA-to-MTA delivery.
If DNS is correct and PTR is correct but mail is still rejected, the next step is to check IP reputation.
First check common RBL/DNSBLs. You can use online tools, or query some lists directly:
dig 10.113.0.203.zen.spamhaus.org A
Here the IP must be written in reverse. For example, 203.0.113.10 becomes 10.113.0.203.
More practical options:
- MxToolbox blacklist check;
- Spamhaus;
- Google Postmaster Tools;
- Microsoft SNDS / JMRP.
Check the IP as soon as you buy a new VPS. We've written about this before:
If the IP is already on a core blacklist, don't waste time fiddling with Postfix. First see whether you can change the IP, get a refund, or switch providers. Some ASNs used by cheap VPS providers are abused long-term, and even with perfect configuration, landing in the Gmail inbox can be very hard.
If the recipient has accepted the email but it goes to spam, it means technical authentication may only be "good enough" and reputation hasn't been established yet.
Check in this order:
- Whether
spf/dkim/dmarcin the Gmail original all pass; - Whether the From domain aligns with the DKIM
d=; - Whether PTR, HELO, and A records are consistent;
- Whether a new IP is sending a lot of mail right away;
- Whether too much mail is sent to nonexistent addresses, causing high bounces;
- Whether the content is all images, has too many short links, or has inconsistent link domains;
- Whether marketing and transactional email are mixed;
- Whether Google Postmaster Tools shows low reputation.
Don't mass-send from a new IP immediately. Start with low volume and genuine engagement email, then gradually increase volume. Self-hosted email is best suited for:
- Personal email;
- Site notifications;
- A small amount of transactional email;
- Internal system alerts.
It's not suited for sending marketing email right away. That's actively trashing your IP reputation.
Common clues look roughly like this:
| Symptom / Error | Focus on |
|---|---|
550 5.7.1 | Policy rejection, reputation, authentication failure |
SPF fail | SPF record, Return-Path, sending IP |
DKIM fail | Selector, public key, signing configuration |
DMARC fail | SPF/DKIM alignment, From domain |
PTR required | Reverse DNS, HELO hostname |
blocked using Spamhaus | IP blacklist |
temporarily deferred | Rate, greylisting, reputation observation |
| Accepted but goes to spam | Reputation, content, sending cadence |
A 4xx usually means a temporary rejection; a 5xx is mostly a hard rejection. Don't just look at "failed" — read the text after it.
This isn't shameful — it's reality.
If you run into the following situations, seriously consider an SMTP relay:
- The provider doesn't open port 25;
- The IP range has poor reputation, and changing IPs isn't stable either;
- You need to send business notifications, verification codes, or order emails and can't gamble on deliverability;
- You don't have the energy to maintain RBLs, DMARC reports, and bounce handling;
- Gmail/Outlook keeps putting mail in spam even though authentication all passes.
A compromise approach is:
- Your own VPS handles receiving, IMAP, and mailbox storage;
- Outbound email goes through a relay like Amazon SES, Mailgun, SendGrid, or Postmark;
- From, DKIM, and Return-Path are all aligned per the relay's requirements;
- Important transactional email and personal email use separate domains or subdomains.
This way you still control your mailbox data, but you don't put all delivery pressure on one cheap VPS IP.
If email is going to spam right now, do this in order:
- Check
/var/log/mail.logor Docker logs to confirm whether it's a bounce, delay, or spam placement; - Send to Gmail and check
spf/dkim/dmarcin the original message; - Use
dig TXT example.com +shortto check SPF; - Use
dig TXT selector._domainkey.example.com +shortto check DKIM; - Use
dig TXT _dmarc.example.com +shortto check DMARC; - Use
dig -x VPS_IP +shortto check PTR; - Use
postconf myhostnameto check HELO/EHLO identity; - Use
nc -vz gmail-smtp-in.l.google.com 25to check port 25; - Check Spamhaus / MxToolbox;
- Register for Google Postmaster Tools;
- Send at low volume from a new IP first — don't mass-send;
- If still unstable, consider an SMTP relay.
Because authentication is only a ticket in, not an inbox guarantee. Recipients also look at IP reputation, domain reputation, sending frequency, complaint history, content quality, link domains, and user engagement. A new VPS IP may need time to build reputation even with correct configuration.
No. Cloudflare manages forward DNS for your domain. PTR/rDNS is the reverse resolution of an IP and must be set at your VPS provider, or handled via a support ticket.
When you first start troubleshooting, you can use ~all to reduce collateral damage. Once you've confirmed all legitimate sending sources, it's recommended to gradually tighten to -all. But only if you truly know all sending sources, including website forms, monitoring systems, and third-party email services.
Not recommended. Start with p=none to collect reports, confirm SPF/DKIM and all sending sources are aligned, then gradually move to quarantine, reject. Otherwise you may reject your own legitimate email.
Yes, but don't underestimate the maintenance cost. Receiving mail and sending a small amount of personal mail is fine; for verification codes, order notifications, and customer email, it's best to at least have an SMTP relay plan ready.
When VPS self-hosted email goes to spam, the most common cause isn't "the mail server is broken" — it's that identity and reputation didn't pass muster.
The troubleshooting order is simple: check bounce logs first, then SPF, DKIM, DMARC, then PTR/rDNS, HELO, port 25, IP blacklists, and Postmaster data. If authentication fails, fix authentication first; once it passes, look at reputation and sending behavior.
If you're using a cheap VPS whose IP range is abused long-term, don't spend all your time on configuration. Change the IP when you should, and use an SMTP relay when you should. Whether self-hosted email delivers reliably is only half about technical configuration — the other half is reputation.