← RFC Reference

How SMTP Really Works

Email Concepts Encyclopedia
ELI5: Sending an email is like sending a registered letter. First you look up the address (DNS), then you walk to the post office and announce yourself (EHLO). The clerk checks your ID (AUTH), you hand over the envelope info (MAIL FROM, RCPT TO), then the letter itself (DATA). The clerk stamps it accepted or tells you what went wrong with a numbered code. The whole thing happens in plain text over a TCP connection.

A complete walkthrough of an SMTP transaction — from DNS lookup to final delivery. If you send email programmatically, this is the mental model you need.

The Big Picture

SMTP — the Simple Mail Transfer Protocol — is the protocol that moves email across the internet. Defined in RFC 5321, it has been the backbone of email since 1982 (the original RFC 821). Despite decades of extensions, the core transaction is still a short, synchronous text conversation between two servers over TCP port 25.

Every email delivery follows the same sequence:

  1. DNS lookup — find the recipient's mail server
  2. TCP connection — connect to port 25 (or 465/587 for submission)
  3. Banner & EHLO — exchange identities and capabilities
  4. STARTTLS — upgrade to encrypted connection (usually)
  5. AUTH — authenticate if submitting (port 587)
  6. Envelope — MAIL FROM and RCPT TO
  7. DATA — transmit the message headers and body
  8. QUIT — close the connection

Step 1: DNS — Finding the Mail Server

Before any SMTP conversation begins, the sending server must discover where to deliver the message. It queries DNS for MX records on the recipient's domain.

$ dig +short MX example.com
10 mx1.example.com.
20 mx2.example.com.

The number is the priority (lower = preferred). The sender tries mx1.example.com first. If it is unreachable or returns a temporary error, the sender falls back to mx2.example.com.

If no MX records exist, the sender falls back to the domain's A or AAAA record — but this is a last resort. If an explicit Null MX record exists (0 .), the domain does not accept mail at all. See DNS and Mail Routing for the full algorithm.

Step 2: TCP Connection and the Banner

The sender opens a TCP connection to port 25 of the MX host. The receiving server speaks first with a 220 banner:

# Server speaks first
220 mx1.example.com ESMTP ready

The 220 status code means "service ready." If the server is overloaded, it may respond with 421 (service not available) and close the connection. The sender should retry later.

For message submission (a user's mail client sending through their provider), the connection goes to port 587 (RFC 6409) or port 465 (implicit TLS, RFC 8314) instead of port 25.

Step 3: EHLO — Announcing Capabilities

The sender introduces itself with EHLO (Extended HELO), providing its own hostname. The server responds with its supported extensions:

EHLO sender.mailertogo.com
250-mx1.example.com Hello sender.mailertogo.com
250-SIZE 52428800
250-8BITMIME
250-STARTTLS
250-AUTH PLAIN LOGIN
250-PIPELINING
250-ENHANCEDSTATUSCODES
250 SMTPUTF8

Each 250- line advertises an extension. The last line uses 250 (space, not dash) to signal the end. Key extensions:

The legacy HELO command (without the "E") skips extensions entirely. It is almost never used in practice today.

Step 4: STARTTLS — Upgrading to Encryption

If the server advertised STARTTLS, the sender issues the command to upgrade the connection:

STARTTLS
220 2.0.0 Ready to start TLS
# TLS handshake happens here
# Connection is now encrypted
# Sender must EHLO again over the encrypted channel
EHLO sender.mailertogo.com
250-mx1.example.com Hello sender.mailertogo.com
250-SIZE 52428800
250 ENHANCEDSTATUSCODES

After STARTTLS, the sender must send EHLO again. The server may advertise different extensions over the encrypted connection (for instance, AUTH is typically only advertised after TLS is established).

On port 465, TLS is implicit — the connection is encrypted from the first byte, and no STARTTLS step is needed.

Without TLS, the entire SMTP conversation — including passwords and message content — is sent in plaintext. Modern best practice is to always use TLS. See MTA-STS and DANE for mechanisms that enforce it.

Step 5: AUTH — Authentication (Submission Only)

When a mail client submits a message through port 587, it authenticates using SMTP AUTH (RFC 4954):

AUTH PLAIN AGFsaWNlQGV4YW1wbGUuY29tAHMzY3IzdA==
235 2.7.0 Authentication successful

The Base64 string encodes \0username\0password. This is why TLS is critical — without it, credentials travel in the clear.

Server-to-server delivery on port 25 does not use AUTH. Instead, the receiving server relies on the sender's IP address, SPF records, DKIM signatures, and other authentication mechanisms to verify the message. See Email Authentication Explained.

Step 6: The Envelope — MAIL FROM and RCPT TO

The envelope is separate from the message headers. It tells the receiving server who is sending the message and who should receive it:

MAIL FROM:<alice@example.com> SIZE=1024
250 2.1.0 OK
RCPT TO:<bob@example.net>
250 2.1.5 OK
RCPT TO:<carol@example.net>
250 2.1.5 OK

Key details:

Each command gets an individual response. A 250 means accepted. A 550 on RCPT TO means the mailbox does not exist. A 452 means the server is temporarily unable to accept that recipient. The sender must handle each response individually — some recipients may be accepted while others are rejected.

Step 7: DATA — Sending the Message

The DATA command begins message transmission:

DATA
354 Start mail input; end with <CRLF>.<CRLF>
From: Alice <alice@example.com>
To: Bob <bob@example.net>
Subject: Meeting tomorrow
Date: Tue, 11 Mar 2026 10:30:00 -0400
Message-ID: <abc123@example.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8

Hi Bob,

Are we still on for 2pm?

- Alice
.
250 2.0.0 OK: queued as 4F3A21C8

The message includes both headers and body, separated by a blank line. The message is terminated by a line containing only a single period (.) — the "dot-stuffing" convention. Any line in the message body that starts with a period has an extra period prepended during transmission and stripped on receipt.

The 250 response after DATA means the message has been accepted for delivery. It does not mean the message has been delivered to the recipient's mailbox. The receiving server may still reject it during content filtering, or generate a bounce later.

The queue ID (e.g., 4F3A21C8) is invaluable for debugging. Record it.

Step 8: QUIT

QUIT
221 2.0.0 Bye

The sender closes the session. The TCP connection is torn down. If the sender has more messages for the same server, it can issue another MAIL FROM instead of QUIT to reuse the connection.

SMTP Response Codes

Every SMTP response starts with a three-digit code. The first digit tells you the category:

Code Meaning Action
2xx Success Command completed; proceed
3xx Intermediate Server is waiting for more data (e.g., after DATA)
4xx Temporary failure Retry later. The server may accept the message on a subsequent attempt
5xx Permanent failure Do not retry. The message will never be accepted as-is

Common codes you will encounter:

With ENHANCEDSTATUSCODES, the server appends a more specific code like 5.1.1 (bad destination mailbox). See Understanding Email Bounces for a full breakdown.

A Complete Transaction

Here is an entire SMTP session from connection to close, annotated:

# 1. TCP connection established to mx1.example.net:25
220 mx1.example.net ESMTP Postfix

# 2. Client introduces itself
EHLO sender.mailertogo.com
250-mx1.example.net
250-STARTTLS
250-SIZE 26214400
250-PIPELINING
250-ENHANCEDSTATUSCODES
250 8BITMIME

# 3. Upgrade to TLS
STARTTLS
220 2.0.0 Ready to start TLS
# (TLS handshake completes)

# 4. Re-introduce over encrypted channel
EHLO sender.mailertogo.com
250-mx1.example.net
250-SIZE 26214400
250-PIPELINING
250-ENHANCEDSTATUSCODES
250 8BITMIME

# 5. Envelope
MAIL FROM:<notifications@app.example.com>
250 2.1.0 OK
RCPT TO:<bob@example.net>
250 2.1.5 OK

# 6. Message content
DATA
354 End data with <CR><LF>.<CR><LF>
From: App Notifications <notifications@app.example.com>
To: bob@example.net
Subject: Your invoice is ready
Date: Tue, 11 Mar 2026 14:00:00 +0000
Message-ID: <inv-7842@app.example.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8

Your March invoice is ready. Log in to view it.
.
250 2.0.0 OK: queued as B9C4E1A3F

# 7. Done
QUIT
221 2.0.0 Bye

Submission vs. Relay

SMTP serves two distinct roles:

An open relay — a server that accepts mail from anyone to anyone — is the cardinal sin of email configuration. Spammers exploit open relays immediately. Every modern mail server must restrict relaying to authenticated users or known senders.

What Can Go Wrong

Connection refused or timed out

The MX host is down or firewalled. The sender's queue retries with exponential backoff, cycling through lower-priority MX records. After the retry period (typically 4-5 days), the message bounces.

Greylisting

The receiving server returns 450 for the first attempt from an unknown sender. Legitimate servers retry; spammers typically do not. Your message will be delayed by minutes but will eventually deliver.

Rejected at RCPT TO

A 550 5.1.1 User unknown response means the mailbox does not exist. This is a hard bounce. Remove the address from your list immediately.

Rejected at DATA

The server may accept the envelope but reject the content. Common reasons: message too large, content flagged as spam, or failed authentication checks (SPF/DKIM/DMARC). The response comes after the terminating dot.

Accepted then bounced

The server returns 250 for DATA but later generates a DSN (bounce message) because the mailbox was over quota, content filtering rejected it, or an internal error occurred. This is the hardest case to handle — you only find out through the bounce message sent to the MAIL FROM address.

TLS failures

If STARTTLS negotiation fails, most servers fall back to plaintext. This is a security risk — an active attacker can strip TLS. MTA-STS and DANE prevent this downgrade.

Key Takeaways

Further Reading

Related RFCs