Why Transactional Email From a VPS IP Dies
Transactional mail from a new VPS IP often never reaches the inbox. This post covers blocklists, missing PTR, port 25, and when an ESP is the only path.
Netbay Engineering
Netbay Engineering
On this page
Password resets, invoice PDFs, and magic links are not marketing. They are the mail your product has to send. Teams still point nodemailer or Django at 127.0.0.1 port 25 on the same VPS that runs the app, then watch Gmail junk the message or return 550 5.7.1. The framework did not fail. Large receivers treat unknown datacenter IPs as untrusted, and a freshly issued VPS address has no sending history at all.
What receivers actually check
A receiving MX does not read your product copy. It scores the TCP session before it scores the body.
- Reverse DNS for the connecting IP, and whether that PTR matches the HELO name and a matching A record (forward-confirmed reverse DNS).
- Whether the IP sits on Spamhaus, Barracuda, SORBS, or a dozen smaller lists. Cloud ranges appear on policy lists even when you have never sent spam.
- SPF on the envelope sender, DKIM on the signed headers, and DMARC alignment for the visible From domain.
- Volume, complaint rate, and unknown-user rate if you already have any history on that IP or domain.
Fail two of those and the message is junk or rejected. Fail IP reputation and the authentication records never get a fair reading.
Datacenter IPs start in the hole
Consumer broadband IPs are not automatically trusted, but they are at least familiar to inbox providers. Datacenter ranges are the opposite. They host scanners, botnets, and throwaway bulk senders. Gmail, Outlook, and Yahoo apply a higher bar before they accept mail from those ranges. A Lucknow DC01 address on Intel Xeon Platinum hardware with High-Speed SSD storage and L3/L4 DDoS filtering is a solid application node. It is not, by itself, a mail node those inboxes have seen before.
Reused IPs are worse. The address assigned this morning may have been listed last month. That debt travels with the number, not with your customer account. Always check the IP the day you get it, before you send a single reset mail.
Port 25 is the other silent killer
Outbound TCP 25 is how SMTP reaches a public MX. Many networks block it to cut abuse. If this VPS cannot open 25 to a remote mail exchanger, local Postfix queues forever and your app still thinks sendMail succeeded. Test the path the day you provision the box, before you design around direct delivery.
nc -vz gmail-smtp-in.l.google.com 25
dig -x 203.0.113.40 +short
host 203.0.113.40
IP=203.0.113.40
REV=$(python3 -c "print('.'.join(reversed('$IP'.split('.'))))")
dig +short $REV.zen.spamhaus.org A
dig +short $REV.bl.spamcop.net AAn empty dig answer is the only result you want from those list zones. Any A record means the IP is listed and Gmail will not give you the benefit of the doubt.
The application code is not the bottleneck
This is the pattern that dies quietly:
const nodemailer = require("nodemailer");
const transport = nodemailer.createTransport({
host: "127.0.0.1",
port: 25,
secure: false,
name: "app.example.com"
});
function sendReset(to, url) {
return transport.sendMail({
from: "noreply@example.com",
to: to,
subject: "Reset your password",
text: "Open this link: " + url
});
}The SMTP conversation succeeds locally. The remote MX then rejects, greylists, or silently junks. Your logs show 250 because the local MTA accepted the message, not because a human read it. Until you watch bounce logs and a real inbox, you do not have delivery.
What actually works
Pick one of three honest designs.
- Send transactional mail through an ESP (Amazon SES, Mailgun, Postmark, or similar) over authenticated submission on port 587. Their IPs are warmed and monitored.
- Relay the VPS through that ESP as a smarthost so cron and existing app mail still work without teaching every process a new SDK.
- Send directly only if you control PTR, SPF, DKIM, DMARC, a dedicated IP, and a weeks-long warmup, and you accept that Gmail may still throttle you.
Direct send from a new VPS IP is the hardest of the three. Netbay does not sell a managed mailbox or outbound filter. You get a static IP in Lucknow and a Linux or Windows VPS you control. That is enough to run an MTA. It is not enough to skip reputation work.
Warmup is not folklore. Start at a few dozen messages a day to addresses that will open and not complain. Double slowly. A burst of password resets to unengaged users on day one looks like a harvested list. Inbox providers do not distinguish "our app launched" from "this IP just joined a botnet."
Takeaway
Transactional mail dies on VPS IPs because receivers score the IP first. Fix identity (PTR, HELO, SPF, DKIM, DMARC) and still prefer an ESP for anything a user must actually read. You can spin up an Ubuntu 24.04 instance on Netbay in under 60 seconds and run the port-25 and blocklist checks above — netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance