SMTP protocol

SMTP, the Simple Mail Transfer Protocol, is the standard that moves mail between servers. It is defined in RFC 5321. SMTP only sends and relays. Retrieving mail into a mailbox is a different job handled by IMAP or POP, which is the distinction most people miss when they first read an SMTP error and assume their inbox is broken.

VerifiedBy Kam Low, Co-founder·Updated

How SMTP works

An SMTP transaction is a short conversation between two machines. A client opens a TCP connection to a server, identifies itself, names the sender, names each recipient, then transmits the message body. The server replies to every command with a three-digit code that says whether it accepted, temporarily deferred, or permanently rejected what it was given.

Those codes are the protocol's real interface. Acceptance comes back as 250. The 4xx range means try again later, and a well-behaved sender does exactly that on a backoff. Anything in the 5xx range means stop, because retrying a permanent failure is how a sender turns one bad address into a reputation problem.

Connection

The client opens a TCP connection to the server's listening port. Modern practice is implicit TLS on port 465 or an explicit upgrade via STARTTLS on port 587, both covered in RFC 8314, which recommends implicit TLS for message submission.

A submission connection is authenticated. The server asks the client to prove it is allowed to send, usually with a username and password over an encrypted channel. Relay without authentication is what open relays did, and it is why mail from them is now rejected on sight.

Our own relay shows what locked-down SMTP ingress looks like in practice. It accepts mail only from our authenticated Rails control plane on TCP 2525, after SES has accepted and validated the inbound message, and it persists exactly one durable single-recipient delivery obligation before forwarding to the customer's captured pre-cutover MX host over TCP 25. TCP 2525 is firewall-restricted to our API host. TLS and exact SMTP authentication are mandatory, every one-recipient route and MX snapshot is HMAC-signed, and arbitrary destinations, mail loops back into our own MX, extra recipients and replayed requests are rejected. SRS and VERP correlate the DSNs that come back, ARC preserves the validated ingress authentication, and Rspamd checks the relay traffic.

Greeting

The client opens with HELO, or more commonly EHLO, and its own hostname. EHLO is the extended form: the server answers with the list of extensions it supports, which is how the client learns whether STARTTLS, authentication mechanisms, size limits, or pipelining are available before it commits to anything.

A greeting is also the first reputation signal in the transaction. The hostname a client announces should resolve, and its reverse DNS should match, because receiving servers check.

EHLO responses are the negotiation surface for everything that follows. A server advertising SIZE declares its maximum message length, PIPELINING allows commands to be sent without waiting for each reply, and 8BITMIME signals that the body need not be restricted to 7-bit ASCII. A client that ignores these advertisements and assumes defaults will fail against strict servers.

Transfer

The message itself moves in three commands. MAIL FROM sets the return path, the address bounces go back to. RCPT TO names one recipient, repeated per recipient. DATA transmits headers and body, terminated by a single dot on its own line.

The return path in MAIL FROM is not the From header the reader sees. They are different addresses with different jobs, and conflating them is behind a large share of misrouted bounce handling.

The visible From has its own failure mode. We advise always sending from a subdomain, send.yourdomain.com, never the bare apex or primary domain. When a custom MAIL FROM is not registered, our Email::Sender falls back the visible From address to the sending subdomain, hello@send.yourdomain.com for example, while the Reply-To stays on the apex domain. A support ticket taught us how that renders: Gmail shows a bare hello with no display name, which is exactly the header mismatch this layer produces when configuration is half done.

Delivery

After accepting a message, the receiving server looks up the recipient domain's MX records and passes the message on, or delivers it locally if it is the final destination. Bounces are reported asynchronously as a DSN sent back to the return path, which is why a failure can arrive minutes or days after a successful send.

We hit this asynchrony inside our own pipeline. SES runs a suppression-list preflight, and when it flags a recipient the send fails without ever reaching SMTP. We record that per-recipient failure context in the send logs and campaign progress rather than raising an operator alert, because a suppressed address is information about the recipient, not an outage.

A message can be accepted, relayed, and still never reach an inbox. Placement is decided by the receiving mailbox provider on reputation, authentication and engagement, well after SMTP has finished.

Chong, on our team, keeps a practical rule for that layer: verify the customer's apex domain separately with the provider so it becomes a trusted domain as well. It reads as redundant next to a verified sending subdomain, and it measurably helps deliverability.

Common ports

Three ports carry almost all SMTP traffic, and they are not interchangeable. The registry is IANA's service name and port number assignments.

Port 587 is the submission port and the correct default for an application sending mail. It expects authentication and a STARTTLS upgrade, specified in RFC 3207.

Port 465 is implicit TLS submission. The connection is encrypted before any SMTP command is sent. It was deprecated, then reinstated by RFC 8314 as the recommended submission port, which is why advice written between those two dates contradicts itself.

Port 25 is server-to-server relay. It is not a submission port, and most residential and cloud providers block outbound 25 by default to limit spam. An application trying to send on port 25 from a hosting environment is the single most common cause of a send that hangs with no error.

We are not immune ourselves. Chong once traced a dead send in our own app to exactly this, the app pointed at the wrong SMTP port, and fixed it after inviting his own personal email to test. The protocol does not error helpfully when the port is wrong. It just waits.

Why a fifty-year-old protocol is still underneath everything

Email is the cockroach of the internet, and that is meant admiringly. It has outlived every platform that was going to replace it, and after many years working on it the recent resurgence of interest is genuinely satisfying to watch.

The conversation ends at "accepted" Outside the protocol
EHLO app.acme.com
MAIL FROM:<[email protected]>
DATA … .
250 2.0.0 accepted · queued
Delivered? the protocol does not say
Opened? a different layer entirely
Bounced later? arrives as new mail, not a reply
retry, do not bounce: 408 · 409 · 425 · 429 · any 5xx
SMTP guarantees one thing: the server accepted. Everything an application wants to know happens after the conversation ends.

The reason it persists is the reason it frustrates: it is federated and nobody owns it. Any server can talk to any other, which is why email still works across organisations that agree on nothing else, and also why delivery is a negotiation rather than a guarantee.

That is also why we built Nitrosend the way we did. We are not really inventing a new communication protocol here. It is all email. The work goes into the layers the protocol leaves open. Before we switched our sending over to SES I finished the deliverability layer and the DNS layer first, because the day we were approved our cap was 50,000 sends per day, and at that size one big sender could have parked the whole queue for days.

What the protocol gives an application is narrow. It confirms a server accepted a message and stops there. Everything an application actually wants to know, whether the message was delivered, whether it was read, whether it bounced an hour later, sits outside the conversation entirely.

That narrowness is why our REST API sits on top. A single transactional email or SMS queues with one POST to /v1/my/messages, and our normal background sender handles the SMTP conversation, the retries and the bounce correlation for you.

Retry semantics are where this bites hardest in practice. Classifying which failures are transient and worth retrying is a decision the protocol pushes onto you, and getting it wrong in either direction is costly. Our own adapters classify HTTP 408, 409, 425, 429 and any 5xx as retryable and everything else as terminal, because retrying a permanent failure is how you turn one bad address into a reputation problem.

Timing matters as much as classification. If a transactional email fails, you do not want it auto-sending a day later, even where automatic unblocking exists, unless the recovery window is short. A password reset that arrives on Tuesday for a request made on Monday is worse than one that never arrives, because the user has already solved their problem another way and now has a live reset link in their inbox.

Go deeper

First send in thirty seconds.

Simple pricing. Unlimited contacts.

Every plan includes full stack emailing: Flows, Newsletter Campaigns and Transactional Email, plus our NitroWheel LLM and all agent integrations (Claude, ChatGPT, Codex, Cursor and others). Pay for what you send, not who you store.

Free
$0
forever
  • Emails 8,000then 500/mo
  • Email types Transactional & Marketing
  • AI actions 20/mo
  • Contacts Free & Unlimited
  • Brands 3 · Custom domain 1
  • Seats 1
  • Recipients / rolling 24h 100–5,000
  • Email validation Prepaid only
Start free
Ultra
$100
per month
  • Emails 125,000/month
  • AI actions 5,000/mo
  • Brands 10 · Domains 10
  • Seats 10
  • Frontier AI Included
  • Dedicated IP Available
  • Recipients / rolling 24h 1,000–625,000
  • Email validation Prepaid only
Get started
Enterprise
$300
per month
  • AI actions Unlimited
  • Unlimited brands & domains Included
  • SSO / SAML Included
  • 99.9% SLA Included
  • Recipients / rolling 24h Contracted
  • Email validation Prepaid only
Get started

Daily allowances depend on your plan and sender standing. Strong list, domain and delivery evidence can raise standing, including on day one. Trusted receives the full plan allowance; available email credits, safety checks and delivery pacing still apply.

Free forever. No credit card required. See full comparison →