SMTP Protocol in Practice: Raw Commands, Authentication & Message Format

SMTP Protocol

SMTP (Simple Mail Transfer Protocol), defined in RFC 5321, is the internet standard for moving email from one server to another. While users typically interact with email through a client (Outlook, Gmail, Apple Mail), SMTP is the unseen engine that transports messages across the internet.

This post documents an actual SMTP submission session against a production mail server, command by command. Every line that crosses the wire is shown and explained.


Connecting with TLS

SMTP submission is always encrypted. On port 465 the connection is wrapped in TLS from the first byte (implicit TLS). OpenSSL’s s_client connects and handles the TLS handshake, then passes raw SMTP commands through the encrypted channel:

$ openssl s_client -connect smtp.tinkmail.me:465 -crlf

On success, openssl prints certificate and handshake details. The first SMTP line is the server greeting:

220 smtp.tinkmail.me ESMTP Service Ready

The 220 code means the service is ready. If the server were not available, it would return a 421 temporary failure instead. (The full response code taxonomy is covered in SMTP Response Codes.)

Alternative — STARTTLS (port 587). Some servers use port 587 with the STARTTLS command to upgrade a plain-text connection to TLS after the EHLO handshake. The SMTP commands are identical after encryption is established; only the connection preamble differs. Use openssl s_client -starttls smtp -connect host:587 -crlf for that variant.


Server Capabilities: EHLO

The client announces itself with EHLO (Extended Hello), and the server responds with its capabilities:

EHLO client.example.tinkmail.me
250-smtp.tinkmail.me
250-PIPELINING
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN
250-CHUNKING
250 SMTPUTF8

The 250 response is multi-line. Continuation lines use a dash (250-) and the final line uses a space (250 ). (See SMTP Response Codes for the full multi-line format specification.)

The set of advertised extensions varies per server. A full reference for each capability — PIPELINING, SIZE, 8BITMIME, CHUNKING, SMTPUTF8, and others — is in SMTP Ports, Authentication & Extensions.


Authentication: AUTH LOGIN

Before accepting mail for relay, the server requires proof of identity. We use AUTH LOGIN. The server issues base64-encoded challenges, and the client responds with base64-encoded credentials:

C: AUTH LOGIN
S: 334 VXNlcm5hbWU6

VXNlcm5hbWU6 decodes to Username:. The client responds with the username base64-encoded:

C: ZW1haWxAZXhhbXBsZS50aW5rbWFpbC5tZQ==
S: 334 UGFzc3dvcmQ6

ZW1haWxAZXhhbXBsZS50aW5rbWFpbC5tZQ== decodes to [email protected]. The server responds 334 UGFzc3dvcmQ6Password:.

The client sends the password in the same fashion:

C: bXktdGVzdC1wYXNzd29yZA==
S: 235 2.7.0 Authentication successful

bXktdGVzdC1wYXNzd29yZA== decodes to my-test-password. The 235 code confirms success. A 535 code would indicate authentication failure.

The wire exchange in full:

Direction Raw Wire Decoded
Server 334 VXNlcm5hbWU6 Username:
Client ZW1haWxAZXhhbXBsZS50aW5rbWFpbC5tZQ== [email protected]
Server 334 UGFzc3dvcmQ6 Password:
Client bXktdGVzdC1wYXNzd29yZA== my-test-password

Base64 provides no secrecy. echo ZW1haWxAZXhhbXBsZS50aW5rbWFpbC5tZQ== | base64 -d reveals the username instantly. The security of this exchange depends entirely on the TLS layer. Without TLS, credentials are exposed in plain text to any observer on the network path.


Message Envelope and Content

After authentication, the SMTP envelope is defined with MAIL FROM (sender) and RCPT TO (recipient). The envelope is distinct from the message headers — the envelope is consumed by the SMTP protocol itself, while headers travel inside the message body and are visible to the recipient.

C: MAIL FROM: <[email protected]>
S: 250 2.1.0 Ok

C: RCPT TO: <[email protected]>
S: 250 2.1.5 Ok

A 250 response means the server has accepted the envelope. If the recipient domain were not handled by this server, it would return 550 (mailbox not found) or 551 (user not local).

DATA: Headers vs. Body

The DATA command signals that the message content follows. The server responds with 354 and waits for the complete message, terminated by \r\n.\r\n (CRLF + dot + CRLF):

C: DATA
S: 354 End data with <CR><LF>.<CR><LF>
C: From: Sender Name <[email protected]>
C: To: Recipient Name <[email protected]>
C: Subject: SMTP Protocol Demonstration
C: Date: Mon, 28 Jul 2026 14:30:00 +0000
C: Message-ID: <[email protected]>
C: MIME-Version: 1.0
C: Content-Type: text/plain; charset=UTF-8
C: Content-Transfer-Encoding: 7bit
C:
C: This is the message body.
C:
C: Headers above the blank line describe the message metadata.
C: Everything below the blank line is the body content.
C:
C: The message ends with a single dot on its own line.
C: .
S: 250 2.0.0 Ok: queued as 4XpYqZ0v9TzB1kR

The structure is rigid:

headers  ← one or more [RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322) header fields, each ending with CRLF
         ← empty line (CRLF alone) — REQUIRED separator
body     ← arbitrary text, terminated by CRLF.CRLF

Headers are structured lines in Field-Name: value format. Common header fields include From:, To:, Subject:, Date:, Message-ID:, MIME-Version:, Content-Type:, and Content-Transfer-Encoding. Headers may span multiple lines by starting continuation lines with whitespace (folding, RFC 5322 Section 2.2.3).

Body follows the blank line and is whatever the sender chooses. For multipart content (MIME), the Content-Type header declares a boundary string that delimits the parts. The SMTP layer does not interpret the body — it transports it as opaque data.

The 250 2.0.0 Ok: queued as 4XpYqZ0v9TzB1kR response confirms that the server has accepted the message and assigned it a queue identifier. This does not mean the message has been delivered to the recipient — only that it has been handed off to the server’s outbound processing pipeline.


Session Termination

C: QUIT
S: 221 2.0.0 Bye

The 221 response confirms the server is closing the connection. Any client that does not send QUIT leaves the server to time out the connection, which wastes server resources.


Post-Queuing: What Happens After 250

The queued as response is the last SMTP interaction, but the message’s journey is far from over. The server’s internal pipeline proceeds as follows:

  1. Queue insert — The message is written to persistent storage (typically a disk-based queue in Maildir or a database). The queue ID (4XpYqZ0v9TzB1kR) is the server’s internal reference for tracking, logging, and potential retries.

  2. Spam and virus scanning — The message content is analysed by the server’s filtering pipeline before it is accepted for relay.

  3. DNS resolution — The server extracts the recipient domain (tinkmail.me), queries its MX record, and resolves the target MTA’s IP address.

  4. Outbound relay — A new SMTP connection is opened to the target MTA on port 25, and the message is transmitted through the same command sequence (EHLO, MAIL FROM, RCPT TO, DATA, QUIT) that was just performed by the original client.

  5. Delivery notification — If the target MTA accepts the message (250), the queue entry is removed. If a temporary failure (4xx) occurs, the message remains in the queue for retry with exponential backoff. A permanent failure (5xx) generates a bounce message back to the sender.

This pipeline is explored in detail in The SMTP Email Journey.


Complete Session Transcript

$ openssl s_client -connect smtp.tinkmail.me:465 -crlf
# ... TLS handshake output omitted ...
220 smtp.tinkmail.me ESMTP Service Ready

EHLO client.example.tinkmail.me
250-smtp.tinkmail.me
250-PIPELINING
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN
250-CHUNKING
250 SMTPUTF8

AUTH LOGIN
334 VXNlcm5hbWU6
ZW1haWxAZXhhbXBsZS50aW5rbWFpbC5tZQ==
334 UGFzc3dvcmQ6
bXktdGVzdC1wYXNzd29yZA==
235 2.7.0 Authentication successful

MAIL FROM: <[email protected]>
250 2.1.0 Ok

RCPT TO: <[email protected]>
250 2.1.5 Ok

DATA
354 End data with <CR><LF>.<CR><LF>
From: Sender Name <[email protected]>
To: Recipient Name <[email protected]>
Subject: SMTP Protocol Demonstration
Date: Mon, 28 Jul 2026 14:30:00 +0000
Message-ID: <[email protected]>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit

This is the message body.

Headers above the blank line describe the message metadata.
Everything below the blank line is the body content.

The message ends with a single dot on its own line.
.
250 2.0.0 Ok: queued as 4XpYqZ0v9TzB1kR

QUIT
221 2.0.0 Bye

Protocol Summary

Phase Commands Purpose
Connection TCP handshake + TLS Establish encrypted channel to port 465 (or 587 with STARTTLS).
Greeting Server → 220 Server announces readiness.
Capabilities EHLO250-... Client learns server extensions.
Authentication AUTH LOGIN235 Client proves identity via SASL.
Envelope MAIL FROM + RCPT TO Define sender and recipient for the transport layer.
Data Transfer DATA354250 Transmit message headers and body.
Cleanup QUIT221 Graceful session end.

From here, the next post in this series follows the message through the full relay chain — MX resolution, MTA-to-MTA transfer, inbound filtering, and mailbox delivery.