SMTP check with telnet

A practical guide to testing an email server by hand. Learn what every SMTP command does, how the server answers, and how to run a full verification session with telnet or openssl.

SMTP (Simple Mail Transfer Protocol) is a plain-text, line-based protocol. That means you can talk to a mail server directly from a terminal and read exactly what it answers — no special software required. This is the most transparent way to check whether a mailbox exists, whether a server is reachable, and how it is configured.

1. Connecting to a mail server

First find the mail server (MX host) for the domain, then open a TCP connection to its SMTP port. The classic port is 25. Submission ports 587 and 2525 are used with STARTTLS; port 465 is implicit TLS (SMTPS).

Plain connection (port 25):

telnet mail.example.com 25

STARTTLS port (587 or 25) — telnet can't do TLS, use openssl:

openssl s_client -connect mail.example.com:587 -starttls smtp -crlf

Implicit TLS port (465):

openssl s_client -connect mail.example.com:465 -crlf

Note: many home and mobile ISPs block outgoing port 25 to fight spam. If telnet ... 25 just hangs, that is usually your provider, not the mail server. Test from a server/VPS where port 25 is open, or use submission ports.

2. SMTP commands explained

You type commands (case-insensitive); the server replies with a 3-digit code and text. End every command with Enter (CRLF).

CommandWhat it does
HELO domainLegacy greeting. Identifies the connecting host by name. The server replies 250.
EHLO domainModern greeting (Extended HELO). Same as HELO but the server also lists supported extensions (STARTTLS, AUTH, SIZE, PIPELINING…).
MAIL FROM:<addr>Starts a new message and sets the envelope sender (the “return path”). Reply 250 if accepted.
RCPT TO:<addr>The key command for verification. Asks the server to accept a recipient. 250 = the mailbox is accepted; 550 = no such user; 4xx = try later (e.g. greylisting).
DATABegins the message body. Server replies 354; you send headers + body and finish with a single dot . on its own line. (For a verification check you never reach this step.)
RSETResets the current transaction (forgets MAIL FROM / RCPT TO) without closing the connection.
VRFY userAsks the server to verify a username/address. Designed for exactly this, but almost always disabled today (returns 252 or 502) because it leaks valid addresses to spammers.
EXPN listAsks the server to expand a mailing list into its members. Like VRFY, disabled almost everywhere for the same privacy reason.
STARTTLSUpgrades a plain connection to encrypted TLS (on ports 25/587). Offered only if listed in the EHLO reply.
AUTH LOGIN / PLAINAuthenticates a user (needed to send mail through submission ports, not for verification).
NOOPDoes nothing; server replies 250. Useful to keep a connection alive or test responsiveness.
HELPAsks the server to list the commands it supports.
QUITPolitely ends the session. Server replies 221 and closes the connection.

3. Response codes

The first digit tells you the category, so you can read any reply even if you don't know the exact code:

  • 2xx — success (command accepted).
  • 3xx — intermediate, the server wants more input (e.g. 354 after DATA).
  • 4xx — temporary failure: try again later. The address may still be valid.
  • 5xx — permanent failure: the command or address was rejected.
CodeMeaning
220Service ready (the greeting banner).
221Closing connection (reply to QUIT).
250OK — command accepted (the answer you want after RCPT TO).
251 / 252User not local but will be forwarded / cannot verify but will try to deliver.
354Start sending the message body (after DATA).
421Service not available, closing — often rate-limiting.
450 / 451 / 452Temporary problem (mailbox busy, local error, low storage). Greylisting frequently shows up here.
502Command not implemented (typical reply to VRFY / EXPN).
550Mailbox unavailable / no such user — the address does not exist.
551 / 552 / 553 / 554User not local / over quota / bad mailbox name / transaction failed.

4. A full worked example

Checking whether john@example.com exists. Lines you type are marked >; everything else is the server:

$ telnet mail.example.com 25 220 mail.example.com ESMTP ready > EHLO checkemail.test 250-mail.example.com Hello checkemail.test 250-STARTTLS 250-SIZE 52428800 250 PIPELINING > MAIL FROM:<probe@checkemail.test> 250 2.1.0 Ok > RCPT TO:<john@example.com> 250 2.1.5 Ok ← mailbox EXISTS > RSET 250 2.0.0 Ok > QUIT 221 2.0.0 Bye

If instead the recipient does not exist you would see something like:

> RCPT TO:<nosuchuser@example.com> 550 5.1.1 <nosuchuser@example.com>: Recipient address rejected: User unknown

5. Things that make results uncertain

  • Greylisting — the server returns a temporary 4xx on the first attempt on purpose, asking you to come back later. A 4xx does not mean the address is invalid.
  • Catch-all domains — some servers accept every recipient with 250 and sort it out later. Then RCPT TO can't prove a specific mailbox exists. To detect a catch-all, try a clearly random address: if it is also accepted, the domain is catch-all.
  • Anti-abuse defenses — servers may delay, hide the real status, or block repeated probes from one IP. Test politely and don't hammer a server.
  • VRFY / EXPN disabled — don't rely on them; RCPT TO is the practical signal.

Want this done automatically, including MX lookup, catch-all detection and a clean verdict? Use our Email Checker on the home page.