Back to Blog

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:

  1. Your application connects to your configured SMTP server (SendPit, Mailgun, your own Postfix, etc.) and submits the message.
  2. 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.
  3. The MX server is the destination mail server. The submission server connects to it via SMTP on port 25 and delivers the message.
  4. The recipient's mail server runs spam filters, authentication checks (SPF, DKIM, DMARC), and then deposits the message in the user's mailbox.
  5. 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.

N

Nikhil Rao

Creator of SendPit. Building developer tools for email testing and SMTP infrastructure.

About SendPit →

More from the blog