Guide
Why Cloud Servers Block SMTP Ports
AWS, GCP, and Azure block outbound SMTP port 25 to stop spam, while ports 587 and 465 stay open. Confirm the block and send email over an API instead.
Written by Caleb Geene Director, Site Reliability Engineering
Which SMTP ports do cloud providers block?
Cloud providers block outbound port 25, the SMTP relay port defined in RFC 5321. Some also throttle the submission ports. Port 587 is the message submission port from RFC 6409, and port 465 is implicit-TLS submission. Port 25 carries server-to-server relay, which is the path spammers abuse, so it draws the hardest block.
The three big providers differ in detail. Google Cloud blocks outbound port 25 on all VMs with no exception and never lifts it. AWS EC2 throttles port 25 by default and removes the limit only after you file a request. Azure blocks port 25 outbound on most subscription types created after November 2017. The reason is the same across all three: spam control and protecting the shared IP ranges those VMs sit on. According to the Azure outbound SMTP connectivity docs (the page may return a WAF challenge to non-browser clients but loads fine in a browser), the recommended path is an authenticated relay rather than raw port 25.
| Port | Role (RFC) | Cloud status |
|---|---|---|
25 | SMTP relay (RFC 5321) | Blocked or throttled on GCP, AWS, Azure |
587 | Message submission (RFC 6409) | Open; GCP explicitly permits it |
465 | Implicit-TLS submission | Open; GCP explicitly permits it |
443 | HTTPS (API send) | Always open |
Why do providers block port 25?
Providers block port 25 to protect the reputation of the IP ranges their VMs share. A single compromised instance sending spam can land an entire subnet on blocklists like Spamhaus, which then bounces mail for every other tenant on that range. Blocking relay at the network edge stops one bad actor from poisoning the pool.
This is a deliberate design choice, not a misconfiguration you can fix in a security group. Google states it plainly in the Compute Engine sending email tutorial: "connections to destination TCP Port 25 are blocked when the destination is external to your VPC network." The same page notes Google "does not place any restrictions" on ports 587 or 465, then points you at a partner relay or an API. New cloud accounts also start with a fresh IP that has no sending history, so even on an open port, deliverability suffers until that IP earns a reputation over weeks of consistent, low-complaint volume.
How do I confirm the port is blocked?
Test the connection with nc -zv (netcat in zero-I/O scan mode). It opens a TCP connection and reports whether the port accepts it. On a blocked port the command hangs until it times out, usually after the default 75-second TCP connect timeout, then prints a timeout error. On an open port it returns succeeded in well under a second.
Run both checks below from the affected VM. The first targets Gmail's relay port 25, which a cloud provider almost always blocks, so it stalls and times out. The second targets submission port 587, which is frequently reachable. Comparing the two tells you whether the block is port-specific or a wider firewall rule. Add -w 5 to cap the wait at 5 seconds instead of the 75-second default.
# Relay port 25 -- typically blocked on cloud VMs (hangs, then times out)
$ nc -zv -w 5 smtp.gmail.com 25
nc: connect to smtp.gmail.com port 25 (tcp) failed: Connection timed out
# Submission port 587 -- often reachable
$ nc -zv -w 5 smtp.gmail.com 587
Connection to smtp.gmail.com 587 port [tcp/submission] succeeded!A timeout (not a refusal) is the signature of a network-level block: the provider silently drops the packets, so the connection never completes. A fast Connection refused instead points at the destination, not your provider. If port 25 times out and 587 also times out, the provider is filtering both submission and relay, and an HTTPS send is the only reliable path left.
How does an HTTPS API send bypass the block?
An email API accepts your message over HTTPS on port 443 and relays it from infrastructure that owns warmed, authenticated sending IPs. Port 443 is never blocked, because it carries ordinary web traffic, so the SMTP port rules simply don't apply. Your VM makes one outbound TLS request and the provider handles relay, retries, and reputation.
This is why nylas email send works on a locked-down EC2 or Compute Engine instance where a raw SMTP script hangs. The command posts the message to the Nylas API over port 443; the CLI never opens a connection to port 25 or 587. The send below uses --to, --subject, --body, and --yes to skip the confirmation prompt on a headless VM. It completes in roughly a second versus the 75-second hang of a blocked SMTP connect.
nylas email send \
--to alerts@example.com \
--subject "Nightly backup complete" \
--body "Backup finished at $(date -u) with 0 errors." \
--yesBecause the request rides HTTPS, the same command runs unchanged on any of the three blocked clouds. There's no relay host to configure, no app password to mint, and no port to open in a security group. The provider behind the API owns the SPF, DKIM, and DMARC alignment that a fresh VM IP would otherwise lack.
How do I script and parse the send?
Wrap the same command in a cron job or deploy hook and capture its output. The tool sends over port 443, so it behaves identically inside a CI runner, a container, or a bare VM. For machine-readable output you pipe the result into jq, the standard JSON processor, to confirm a message ID came back.
The snippet below sends a deploy notification, then extracts the returned message identifier so a pipeline step can log or assert on it. A successful send returns a JSON object with the message id and a UTC date; a blocked SMTP path, by contrast, returns nothing for 75 seconds and then an error. The shape below is illustrative of the fields you read, not a literal API contract.
# Send, then pull the returned message id for logging
nylas email send \
--to oncall@example.com \
--subject "Deploy $(git rev-parse --short HEAD) live" \
--body "Release shipped to production." \
--yes \
--format json \
| jq -r '.id // "send-failed"'
# Example response shape the command prints:
# {
# "id": "msg_01j8...",
# "thread_id": "thr_01j8...",
# "date": "2026-06-19T14:00:00Z"
# }When should I keep SMTP vs use the API?
Keep SMTP only when you control the network path and the sending IP reputation: an on-prem mail server, a dedicated relay on an unblocked IP, or a legacy app that can't change its transport. Use an HTTPS API whenever you're on a cloud VM, in CI, or in a container, because those environments block port 25 by policy and start with a cold IP.
The trade-off is who owns deliverability. With raw SMTP you own relay configuration, TLS negotiation, retry logic, and the multi-week IP warm-up before mail reliably reaches the inbox. With the API path you own one outbound HTTPS call, and the provider owns relay, retries, and authentication alignment. For a backup notification, a deploy alert, or any transactional message from a cloud host, the API removes the one variable the cloud provider has already taken out of your hands: the SMTP port itself. See email API vs SMTP for the full comparison.
Next steps
- Email API vs SMTP -- when each transport wins, with a side-by-side feature table
- Send email from Python without SMTP -- skip smtplib entirely and post over HTTPS
- Send email from the terminal -- the full
nylas email sendwalkthrough with flags, output formats, and tracking - Gmail SMTP settings -- host, ports, and app passwords when you do need SMTP
- Outlook SMTP settings -- Microsoft 365 SMTP AUTH and port details
- Full command reference -- every email, calendar, and contact command
- RFC 6409: Message Submission for Mail -- the IETF standard that defines port 587 submission versus port 25 relay