What Is SMTP? A Developer's Guide to the Simple Mail Transfer Protocol
SMTP stands for Simple Mail Transfer Protocol. It is the standard protocol that applications use to send email across the internet. Every time your application sends a signup confirmation, password reset, or invoice notification, it communicates with a mail server using SMTP.
SMTP was first defined in RFC 821 in 1982 and updated in RFC 5321 in 2008. Despite being over four decades old, it remains the foundation of all email delivery. Understanding how SMTP works at the protocol level makes you significantly better at debugging delivery failures, configuring mail servers, and building reliable email workflows.
How SMTP Works
SMTP is a text-based protocol that operates over TCP, typically on port 25 (server-to-server), port 587 (client submission with authentication), or port 465 (implicit TLS). A typical SMTP session follows a predictable sequence: connect, identify, authenticate, specify sender and recipients, transmit the message body, and disconnect.
Here is what a complete SMTP session looks like at the protocol level:
$ telnet smtp.example.com 587
220 smtp.example.com ESMTP ready
EHLO myapp.example.com
250-smtp.example.com Hello myapp.example.com
250-STARTTLS
250-AUTH PLAIN LOGIN
250 SIZE 10485760
STARTTLS
220 Ready to start TLS
AUTH PLAIN AGFsaWNlAHNlY3JldA==
235 Authentication successful
MAIL FROM:<[email protected]>
250 OK
RCPT TO:<[email protected]>
250 OK
DATA
354 Start mail input; end with <CRLF>.<CRLF>
From: MyApp <[email protected]>
To: [email protected]
Subject: Your password reset
Content-Type: text/html; charset=utf-8
<html><body><p>Click here to reset your password.</p></body></html>
.
250 OK: queued as ABC123
QUIT
221 Bye
Every line starting with a three-digit code is a response from the server. Every other line is a command from the client (your application or mail library).
SMTP Commands Explained
| Command | Purpose | Example |
|---|---|---|
EHLO |
Identify the client and request extended features | EHLO myapp.com |
STARTTLS |
Upgrade the connection to TLS encryption | STARTTLS |
AUTH |
Authenticate with username and password | AUTH PLAIN <base64> |
MAIL FROM |
Specify the sender (envelope sender) | MAIL FROM:<[email protected]> |
RCPT TO |
Specify a recipient (can be repeated for multiple recipients) | RCPT TO:<[email protected]> |
DATA |
Begin the message body (headers + content) | DATA |
QUIT |
End the session | QUIT |
The EHLO command replaced the older HELO and enables Extended SMTP (ESMTP), which supports authentication, TLS, and size limits. Most modern servers require EHLO.
SMTP Response Codes
SMTP servers respond to every command with a three-digit status code. The first digit tells you the category:
| Code Range | Meaning | Example |
|---|---|---|
| 2xx | Success | 250 OK β command accepted |
| 3xx | Intermediate | 354 Start mail input β server is waiting for data |
| 4xx | Temporary failure | 421 Service not available β try again later |
| 5xx | Permanent failure | 550 User not found β do not retry |
Common response codes every developer should know:
- 220 β Server ready (greeting)
- 235 β Authentication successful
- 250 β Requested action completed
- 354 β Ready for message data
- 421 β Service unavailable (temporary, often rate limiting)
- 450 β Mailbox temporarily unavailable (greylisting)
- 535 β Authentication failed (wrong credentials)
- 550 β Mailbox not found or delivery rejected
- 552 β Message size exceeds limit
When your application logs an SMTP error, the response code tells you exactly what went wrong.
The Envelope vs the Headers
A critical concept in SMTP is the difference between the envelope and the headers. They serve different purposes and can contain different values.
The envelope is defined by the MAIL FROM and RCPT TO commands. This is what the mail server uses to route the message. It determines where the message goes and where bounces are sent.
The headers are part of the DATA body β the From:, To:, Subject:, and other fields. These are what the recipient sees in their email client. They are informational, not routing instructions.
This distinction matters because the envelope sender can differ from the From: header. Mailing lists, forwarding services, and bounce handling all rely on this separation. It is also why phishing works β the visible From: header can say anything, regardless of who actually sent the message.
TLS and SMTP Security
SMTP was designed without encryption. Messages were transmitted in plain text, including authentication credentials. Modern SMTP uses TLS in two ways:
STARTTLS (port 587): The connection starts unencrypted. After the EHLO exchange, the client sends STARTTLS to upgrade to TLS. This is called "opportunistic TLS" because the client decides whether to upgrade based on the server's capabilities.
Implicit TLS (port 465): The connection is encrypted from the first byte. No upgrade negotiation is needed. This was briefly deprecated but re-standardized in RFC 8314 (2018) and is now the recommended approach for client-to-server submission.
For development and testing, most SMTP sandboxes support both modes. When configuring your application:
# For STARTTLS (port 587)
MAIL_PORT=587
MAIL_ENCRYPTION=tls
# For implicit TLS (port 465)
MAIL_PORT=465
MAIL_ENCRYPTION=ssl
How Email Delivery Actually Works
When your application sends an email, the message passes through multiple servers before reaching the recipient:
- Your application connects to your configured SMTP server (SendPit, Mailgun, your own Postfix, etc.) and submits the message.
- The submission server accepts the message and looks up the recipient's domain. It queries DNS for the MX (Mail Exchanger) record of the recipient's domain.
- The MX server is the destination mail server. The submission server connects to it via SMTP on port 25 and delivers the message.
- The recipient's mail server runs spam filters, authentication checks (SPF, DKIM, DMARC), and then deposits the message in the user's mailbox.
- The recipient retrieves the message using IMAP or POP3 (not SMTP β those are separate protocols for reading email).
Each hop in this chain can fail independently. Your application may get a 250 OK from the first server, but the message can still fail at any subsequent hop. This is why SMTP sandboxes are valuable for development β they let you verify the message content and headers without relying on the full delivery chain.
SMTP Relay vs Direct Delivery
There are two models for sending email from your application:
Direct delivery means your server connects directly to the recipient's MX server. This requires a properly configured server with reverse DNS, SPF records, and a clean IP reputation. Most application servers cannot do this reliably because cloud provider IP ranges are often blacklisted by default.
SMTP relay means your application sends to an intermediary service (SendPit, Mailgun, Amazon SES, Postfix relay) that handles delivery on your behalf. The relay service manages IP reputation, retry logic, and bounce handling. This is what most applications use.
For development and testing, an SMTP sandbox like SendPit acts as a relay that captures messages instead of delivering them. Your application sends email exactly as it would in production, but nothing reaches a real inbox.
Common SMTP Failure Modes
| Failure | Cause | SMTP Code | Fix |
|---|---|---|---|
| Authentication failed | Wrong username or password | 535 | Check credentials, ensure correct encoding |
| Connection refused | Wrong port, firewall blocking | N/A (TCP) | Verify port and network rules |
| TLS handshake failed | Certificate mismatch, old TLS version | N/A (TLS) | Update TLS config, check server certificates |
| Message rejected | Spam filter, blacklisted IP, missing SPF | 550, 554 | Check DNS records, IP reputation |
| Rate limited | Too many messages in a short window | 421, 450 | Implement backoff, use queuing |
| Greylisted | First-time sender to that server | 450 | Retry after delay (automatic with queues) |
| Size exceeded | Message or attachment too large | 552 | Reduce attachment size, use links instead |
Debugging SMTP Issues
When email delivery fails, the SMTP response code and message tell you where to look. Most mail libraries expose these in their error handling:
// Laravel example
try {
Mail::to('[email protected]')->send(new WelcomeMail($user));
} catch (\Symfony\Component\Mailer\Exception\TransportException $e) {
// $e->getMessage() contains the SMTP response
Log::error('Email delivery failed', [
'error' => $e->getMessage(),
'code' => $e->getCode(),
]);
}
For deeper debugging, capture the full SMTP transaction in an SMTP sandbox. SendPit shows you the complete email including all headers, MIME structure, and the raw source β everything you need to diagnose delivery issues without waiting for a real mailbox to respond.
Summary
SMTP is the protocol that powers all email delivery. It is a simple, text-based protocol built on commands and response codes. Understanding the distinction between envelope and headers, how TLS encryption works, and what each response code means gives you the knowledge to debug almost any email delivery problem.
For development and testing, use an SMTP sandbox to capture and inspect emails without affecting real users. Configure your application to point at the sandbox's SMTP server, and every email your app sends is captured for inspection instead of delivered.
Nikhil Rao
Creator of SendPit. Building developer tools for email testing and SMTP infrastructure.
About SendPit →