Simple Mail Transfer Protocol (SMTP)
The Simple Mail Transfer Protocol (SMTP) is the protocol mail servers use to hand messages to one another, and that mail clients use to submit new messages for sending. It is defined in RFC 5321.
SMTP is a line-based conversation in plain text. That is worth knowing not out of nostalgia but because every rejection you will ever debug is a line from this conversation, quoted back at you in a log file.
What does an SMTP session look like?
Client lines are the commands; the numbered lines are the server’s replies:
$ telnet mx1.example.net 25
220 mx1.example.net ESMTP Postfix
EHLO mail.example.com
250-mx1.example.net
250-PIPELINING
250-SIZE 20480000
250-STARTTLS
250 8BITMIME
MAIL FROM:<sender@example.com>
250 2.1.0 Ok
RCPT TO:<recipient@example.net>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: Sender <sender@example.com>
To: Recipient <recipient@example.net>
Subject: Test
This is the message body.
.
250 2.0.0 Ok: queued as 4Rk8Zt1234
QUIT
221 2.0.0 Bye
Every acceptance decision a receiving server makes happens at one of those steps, which is why “where in the conversation was it rejected” is the first question when mail goes missing.
What is the envelope, and why does it differ from the headers?
MAIL FROM and RCPT TO are the envelope. They are what the servers act on:
where a bounce goes and where the message is
actually delivered.
From:, To: and Cc: are headers. They are part of the message content and
are what the recipient sees. Nothing in SMTP requires the two to agree.
This gap is not a flaw so much as a design: it is what makes mailing lists and
Bcc work. It is also the root of a great deal of
abuse, and the reason
SPF authenticates the envelope while
DMARC
exists to tie that result back to the visible From:.
What do the response codes mean?
| Class | Meaning | Sender’s reaction |
|---|---|---|
2xx |
success | continue |
3xx |
intermediate, send more | continue |
4xx |
temporary failure | retry later, keep queued |
5xx |
permanent failure | give up, generate a bounce |
The distinction between 4xx and 5xx decides everything downstream. A 450
keeps the message in the queue for retry; a 550
produces a non-delivery report at once.
This is also the mechanism behind greylisting: a server answers 450 to an
unknown sender on first contact, expecting a legitimate server to retry a few
minutes later while a great deal of bulk-sending software never will.
Which ports are used, and for what?
- Port 25 — server-to-server transfer. Accepts mail for local recipients from anyone, without authentication. Many consumer ISPs block outbound connections to it.
- Port 587 — the submission service, defined in
RFC 6409. Authentication is
mandatory, and TLS is negotiated with
STARTTLS. - Port 465 — submission with TLS established before the greeting (implicit TLS). Deprecated for years, then re-standardised, and now widely used again.
Treating 25 and 587 as interchangeable is how a server becomes an open relay. See access management.
Where do the checks hook into the conversation?
Each stage is an opportunity to reject, and rejecting early is cheaper and safer:
| Stage | What is checked |
|---|---|
| connection | client IP against local maps and DNSBLs |
EHLO |
the hostname, and its reverse DNS |
MAIL FROM |
envelope sender, SPF |
RCPT TO |
does the recipient exist, is relaying permitted |
DATA / end of data |
content scanning, DKIM verification, DMARC |
Rejecting an unknown recipient at RCPT TO rather than accepting and bouncing
afterwards is what prevents backscatter — the
single most consequential configuration choice in this table.
How do you test an SMTP server by hand?
telnet or openssl s_client to the port and type the commands above. For
TLS-only submission:
$ openssl s_client -connect mx1.example.net:465 -quiet
220 mx1.example.net ESMTP Postfix
EHLO mail.example.com
For scripted testing, sending through the local MTA is usually more convenient than speaking the protocol directly — see sending test emails from shell.