Hello, I'm Shrijith Venkatramana. I’m building LiveReview, a private AI code review tool that runs on your LLM key (OpenAI, Gemini, etc.) with highly competitive pricing -- built for small teams. Do check it out and give it a try!
Email powers a lot of our daily communication, from work updates to personal notes. This post breaks down the key protocols and systems that make email function. You'll see how they interact, with examples and code to illustrate the process. By the end, you'll have a clear picture of email's inner workings.
Email's Core Components
Email involves senders, receivers, servers, and clients. At its heart, an email message has headers (like From, To, Subject) and a body. Headers guide delivery, while the body holds the content.
Servers act as intermediaries. A sending server pushes the email, and a receiving server stores it until the recipient fetches it. Clients, like Outlook or web apps, connect to these servers.
Key systems include mail transfer agents (MTAs) for routing, mail delivery agents (MDAs) for storage, and mail user agents (MUAs) for user interaction.
For a quick overview, here's a table of main components:
Component | Role | Example |
---|---|---|
MTA | Routes emails between servers | Postfix, Sendmail |
MDA | Delivers to user mailboxes | Dovecot, Procmail |
MUA | Lets users read/send emails | Thunderbird, Gmail app |
Without these, emails couldn't move from sender to recipient.
Learn more from the RFC 5322 on email message format.
SMTP: The Sending Protocol
Simple Mail Transfer Protocol (SMTP) handles sending emails from your client to the server or between servers. It operates on port 25 for unencrypted, 465 for SSL, or 587 for TLS.
When you hit send, your client connects to an SMTP server, authenticates if needed, and transmits the message. The server then relays it toward the recipient's domain.
SMTP uses commands like HELO/EHLO (hello), MAIL FROM (sender), RCPT TO (recipient), DATA (message), and QUIT.
For security, STARTTLS upgrades connections to encrypted.
Here's a Python example using smtplib to send a basic email. This code connects to a test SMTP server (use your own for real tests):
import smtplib
from email.mime.text import MIMEText
# Define email details
sender = 'your_email@example.com'
recipient = 'recipient@example.com'
subject = 'Test Email'
body = 'This is a test email sent via SMTP.'
# Create message
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = recipient
# Connect to SMTP server (use Gmail's for testing, enable less secure apps or use app password)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls() # Upgrade to TLS
server.login(sender, 'your_password') # Replace with actual password
# Send email
server.sendmail(sender, recipient, msg.as_string())
server.quit()
# Output: No console output if successful; raises SMTPException on failure.
SMTP is outbound-focused and doesn't handle retrieval.
See the SMTP RFC 5321 for full specs.
POP3 and IMAP: Fetching Emails
Post Office Protocol version 3 (POP3) and Internet Message Access Protocol (IMAP) retrieve emails from servers to clients.
POP3 downloads messages to your device and often deletes them from the server. It uses port 110 (unencrypted) or 995 (SSL). Commands include USER/PASS for login, LIST for message list, RETR for retrieve, DELE for delete.
IMAP keeps emails on the server, syncing across devices. It supports folders and flags (read/unread). Ports: 143 (unencrypted), 993 (SSL). Commands: LOGIN, SELECT (folder), FETCH (messages).
IMAP is better for multi-device use, while POP3 suits single-device setups.
Comparison table:
Protocol | Storage | Sync | Best For |
---|---|---|---|
POP3 | Local download | No | Offline access |
IMAP | Server-based | Yes | Multiple devices |
Choose IMAP for modern workflows to avoid data loss.
Here's a Python POP3 example to list and fetch an email:
import poplib
from email.parser import Parser
# Connect to POP3 server (use your provider)
server = poplib.POP3_SSL('pop.gmail.com', 995)
server.user('your_email@example.com')
server.pass_('your_password') # Replace with actual password
# Get message count
num_messages = len(server.list()[1])
print(f'Number of messages: {num_messages}')
# Fetch first message if exists
if num_messages > 0:
response, lines, octets = server.retr(1)
msg_content = b'\r\n'.join(lines).decode('utf-8')
msg = Parser().parsestr(msg_content)
print(f'Subject: {msg["subject"]}')
server.quit()
# Output example:
# Number of messages: 5
# Subject: Test Email
Explore IMAP RFC 3501 for details.
MIME: Attachments and Content Types
Multipurpose Internet Mail Extensions (MIME) extends email to support non-text content like images, PDFs, or HTML.
MIME defines content types (e.g., text/plain, image/jpeg) and encodings (base64 for binaries). Messages can be multipart, mixing text and attachments.
Headers like Content-Type and Content-Transfer-Encoding tell clients how to parse.
Without MIME, emails were text-only.
Example MIME structure in an email:
- Content-Type: multipart/mixed; boundary="boundary-string"
Then parts separated by --boundary-string.
MIME makes emails versatile for modern use.
In the SMTP code above, we used MIMEText for the body.
Check the MIME RFC 2045 for standards.
DNS in Email Routing
Domain Name System (DNS) resolves email domains to servers. When sending, SMTP queries MX (Mail Exchanger) records for the recipient's domain.
For example, for example.com, DNS returns MX records like mail.example.com with priorities.
Other records: TXT for SPF/DMARC, A/AAAA for IP addresses.
Without DNS, servers couldn't find each other.
Use dig for checks:
dig MX example.com
# Output example:
# ;; ANSWER SECTION:
# example.com. 3600 IN MX 10 mail.example.com.
MX records prioritize backup servers for reliability.
Python example with dnspython:
import dns.resolver
# Query MX records
domain = 'example.com'
answers = dns.resolver.resolve(domain, 'MX')
for rdata in answers:
print(f'Priority: {rdata.preference}, Server: {rdata.exchange}')
# Output example:
# Priority: 10, Server: mail.example.com.
See DNS RFC 1035 for basics.
Email Servers and Their Roles
Email servers run software like Postfix (MTA), Dovecot (IMAP/POP3), or Exim.
An outgoing server (SMTP) relays to the recipient's incoming server, which stores in mailboxes.
Clients connect via POP3/IMAP to fetch.
In setups, one server might handle all, or separate for scale.
Common flow: User -> MUA -> SMTP server -> Recipient's MX -> MDA -> Recipient's MUA.
Servers ensure emails route correctly across the internet.
For setup, try Postfix documentation.
Security Layers: TLS, SPF, DKIM, DMARC
Security prevents spam and spoofing.
TLS encrypts connections (e.g., STARTTLS in SMTP).
SPF (Sender Policy Framework) checks if sender IP is authorized via DNS TXT.
DKIM (DomainKeys Identified Mail) signs messages with private keys, verified by public DNS keys.
DMARC aligns SPF/DKIM and sets policies (quarantine/reject fails).
These reduce phishing.
Table of protections:
Protocol | Purpose | How It Works |
---|---|---|
TLS | Encryption | Secures data in transit |
SPF | Auth sender IP | DNS TXT record check |
DKIM | Message integrity | Cryptographic signature |
DMARC | Policy enforcement | Builds on SPF/DKIM |
Implement all for robust security.
Verify with DMARC RFC 7489.
Tracing an Email's Journey Step by Step
Let's walk through sending an email from alice@example.com to bob@domain.com.
Alice's client composes and connects to her SMTP server via TLS.
SMTP server authenticates, accepts message.
Queries DNS for domain.com's MX record, connects to that server.
Recipient server checks SPF/DKIM/DMARC; if pass, stores via MDA.
Bob's client fetches via IMAP, verifying TLS.
If fails: Bounces back.
Example headers show path:
Received: from smtp.example.com by mail.domain.com
Each step logs for troubleshooting.
Use tools like telnet for manual SMTP tests:
telnet smtp.example.com 25
EHLO me
MAIL FROM:<alice@example.com>
RCPT TO:<bob@domain.com>
DATA
Subject: Hello
Hi Bob.
.
QUIT
# Output: Server responses like 250 OK, 354 Start mail input.
This setup shows how protocols link for reliable delivery.
Understanding these connections helps debug issues like bounces or spam filters. Experiment with local servers or APIs to see it in action—tools like Python's libraries make it accessible for developers.
Top comments (0)