Why VPS Emails Go to Spam Even When SPF, DKIM and DMARC Are Set Up
SPF is set up, DKIM signs your messages, DMARC does not complain, and yet recipients still see your mail in the spam folder or do not see it at all. If your DNS records are in order (for how SPF, DKIM and DMARC work as DNS records, see our article on DNS resource records), the problem almost always sits one level lower. Either your server physically cannot reach the recipient on the required port, or the receiving side cannot confirm that your IP really is the server it claims to be, or your IP is already on a spam list. This article covers three things that rarely get mentioned alongside SPF, DKIM and DMARC but matter just as much for deliverability: blocked port 25, the PTR record and blacklists, and how the reputation of a new IP is formed.
Outbound port 25 is closed: it may be policy, not a bug
Port 25 is the standard SMTP port that mail servers use to exchange messages with each other directly. It is a different story from ports 587 and 465, which are normally used to send mail through an authenticated relay, for example when a mail client or a script on the server sends a message through an SMTP service. If your Postfix or another MTA on the VPS tries to deliver mail straight to the recipient on port 25, and outbound port 25 is blocked at network level by the hosting provider, the message simply will not leave. The connection drops before the receiving server can check anything, including SPF and DKIM.
Blocking outbound port 25 by default is common practice among large cloud and hosting providers, and the reason is the same everywhere: new and compromised servers are the main source of mass spam, and blocking the port by default removes that possibility before it becomes a problem. Policies differ from provider to provider. Typical variants look like this:
- Blocked for public addresses, open on request. Outbound traffic on port 25 is allowed only to private addresses, and the restriction can be lifted through a separate request form with a justification of legitimate use. Review can take up to a couple of days, and if you run instances in several regions, the request may have to be filed for each region separately.
- Blocked on all submission ports, no unblocking. Some providers block 25, 465 and 587 by default to prevent abuse, and recommend not running your own mail server at all but sending through a third-party email service.
- Blocked on 25 only. Connections to port 25 on addresses outside the provider’s own network are blocked, while ports 587 and 465 stay open.
- Unblocking after a trial period. The block is lifted only after some time of account use and after the first invoice is paid, and each decision is made individually by request.
You cannot generalize one procedure to everyone. Each provider has its own conditions and timelines for unblocking, and some do not offer unblocking at all and advise using an external relay. Find out your provider’s policy separately. If the provider will not lift the block, the only option left is sending through an external SMTP relay on port 587 or 465.
You can check whether outbound port 25 is open with one command from the server:
nc -zv -w5 smtp.gmail.com 25
If the answer contains succeeded, the port is open and the connection is established. If nc is not at hand, you can get the same result with bash itself:
timeout 5 bash -c "echo > /dev/tcp/smtp.gmail.com/25" && echo "port open" || echo "port closed or filtered"
If the port is closed, there is no point in checking PTR and blacklists yet: messages will not go out directly anyway until the port is opened or you switch to sending through an external SMTP relay on port 587 or 465.
The PTR record: the receiver must be able to confirm who you are
PTR is a record in the reverse DNS zone (in-addr.arpa) that maps an IP address to a hostname, the opposite direction from an ordinary A record, which turns a hostname into an IP. Unlike A, MX or TXT records of your own domain, which you edit at your DNS registrar, the PTR record for a VPS is not set by you. The hosting provider sets it through the control panel or on request to support, because the reverse DNS zone belongs to the owner of the IP block, not to the tenant of an individual address.
You can check your current PTR record like this:
dig -x YOUR_IP +short
or, shorter:
host YOUR_IP
One point often causes confusion: the hostname the PTR returns usually does not match what the hostname command shows on the server itself (the contents of /etc/hostname), and that is normal and not a problem in itself. For mail deliverability, what matters is not that PTR matches the server’s internal name but that PTR matches the name your mail server announces to recipients when it connects, with the HELO/EHLO command. That name is configured separately in the MTA configuration: in Postfix these are the smtp_helo_name and myhostname parameters in main.cf. If PTR points to mail.example.com while Postfix introduces itself as vps-12345.localdomain, many receiving servers have a reason to treat the message with suspicion.
The PTR requirement is not a formality or the caution of a few picky servers. Gmail states it directly in its sender guidelines: the sending SMTP server’s public IP address must have a matching PTR record that resolves to a hostname, and the sender’s IP must match the IP that hostname resolves to in the forward record. This is the forward-confirmed reverse DNS (FCrDNS) mechanism: the IP is turned into a name through PTR, and then that same name must resolve back to the very same IP through an ordinary A record. Both directions have to agree.
This is not a purely theoretical requirement. Postfix can enforce it on incoming mail (in ready-made images these restrictions are usually off and need manual setup by the administrator, but there are plenty of receiving servers on the internet where they are on). The Postfix documentation describes it explicitly:
reject_unknown_reverse_client_hostnamerejects the request if the client IP address has no record mapping the address to a name.reject_unknown_helo_hostnamerejects the request if the name given in HELO/EHLO has no DNS A or MX record.reject_non_fqdn_helo_hostnamerejects the request if the name in HELO/EHLO is not given as a fully qualified domain name (FQDN) or an address literal.
So a missing or wrong PTR is not a myth and not a rarity but a documented and widely used reason for rejection on the receiving side. If your VPS still has a default PTR such as 123-45-67-89.example-provider.net while mail goes out in the name of your company’s domain, fix that first, through the provider’s control panel or by asking the provider’s support.
Checking blacklists (DNSBL): how it works and where beginners go wrong
A DNSBL (DNS-based blackhole list) is a way to find out whether an IP address is on a spam list using an ordinary DNS query. The octets of the IP address are reversed and appended to the zone name of a specific list. For example, for IP 1.2.3.4 and the Spamhaus ZEN zone, the query looks like 4.3.2.1.zen.spamhaus.org. The answer is read by its code:
- no answer or NXDOMAIN: the IP is not listed;
127.0.0.2: SBL, a direct source of spam;127.0.0.4: CBL/XBL, malware or botnet activity detected;127.0.0.10/127.0.0.11: PBL, an address range that should not send mail directly (often dynamic addresses or some VPS subnets).
A common trap in manual checks. If you query the Spamhaus zone with dig through a public DNS resolver, such as Cloudflare’s 1.1.1.1, which many VPS use by default, Spamhaus returns the code 127.255.255.254. We reproduced this on a test server. According to Spamhaus’s documentation, this answer means “the query came through a public/open resolver”, and it must not be treated as a confirmation of listing. Beginners regularly mistake this code for a real blacklisting and start fixing a problem that does not exist. Other public resolvers can behave the same way, so do not rely on them for DNSBL checks.
To check correctly with dig, query the zone’s authoritative servers directly rather than the default resolver:
dig +short NS zen.spamhaus.org
dig @ONE_OF_THE_RETURNED_NS REVERSED.OCTETS.OF.IP.zen.spamhaus.org
If you do not want to bother with dig, it is simpler and more reliable to use a web checker, for example mxtoolbox.com/blacklists.aspx. Such services query the zones directly and do not have the public-resolver problem. For regular automatic checks (rather than a one-off), the proper way with Spamhaus is to get a free DQS key instead of constantly querying their public mirrors. A one-off manual check through dig, as described above, is not intended for that kind of use.
A second trap, separate from Spamhaus: the SORBS list was shut down as a service by Proofpoint on June 5, 2024, and its zones are no longer maintained. If an old article or checklist recommends checking your IP against SORBS, that advice is outdated. The domain sorbs.net, which hosted the official zone, no longer resolves at all. A similarly spelled domain, sorbs.org, has been registered by someone else and has nothing to do with the original service. Its zone dnsbl.sorbs.org answers with the same IP address to literally any query, including a clearly random nonexistent subdomain, so it is not a DNSBL but a wildcard answer from an unrelated domain. The practical conclusion is to remove SORBS in any spelling from your checklists and settings. For checking any other blacklist zone with dig, there is a universal protection against this trap: a genuine DNSBL answer always lies in the 127.0.0.0/8 range. If a zone returns something outside it, or answers “found” even for a random nonexistent subdomain, do not trust that zone’s results.
IP reputation and “warming up” a new server
Even if the port is open, PTR is correct and the IP is clean on all blacklists, a new mail server can still land in spam simply because it has no sending history yet. Receiving services build the reputation of an IP and a domain from the volume and nature of the mail sent over time, and a sudden start with a large volume from an address with no history is typical spammer behavior.
Google directly recommends that senders increasing their volume start small, sending to engaged users first, and grow the volume gradually, avoiding sharp jumps. This is what “IP warm-up” means. It matters most for a new VPS with a new address that has no reputation history, which mail services trust less by default at first.
Shared IP addresses are a separate matter: it is common for a VPS provider to reuse addresses between customers. Gmail warns separately that the activity of any sender using a shared IP address affects the reputation of all senders on that address. If the IP was used before you by someone whose mailings were flagged as spam, its reputation may already be damaged, through no fault of yours. The practical conclusion: check blacklists and the reputation of a new IP right after you receive the address from the provider, before you start real sending, so you can tell someone else’s problem from your own.
One more documented factor to keep in mind when building email templates: Gmail warns against using HTML and CSS to hide content in messages. It can lead to the message landing in spam even when the rest of the technical setup is fine. As for other popular tips like “avoid spam trigger words” or a specific text-to-image ratio, these are more general industry practice than rules confirmed by official sources, so treat such advice accordingly, without blindly following the numbers.
Checklist: what to check, in order, if mail does not arrive
- Make sure SPF, DKIM and DMARC are set up and passing. This is the base without which the rest makes no sense.
- Check whether outbound port 25 is open:
nc -zv -w5 smtp.gmail.com 25. If it is closed, contact your provider’s support with a justification or switch to sending through an external SMTP relay on port 587 or 465. - Check your IP’s PTR record:
dig -x YOUR_IP +short. Make sure it points to a meaningful hostname and not to the provider’s default name. - Compare the PTR with what your mail server announces in HELO/EHLO (in Postfix,
smtp_helo_name/myhostname). The HELO/EHLO hostname should match what the PTR returns, and the PTR hostname in turn must resolve back to the same IP through an A record. Both directions must agree. - Check the IP against blacklists with a web checker (for example mxtoolbox.com/blacklists.aspx) or with
digdirectly against the zone’s authoritative name servers, not through a public resolver such as 1.1.1.1, otherwise you will get a false127.255.255.254from Spamhaus. Do not include SORBS (in any spelling of the domain) in your checks: the service has been closed since June 2024. - If you check manually with
dig, also run a control query for a random nonexistent subdomain of the same zone. A genuine DNSBL answers such a query with nothing. If the zone returns something outside127.0.0.0/8or “finds” even a random address, do not trust its results. - If the server is new, do not send a large volume of mail right away. Start small with engaged recipients and grow gradually.
- Check your messages for content hidden with HTML or CSS: Gmail warns separately that it can cause a message to land in spam.
Related
All articles
DKIM and DMARC on a VPS: How to Set Them Up So Your Emails Don’t End Up in Spam
Why you need DKIM and DMARC if SPF is already set up SPF answers one question: which IP addresses are allowed to send mail on behalf of a domain. That is only part of the protection. A receiving server can…
Your Own Mail Server on a VPS: Installing Postfix and Dovecot from Scratch
Running your own mail server makes sense when you need full control over email delivery on a company domain, want to understand how mail works at the protocol level, or simply do not want to depend on a third-party mail…