DEV Community

Cover image for When Your VPS Blocks Outbound SMTP: What Actually Helps
Schiff Heimlich
Schiff Heimlich

Posted on

When Your VPS Blocks Outbound SMTP: What Actually Helps

You spin up a VPS, install Gitea, and realize it needs to send email. You point it at port 25. Nothing happens. You try 587. Still nothing. Your provider is blocking outbound SMTP and they may not advertise it.

This comes up often enough that it's worth having a clear picture of what's happening and what the actual options are.

Why VPS Providers Block SMTP Outbound

DigitalOcean, AWS Lightsail, Linode, Vultr — they all block port 25 by default. Some block 587 too, or at least rate-limit it heavily. The reason is legitimate: open relays on port 25 are the backbone of spam, and a single compromised VPS can become a spam relay before you notice. Providers block it to protect their IP reputation and avoid getting listed.

The catch is that this affects self-hosted apps — Gitea, Ghost, Mastodon, Umami, anything that needs to send transactional email — without necessarily telling you upfront.

The Workarounds

1. Use a Transactional Email Service with Their SDK

Postmark, Resend, Mailgun, AWS SES — they all expose an HTTP API. Point your app at their API instead of SMTP and the port blocking becomes irrelevant. Most modern self-hosted tools support this natively.

The tradeoff: you're adding another service dependency, another API key to manage, and if you're self-hosting six different apps, you're copying that API key into six different config files.

2. Use an Alternate SMTP Port

Some providers unblock port 465 (SMTP over SSL) or port 587 (submission) if you open a support ticket. It's worth asking. This won't help if the block is at the network level rather than the port level, but it's the low-effort first step.

3. Run a Mail Relay Gateway

This is where something like Posthorn helps. You deploy one container inside your network, configure it once with your transactional email provider credentials, and every app on your server points to it over localhost — which bypasses the outbound port restrictions entirely.

Posthorn accepts SMTP from your apps locally, then relays to Postmark, Resend, Mailgun, or SES over HTTP. It handles retries, honeypot filtering, and per-app rate limiting from a single TOML config. The provider credentials live in one place, not duplicated across your stack.

If you're running Gitea, Ghost, a contact form, and a cron job that sends digests — they all point to localhost:25 and you never touch the blocked port.

Which Approach to Use

If you have one or two apps that support HTTP APIs directly, just configure the SDK. No need to add infrastructure.

If you're running a stack of self-hosted tools that only speak SMTP, a local relay gateway is the cleaner solution. It keeps your provider credentials in one config file and sidesteps the port problem without needing to petition your host.

The port blocking isn't going away. It's a reasonable spam control measure. The workaround is to route around it at the application layer, which is a lot less painful than it sounds once you have one thing in the middle handling it.

Top comments (0)