Skip to content
Skip to main content

Why SMTP ports 25 & 587 are blocked

Last updated:

Your code sends mail fine on your laptop, then you deploy to a cloud server and every send hangs until it times out. The connection to smtp.gmail.com on port 587 never opens, the logs show Connection timed out, and nothing in your app changed. This isn’t a bug in your mailer library. Your cloud provider is dropping the outbound SMTP connection on purpose.

This guide explains why providers block ports 25 and 587, how to confirm that’s what’s happening, and how to send mail over plain HTTPS so the blocked ports stop mattering at all.

Why are SMTP ports 25 and 587 blocked on cloud servers?

Section titled “Why are SMTP ports 25 and 587 blocked on cloud servers?”

Cloud providers block outbound SMTP because compromised or rented servers are the cheapest way to send spam at scale. AWS, Google Cloud, Microsoft Azure, DigitalOcean, and Oracle Cloud all restrict outbound connections on port 25 by default, and several throttle or block 587 too. The block protects the provider’s IP address reputation, since one abusive server can get an entire address range listed on a spam denylist.

Port 25 is the worst offender because it’s the server-to-server relay port with no required authentication, so it’s trivial to abuse from a hijacked instance. Spam remains a large share of all email traffic, and much of it originates from breached cloud hosts firing through open relays. AWS keeps port 25 throttled until you request a removal through a support form, and Google Cloud blocks outbound 25 permanently with no exception path. Ports 587 and 465 are the authenticated submission ports, so they’re treated more leniently, but providers still rate-limit them and can suspend an account that trips abuse heuristics.

Run a direct connection test from the affected server and watch whether the socket opens. The fastest check is nc -zv smtp.gmail.com 587: a working port returns succeeded in under 1 second, while a blocked port hangs for the full TCP timeout (often 20 to 130 seconds) before reporting Connection timed out. A blocked port never returns Connection refused, which is the tell that a firewall is silently dropping packets rather than rejecting them.

Test both ports from inside the deployed environment, not your local machine, because the block lives at the provider’s network edge. The command below uses netcat to probe port 25 and port 587 in sequence. If both hang, the provider is filtering outbound SMTP and no mailer configuration change will fix it. Switching to an HTTPS-based send is the only reliable workaround, which the next sections cover.

Send the message through an HTTPS REST API instead of opening an SMTP socket. The Nylas Email API exposes POST /v3/grants/{grant_id}/messages/send, which accepts a JSON payload over port 443 and relays the message through Gmail, Microsoft 365, Yahoo, or any connected IMAP provider. Because the call rides on standard HTTPS, no cloud firewall blocks it, and you skip SMTP authentication, TLS negotiation, and connection pooling entirely.

The request below posts a subject, body, and to array, then the API delivers it through the provider attached to the grant. Port 443 is open on every cloud platform by default, so this same call works unchanged from AWS Lambda, a Kubernetes pod, or a DigitalOcean droplet. Attachments under 3 MB go inline in the JSON; larger payloads use multipart/form-data up to the 25 MB provider limit. For the full migration path off SMTP, see send email without SMTP.

SMTP and a REST API both deliver mail, but they fail in different places on a cloud host. SMTP needs an open outbound port, a TLS handshake, and credentials your code holds, and any one of those breaking means a silent timeout. The REST API moves all of that behind a single HTTPS call on port 443, so the only thing that can fail is a 4xx response you can read and retry. The table below maps the two approaches across the friction points that matter in production.

ConcernDirect SMTPNylas Email API
Transport port25, 465, or 587 (often blocked)443 (HTTPS, always open)
Cloud firewallBlocked by AWS, GCP, Azure by defaultNo block, runs over HTTPS
AuthPer-provider SMTP credentialsOne API key plus a grant
Retry safetyManual, risks duplicate sendsIdempotency-Key, cached 1 hour
ProvidersOne SMTP config per providerGmail, Microsoft 365, Yahoo, IMAP

How do I send email from a Docker container without SMTP?

Section titled “How do I send email from a Docker container without SMTP?”

Call the send endpoint over HTTPS from inside the container and skip SMTP entirely. A Docker container inherits the host’s outbound network rules, so if the host’s port 587 is blocked, the container’s is too, and localhost mail relays add a sendmail daemon you then have to run and monitor. A single POST to /v3/grants/{grant_id}/messages/send over port 443 needs no extra process and no exposed mail port in your Dockerfile.

Pass the API key and grant ID as environment variables at runtime rather than baking them into the image, which keeps secrets out of layers that might get pushed to a registry. The container only needs outbound 443, which is already allowed for pulling images and calling other APIs. This pattern scales cleanly to multi-replica deployments because there’s no shared SMTP connection pool to coordinate. The send email from Docker guide covers the full container setup, including the environment variable wiring.

How do I send email from a bash script or cron job?

Section titled “How do I send email from a bash script or cron job?”

Use curl to post the message in a single command, with no mailer binary to install or configure. A cron job that pipes output to mail depends on a local MTA like Postfix or sendmail being installed, running, and able to reach an unblocked SMTP port, which fails on most cloud hosts. A curl call to the send endpoint over HTTPS has none of those dependencies and returns a JSON response you can log or alert on.

Cron runs with a minimal environment, so load credentials from a file the script sources rather than relying on the shell profile, and check curl’s exit code so a failed send doesn’t pass silently. Each send is independent, so a job that runs every 5 minutes never needs a persistent connection. To avoid duplicate mail when a retried job re-runs, add an Idempotency-Key header; the API caches the result for 1 hour per grant, so a replay returns the original response instead of sending twice. The transactional send guide details idempotency and delivery tracking for automated jobs like these.

When is direct SMTP still the right choice?

Section titled “When is direct SMTP still the right choice?”

Direct SMTP makes sense when you control the network and the sending reputation yourself. If you run on dedicated hardware or a colocated server where outbound 25 and 587 are open, and you’ve already warmed a dedicated IP address with proper SPF, DKIM, and DMARC records, a self-hosted Postfix relay gives you full control with no per-message cost. High-volume senders with a dedicated deliverability team often prefer that ownership.

That tradeoff stops paying off the moment a cloud provider sits between your code and the internet. On AWS, GCP, or Azure, you’d spend engineering time fighting port blocks, requesting throttle removals, and monitoring an MTA, all before you send a single production message. An HTTPS send removes that work, and one grant reaches Gmail, Microsoft 365, Yahoo, and IMAP through the same call, so adding a provider later costs no new SMTP configuration.