# RFC 5321 — SMTP: The Transport Protocol

> Deliverability-focused digest of SMTP: session model, envelope vs. content, reply-code semantics, null sender, retry rules, size limits, and timeouts.

Source: emailmarketing.net — https://emailmarketing.net/learn/rfc/rfc5321-smtp

Every time a receiving server accepts, defers or rejects your mail, it answers in the terms of one protocol. RFC 5321 defines how mail moves between hosts, and every bounce code, retry policy and envelope identity used in deliverability work comes from it.

For the vocabulary around it (MTA, MSA, ADMD and so on), see [RFC 5598: Internet Mail Architecture](https://emailmarketing.net/learn/rfc/rfc5598-email-architecture). For the message inside the envelope, see [RFC 5322: Message Format](https://emailmarketing.net/learn/rfc/rfc5322-message-format).

## Session model

An SMTP session is a lock-step dialog, one command at a time. Extensions such as PIPELINING relax this when both sides agree.

| Step | Client sends | Server success reply |
|---|---|---|
| Connect | (TCP connection) | `220` greeting |
| Identify | `EHLO client-hostname` (fallback `HELO`) | `250` and the list of extensions |
| Envelope sender | `MAIL FROM:<reverse-path>` | `250` |
| Envelope recipient(s) | `RCPT TO:<forward-path>` (one per recipient, repeatable) | `250` (or `251` forwarded) |
| Content | `DATA` | `354`, then the message, ended by `<CRLF>.<CRLF>`, then `250` |
| End | `QUIT` | `221` |

Other commands: `RSET` (abort the current transaction), `VRFY` and `EXPN` (address verification, widely disabled or answered with `252` to prevent address harvesting), `NOOP` and `HELP`.

- A rejection at `MAIL FROM` or `RCPT TO` costs the receiver nothing for each message. A rejection after `DATA` means the receiver has already accepted the bytes. Many providers leave their final judgment (content filtering) to the reply after `DATA`, so a `5xx` after the final dot is a rejection for content or reputation, not an address problem.
- The `EHLO` hostname is an identity signal. Receivers commonly check that it is a fully qualified domain name (FQDN) that resolves, and that it is consistent with the reverse DNS (rDNS) of the connecting IP address. RFC 5321 requires it to be the client's primary host name (or an address literal when there is none).

## Envelope vs. content

The **envelope** is the addressing at the protocol level: one reverse-path (`MAIL FROM`) and one or more forward-paths (`RCPT TO`). The **content** is everything sent inside `DATA`: the header section and the body (governed by [RFC 5322](https://emailmarketing.net/learn/rfc/rfc5322-message-format)).

These consequences come up constantly in deliverability:

- The address people see (the `From:` header) and the address bounces go to (`MAIL FROM`, recorded at delivery as `Return-Path:`) are independent. SPF authenticates the envelope `MAIL FROM`, and DMARC then tests whether it aligns with the header `From:` (see [DMARC](https://emailmarketing.net/learn/authentication/dmarc)).
- Recipients in `RCPT TO` do not need to appear in `To:` or `Cc:`. This is how Bcc and list expansion work.
- Relays MUST NOT modify the envelope addresses or the meaning of the message. They only add trace fields at the top (`Received:`, and the final delivery agent adds `Return-Path:`).

## Reply codes

A reply code has three digits. The text after the code is for people, and the number is the contract.

| First digit | Class | Sender behavior |
|---|---|---|
| `2yz` | Positive completion | The action succeeded; proceed |
| `3yz` | Positive intermediate | Send more (only `354` in base SMTP) |
| `4yz` | Transient negative | The failure may clear; **retry later, unchanged** |
| `5yz` | Permanent negative | **Do not retry the same request**; bounce and suppress |

The second digit gives the category: `x0z` syntax, `x2z` connections, `x5z` mail system status. Modern servers add RFC 3463 enhanced status codes (such as `5.7.1`) after the three-digit code for a finer diagnosis.

Key codes:

| Code | Meaning |
|---|---|
| `220` | Service ready (greeting) |
| `221` | Closing channel (after QUIT) |
| `250` | Requested action OK or completed |
| `251` | User not local; will forward to `<forward-path>` |
| `252` | Cannot VRFY user, but will accept and attempt delivery |
| `354` | Start mail input; end with `<CRLF>.<CRLF>` |
| `421` | Service not available, closing channel (also used for rate limiting and for deferrals like greylisting) |
| `450` | Mailbox unavailable (temporary, for example busy or greylisted) |
| `451` | Local error in processing; retry later |
| `452` | Insufficient system storage, or too many recipients; retry |
| `455` | Server unable to accommodate MAIL parameters now |
| `500`–`504` | Syntax error, command not implemented, or bad parameters |
| `550` | Mailbox unavailable (permanent: unknown user, or rejection for policy) |
| `551` | User not local; try `<forward-path>` |
| `552` | Exceeded storage allocation (message too big for the mailbox) |
| `553` | Mailbox name not allowed (bad address syntax) |
| `554` | Transaction failed (no valid recipients, or rejection for content or policy) |
| `555` | MAIL FROM or RCPT TO parameters not recognized |

In practice, receivers are free to use any code with any text. `4xx` deferrals ("try again later", "unusual rate of mail") are the standard soft signal that a provider is throttling you for reputation, and the text of a `550 5.7.x` reply carries the provider's actual reason. Always log the full reply text, not only the code.

## Null reverse-path (`MAIL FROM:<>`)

- Delivery status notifications (bounces) and other notifications that the mail system generates MUST be sent with a **null reverse-path**, `MAIL FROM:<>`, so that a failed bounce can never generate another bounce (loop prevention).
- Servers MUST accept `MAIL FROM:<>`. Rejecting the null sender breaks bounce handling and does not comply with the standard (although some spam filters score it).
- A message received with a null reverse-path must never itself be answered with a DSN to that path.
- In practice, any address you use in `MAIL FROM` must be able to receive mail, for bounce processing. The null sender is only for notifications, never for regular sending.

## Retry expectations (Section 4.5.4)

- After a `4xx` or a connection failure, the sender queues the message and retries. The retry interval SHOULD be at least **30 minutes** for each destination (a strategy that shortens this when the first attempt failed in the middle of the connection is permitted).
- The time before giving up generally needs to be **at least 4–5 days**. After that, a permanent failure notification goes to the reverse-path.
- Retries MUST be tracked for each destination host or address, and exponential backoff is encouraged. Repeatedly hitting a host that is deferring you is itself a reputation signal.
- On a `5xx`, the sender MUST NOT retry the same message to the same address, and generates a non-delivery notification instead. For list hygiene, suppress hard bounces immediately, and suppress soft bounces after repeated failures across the retry window.
- If several MX hosts exist, the client tries them in order of preference (lowest MX value first) before deferring.

## Size limits (Section 4.5.3.1 — minimums implementations MUST handle)

| Object | Minimum capacity |
|---|---|
| local-part | 64 octets |
| domain | 255 octets |
| path (`<...>` including punctuation) | 256 octets |
| command line (including CRLF) | 512 octets |
| reply line (including the code and CRLF) | 512 octets |
| text line (including CRLF) | 1000 octets |
| message content | at least 64K octets; no fixed ceiling, and the limit is advertised through the `SIZE` extension (RFC 1870) |

Exceeding a receiver's declared limits draws a `552` (for the message) or a `500` (for a line or command). In modern practice, check the `SIZE=` value in the EHLO response before sending large messages.

## Timeouts (Section 4.5.3.2: minimum client-side waits)

| Waiting for | Minimum timeout |
|---|---|
| Initial `220` greeting | 5 minutes |
| `MAIL` reply | 5 minutes |
| `RCPT` reply | 5 minutes |
| `DATA` reply (`354`) | 2 minutes |
| Each data block accepted | 3 minutes |
| Reply to final `<CRLF>.<CRLF>` | **10 minutes** |
| (Server side) inactivity | 5 minutes |

The 10-minute wait at the end of data matters. Providers deliberately delay their verdict after DATA while they filter, and clients that hang up early cause duplicate deliveries: the server delivers the message, and the client retries it.

## Related articles

- [RFC 5322: Message Format](https://emailmarketing.net/learn/rfc/rfc5322-message-format), on what goes inside `DATA`
- [RFC 5598: Internet Mail Architecture](https://emailmarketing.net/learn/rfc/rfc5598-email-architecture), on who runs each hop
- [DMARC](https://emailmarketing.net/learn/authentication/dmarc), on how envelope and header identities are authenticated and aligned
