# How Email Actually Works: An Interactive Deep-Dive

Source: https://wraps.dev/blog/how-email-works

S: 220 mail.example.com ESMTP ready

C: EHLO yourcompany.com

S: 250-mail.example.com Hello

S: 250-STARTTLS

S: 250 Ok

C: MAIL FROM:<you@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<alice@example.com>

S: 250 2.1.5 Ok

C: DATA

S: 354 End data with <CR><LF>.<CR><LF>

C: From: you@yourcompany.com

C: To: alice@example.com

C: Subject: Quick question

C: .

S: 250 2.0.0 Ok: queued as ABC123

C: QUIT

S: 221 2.0.0 Bye

S: 220 mx.recipient.org ESMTP Postfix

C: EHLO relay.google.com

S: 250-mx.recipient.org

S: 250-AUTH PLAIN LOGIN

S: 250 Ok

C: MAIL FROM:<bounce+id=abc@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<bob@recipient.org>

S: 250 2.1.5 Ok

C: DATA

S: 354 Go ahead

C: DKIM-Signature: v=1; a=rsa-sha256; d=yourcompany.com

C: Authentication-Results: spf=pass dkim=pass dmarc=pass

C: .

S: 250 2.0.0 Ok: queued as DEF456

C: QUIT

S: 221 Bye

S: 220 mail.example.com ESMTP ready

C: EHLO yourcompany.com

S: 250-mail.example.com Hello

S: 250-STARTTLS

S: 250 Ok

C: MAIL FROM:<you@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<alice@example.com>

S: 250 2.1.5 Ok

C: DATA

S: 354 End data with <CR><LF>.<CR><LF>

C: From: you@yourcompany.com

C: To: alice@example.com

C: Subject: Quick question

C: .

S: 250 2.0.0 Ok: queued as ABC123

C: QUIT

S: 221 2.0.0 Bye

S: 220 mx.recipient.org ESMTP Postfix

C: EHLO relay.google.com

S: 250-mx.recipient.org

S: 250-AUTH PLAIN LOGIN

S: 250 Ok

C: MAIL FROM:<bounce+id=abc@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<bob@recipient.org>

S: 250 2.1.5 Ok

C: DATA

S: 354 Go ahead

C: DKIM-Signature: v=1; a=rsa-sha256; d=yourcompany.com

C: Authentication-Results: spf=pass dkim=pass dmarc=pass

C: .

S: 250 2.0.0 Ok: queued as DEF456

C: QUIT

S: 221 Bye

S: 220 mail.example.com ESMTP ready

C: EHLO yourcompany.com

S: 250-mail.example.com Hello

S: 250-STARTTLS

S: 250 Ok

C: MAIL FROM:<you@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<alice@example.com>

S: 250 2.1.5 Ok

C: DATA

S: 354 End data with <CR><LF>.<CR><LF>

C: From: you@yourcompany.com

C: To: alice@example.com

C: Subject: Quick question

C: .

S: 250 2.0.0 Ok: queued as ABC123

C: QUIT

S: 221 2.0.0 Bye

S: 220 mx.recipient.org ESMTP Postfix

C: EHLO relay.google.com

S: 250-mx.recipient.org

S: 250-AUTH PLAIN LOGIN

S: 250 Ok

C: MAIL FROM:<bounce+id=abc@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<bob@recipient.org>

S: 250 2.1.5 Ok

C: DATA

S: 354 Go ahead

C: DKIM-Signature: v=1; a=rsa-sha256; d=yourcompany.com

C: Authentication-Results: spf=pass dkim=pass dmarc=pass

C: .

S: 250 2.0.0 Ok: queued as DEF456

C: QUIT

S: 221 Bye

S: 220 mail.example.com ESMTP ready

C: EHLO yourcompany.com

S: 250-mail.example.com Hello

S: 250-STARTTLS

S: 250 Ok

C: MAIL FROM:<you@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<alice@example.com>

S: 250 2.1.5 Ok

C: DATA

S: 354 End data with <CR><LF>.<CR><LF>

C: From: you@yourcompany.com

C: To: alice@example.com

C: Subject: Quick question

C: .

S: 250 2.0.0 Ok: queued as ABC123

C: QUIT

S: 221 2.0.0 Bye

S: 220 mx.recipient.org ESMTP Postfix

C: EHLO relay.google.com

S: 250-mx.recipient.org

S: 250-AUTH PLAIN LOGIN

S: 250 Ok

C: MAIL FROM:<bounce+id=abc@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<bob@recipient.org>

S: 250 2.1.5 Ok

C: DATA

S: 354 Go ahead

C: DKIM-Signature: v=1; a=rsa-sha256; d=yourcompany.com

C: Authentication-Results: spf=pass dkim=pass dmarc=pass

C: .

S: 250 2.0.0 Ok: queued as DEF456

C: QUIT

S: 221 Bye

S: 220 mail.example.com ESMTP ready

C: EHLO yourcompany.com

S: 250-mail.example.com Hello

S: 250-STARTTLS

S: 250 Ok

C: MAIL FROM:<you@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<alice@example.com>

S: 250 2.1.5 Ok

C: DATA

S: 354 End data with <CR><LF>.<CR><LF>

C: From: you@yourcompany.com

C: To: alice@example.com

C: Subject: Quick question

C: .

S: 250 2.0.0 Ok: queued as ABC123

C: QUIT

S: 221 2.0.0 Bye

S: 220 mx.recipient.org ESMTP Postfix

C: EHLO relay.google.com

S: 250-mx.recipient.org

S: 250-AUTH PLAIN LOGIN

S: 250 Ok

C: MAIL FROM:<bounce+id=abc@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<bob@recipient.org>

S: 250 2.1.5 Ok

C: DATA

S: 354 Go ahead

C: DKIM-Signature: v=1; a=rsa-sha256; d=yourcompany.com

C: Authentication-Results: spf=pass dkim=pass dmarc=pass

C: .

S: 250 2.0.0 Ok: queued as DEF456

C: QUIT

S: 221 Bye

S: 220 mail.example.com ESMTP ready

C: EHLO yourcompany.com

S: 250-mail.example.com Hello

S: 250-STARTTLS

S: 250 Ok

C: MAIL FROM:<you@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<alice@example.com>

S: 250 2.1.5 Ok

C: DATA

S: 354 End data with <CR><LF>.<CR><LF>

C: From: you@yourcompany.com

C: To: alice@example.com

C: Subject: Quick question

C: .

S: 250 2.0.0 Ok: queued as ABC123

C: QUIT

S: 221 2.0.0 Bye

S: 220 mx.recipient.org ESMTP Postfix

C: EHLO relay.google.com

S: 250-mx.recipient.org

S: 250-AUTH PLAIN LOGIN

S: 250 Ok

C: MAIL FROM:<bounce+id=abc@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<bob@recipient.org>

S: 250 2.1.5 Ok

C: DATA

S: 354 Go ahead

C: DKIM-Signature: v=1; a=rsa-sha256; d=yourcompany.com

C: Authentication-Results: spf=pass dkim=pass dmarc=pass

C: .

S: 250 2.0.0 Ok: queued as DEF456

C: QUIT

S: 221 Bye

S: 220 mail.example.com ESMTP ready

C: EHLO yourcompany.com

S: 250-mail.example.com Hello

S: 250-STARTTLS

S: 250 Ok

C: MAIL FROM:<you@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<alice@example.com>

S: 250 2.1.5 Ok

C: DATA

S: 354 End data with <CR><LF>.<CR><LF>

C: From: you@yourcompany.com

C: To: alice@example.com

C: Subject: Quick question

C: .

S: 250 2.0.0 Ok: queued as ABC123

C: QUIT

S: 221 2.0.0 Bye

S: 220 mx.recipient.org ESMTP Postfix

C: EHLO relay.google.com

S: 250-mx.recipient.org

S: 250-AUTH PLAIN LOGIN

S: 250 Ok

C: MAIL FROM:<bounce+id=abc@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<bob@recipient.org>

S: 250 2.1.5 Ok

C: DATA

S: 354 Go ahead

C: DKIM-Signature: v=1; a=rsa-sha256; d=yourcompany.com

C: Authentication-Results: spf=pass dkim=pass dmarc=pass

C: .

S: 250 2.0.0 Ok: queued as DEF456

C: QUIT

S: 221 Bye

S: 220 mail.example.com ESMTP ready

C: EHLO yourcompany.com

S: 250-mail.example.com Hello

S: 250-STARTTLS

S: 250 Ok

C: MAIL FROM:<you@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<alice@example.com>

S: 250 2.1.5 Ok

C: DATA

S: 354 End data with <CR><LF>.<CR><LF>

C: From: you@yourcompany.com

C: To: alice@example.com

C: Subject: Quick question

C: .

S: 250 2.0.0 Ok: queued as ABC123

C: QUIT

S: 221 2.0.0 Bye

S: 220 mx.recipient.org ESMTP Postfix

C: EHLO relay.google.com

S: 250-mx.recipient.org

S: 250-AUTH PLAIN LOGIN

S: 250 Ok

C: MAIL FROM:<bounce+id=abc@yourcompany.com>

S: 250 2.1.0 Ok

C: RCPT TO:<bob@recipient.org>

S: 250 2.1.5 Ok

C: DATA

S: 354 Go ahead

C: DKIM-Signature: v=1; a=rsa-sha256; d=yourcompany.com

C: Authentication-Results: spf=pass dkim=pass dmarc=pass

C: .

S: 250 2.0.0 Ok: queued as DEF456

C: QUIT

S: 221 Bye

You click Send. What happens in the next 3 seconds? An interactive journey from compose window to inbox — through SMTP handshakes, DNS lookups, relay hops, and authentication.

20 min read•Wraps Team

Start the journey

## Chapter 1: The Compose

Every email starts with a lie — or at least a convenient illusion. The compose window shows you simple fields: To, From, Subject, Body. But underneath that friendly UI, your email client is building a structured document with dozens of headers, MIME encoding, and an envelope that's completely separate from the message itself.

This distinction between the envelope and the content is fundamental. The envelope (`MAIL FROM` and `RCPT TO`) tells servers where to route the message. The content (the `From:` and `To:` headers) is what you see in your inbox. They don't have to match — and that mismatch is exactly how email spoofing works.

Try editing the compose form below and watch the raw SMTP message update in real-time. Notice how the same information appears in two different formats — human-readable and machine-readable.

What you see

From

To

Subject

BodyHi Alice, Just wanted to follow up on our conversation yesterday. Best, You

What the server sees

EHLO yourcompany.com
MAIL FROM:<you@yourcompany.com>
RCPT TO:<alice@example.com>
DATA
From: you@yourcompany.com
To: alice@example.com
Subject: Quick question about the project
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Date: 
Message-ID: <example-id@yourcompany.com>
Hi Alice,
Just wanted to follow up on our conversation yesterday.
Best,
You
.
QUIT

## Chapter 2: The Handshake

SMTP is a surprisingly conversational protocol. Your server doesn't just blast a message at the recipient — it has a structured back-and-forth dialogue, like two people on a phone call. The server introduces itself, the recipient confirms it's listening, then they negotiate how to transfer the message.

The conversation starts with a TCP connection to port 25 (server-to-server) or port 587 (client submission with auth). The receiving server responds with a `220` greeting — its way of saying "I'm here and ready." Your server then says `EHLO` (Extended Hello), and the conversation begins.

Every SMTP response starts with a three-digit code. `2xx` means success. `3xx` means "keep going" (like 354 after DATA). `4xx` is a temporary error (try again). `5xx` is permanent failure (don't retry). The entire protocol runs on this simple numbering system defined in 1982.

Try it yourself. The terminal below simulates a real SMTP session — type each command and watch the server respond.

smtp — telnet mail.example.com 25

guidedfree

S: 220 mail.example.com ESMTP ready

Step 1/6: Connect to the mail server

## Chapter 3: The Lookup

Before your server can deliver the message, it needs to find out where to send it. The recipient's address says `alice@example.com`, but what IP address actually handles mail for `example.com`?

This is where MX records come in. Your server queries DNS for the MX (Mail Exchange) records of the recipient domain. These records list one or more mail servers, each with a priority number. Lower priority = tried first. If the primary server is down, email falls back to the next one.

The DNS resolution path goes: root servers → TLD servers (.com, .org) → authoritative nameserver for the domain → MX records. This usually takes 20-100ms. The result is cached, so subsequent emails to the same domain skip the lookup.

Try looking up the MX records for any domain below. You'll see exactly which servers accept mail for that domain and in what priority order.

### MX Record Lookup

Lookup

## Chapter 4: The Relay

Email rarely goes directly from sender to recipient. It hops through multiple servers — your outbound mail server, possibly a relay service (like AWS SES or Google's SMTP relay), the recipient's inbound MX server, and finally the IMAP store where the message lands.

Each server that touches the email adds a `Received:` header — a stamp showing where the message came from, which server processed it, and when. These headers stack in reverse order: the top Received header is the last hop, and the bottom one is the first.

This chain of Received headers is how you trace an email's journey across the internet. It's also how receiving servers detect suspicious routing — if an email claims to be from Google but the Received chain shows it originated from an unknown server in a different country, that's a red flag.

Your Server

Received: from yourcompany.com

Outbound MTA

Received: by smtp-relay.gmail.com

Recipient MX

Received: from smtp-relay by mx.example.com

Inbox Server

Received: by imap.example.com

## Chapter 5: The Trust Check

SMTP was designed in 1982 — before spam, before phishing, before anyone imagined email would carry financial transactions. The protocol has zero built-in authentication. Any server can claim to be sending from any domain. It's like a postal system where anyone can write any return address on an envelope.

Three protocols were added later to fix this: SPF (2006), DKIM (2007), and DMARC (2012). Together, they form the authentication chain that modern email depends on. When the recipient's server receives your message, it runs all three checks before deciding whether to deliver, quarantine, or reject.

SPFDKIMDMARC

#### SPF

Is this server allowed to send for this domain?

1Receiving server extracts Return-Path domain

2Queries DNS for SPF record (TXT)

3Checks if sending IP is in the allowed list

4Returns Pass, Fail, SoftFail, or Neutral

SPFDKIMDMARCInbox or Reject

Prediction

An email passes DKIM but fails SPF. The domain has DMARC with p=reject. What happens?

Email is rejected — both must pass

Email is delivered — DKIM pass is sufficient for DMARC

Email goes to spam — partial pass means quarantine

The key insight: DMARC requires alignment. It's not enough for SPF or DKIM to pass — the domain in the result must match the `From:` header domain. This prevents attackers from using their own authenticated domain while spoofing a different From: address.

Prediction

Your company uses Google Workspace for email but sends marketing emails through AWS SES. What happens with SPF?

Both pass SPF — one domain can have multiple SPF includes

SES emails fail SPF — only one provider can be authorized

You need separate domains for each provider

## Chapter 6: The Inbox

After passing authentication, the email lands in the recipient's mail store. The recipient's email client retrieves it using IMAP (Internet Message Access Protocol) or the older POP3. IMAP keeps messages on the server and syncs across devices; POP3 downloads and (traditionally) deletes from the server.

The full circle is complete. From compose window to SMTP handshake, through DNS resolution and server relays, past authentication checks, and into the inbox. The entire journey typically takes 1-5 seconds — though queuing, greylisting, or retry logic can extend it to minutes or hours.

Below is the complete Received header chain from our email's journey. Each header was added by a different server at a different step — read bottom to top to trace the path.

### The Complete Header Chain

ParsedRaw

Received headers are added in reverse order — the top header is the last hop. Read bottom to top to trace the email's journey.

Ch 4: Relayimap.example.com (internal) → imap-store.example.com

06 Mar 2026

Ch 5: Trust Checksmtp-relay.gmail.com → mx.example.com

06 Mar 2026

Ch 2: Handshakeyourcompany.com → smtp-relay.gmail.com

06 Mar 2026

## Chapter 7: Deep Cuts

Email's simplicity hides layers of complexity. Here are the edge cases and failure modes that keep email administrators up at night.

Bounces: Hard vs Soft

Greylisting: The Anti-Spam Speed Bump

Spam Filtering: Beyond Authentication

The 10-Lookup SPF Limit

Email Forwarding Breaks SPF

## Build on Top of Email Infrastructure You Own

Wraps deploys production-ready email infrastructure — DKIM, SPF, DMARC, bounce handling, and sending — to your AWS account. One command. You own everything.

Terminal

`$ npx @wraps.dev/cli email init`

[Free CLI Quickstart](https://wraps.dev/docs/quickstart)[Check Your Domain](https://wraps.dev/tools)

No credit card · Open source · Infrastructure you own
