To test an SMTP server, connect to it, read its greeting, upgrade to TLS, authenticate, and send a message through it while checking every reply code. The fastest full test is a single swaks command. The manual route is openssl s_client -starttls smtp. A passing test looks like this: 220 greeting, 250 after EHLO, 235 after AUTH, and 250 after the message body. Anything starting with 4 or 5 tells you where it broke.
| Tool | Handles TLS | Best for |
|---|---|---|
nc / telnet | No | Is the port open? Plaintext servers on port 25 |
openssl s_client | Yes (STARTTLS and implicit) | Typing a session by hand and seeing each reply |
swaks | Yes | Repeatable tests, scripts, CI checks |
Step 1: Check that the SMTP port is reachable
nc -vz smtp.example.com 587
telnet smtp.example.com 587
Test-NetConnection smtp.example.com -Port 587
TcpTestSucceeded : True means the TCP connection opened. Microsoft notes you must install the telnet client before using telnet on Windows, so Test-NetConnection is the easier choice there. For port choice and TLS modes, see which SMTP port to use.
Step 2: Run a full SMTP session by hand with OpenSSL
For port 587 (STARTTLS), let s_client do the upgrade:
openssl s_client -starttls smtp -connect smtp.example.com:587 -crlf -quiet
For port 465 (implicit TLS, RFC 8314), skip -starttls:
openssl s_client -connect smtp.example.com:465 -crlf -quiet
-crlf converts the Enter key into CR+LF, which SMTP requires. Plain telnet only works when the server accepts unencrypted sessions, which in practice means port 25 between servers.
The s_client gotcha: your command may never be sent
The OpenSSL documentation says that when you run s_client interactively (neither -quiet nor -ign_eof), “certain commands are recognized” and “these commands are a letter which must appear at the start of a line. All further data after the initial letter on the line is ignored.” The documented letters include Q (end the connection) and R (renegotiate, TLS 1.2 and below only).
So a typed RCPT TO:<...> or QUIT can be swallowed by s_client instead of reaching the server. Two fixes:
- Add
-quiet, as above. It implicitly turns on-ign_eofand-nocommands, so no letters are special. You lose the certificate printout. - Keep the certificate output with
-nocommands(“Do not use interactive command letters”), or type SMTP verbs in lowercase. RFC 5321 says verbs and arguments are not case sensitive, sorcpt to:is valid.
With -quiet, Ctrl-D will not close the connection. Type QUIT.
Annotated example session
This is the SMTP conversation in its rawest form. Lines starting with > are what you type (leave the > off). Everything else is the server’s reply. This is example output with placeholder hosts; wording differs by server.
> EHLO client.example.com
250-smtp.example.com
250-PIPELINING
250-SIZE 35882577
250-AUTH PLAIN LOGIN
250 8BITMIME
> AUTH PLAIN AHVzZXJAZXhhbXBsZS5jb20AcGFzc3dvcmQ=
235 2.7.0 Authentication successful
> MAIL FROM:<[email protected]>
250 2.1.0 Ok
> RCPT TO:<[email protected]>
250 2.1.5 Ok
> DATA
354 End data with <CR><LF>.<CR><LF>
> Subject: SMTP test
> From: [email protected]
> To: [email protected]
>
> Hello from the command line.
> .
250 2.0.0 Ok: queued as 4F1A2B3C
> QUIT
221 2.0.0 Bye
What the 250 capability lines mean:
SIZE: the maximum message size the server accepts (RFC 1870).PIPELINING: several commands per TCP send (RFC 2920).AUTH: the login mechanisms offered. RunEHLOagain after the upgrade, because the list can change.STARTTLS: shown on plaintext connections. After the upgrade, RFC 3207 requires the client to sendEHLOagain.
Create the AUTH credentials
AUTH PLAIN sends one base64 string built as authzid, NUL, username, NUL, password (RFC 4616). The leading NUL leaves the authzid empty:
printf '\[email protected]\0password' | base64
On GNU base64, add -w0 so long strings are not wrapped. For AUTH LOGIN, the server sends two 334 challenges (VXNlcm5hbWU6 is “Username:” and UGFzc3dvcmQ6 is “Password:”), and you answer each with base64 text. LOGIN is not defined in RFC 4954, which covers PLAIN and CRAM-MD5, but many servers still offer it.
Base64 is encoding, not encryption. Only send it over TLS, and use a throwaway or app-specific password: the command and its output can end up in shell history and terminal scrollback.
Step 3: Script the test with swaks
Swaks describes itself as a “featureful, flexible, scriptable, transaction-oriented SMTP test tool.” Install it with brew install swaks or sudo apt-get install swaks, or download the standalone Perl script from the installation page.
Send a message on port 587 with STARTTLS and authentication:
swaks --to [email protected] --from [email protected] \
--server smtp.example.com:587 --tls \
--auth --auth-user [email protected]
--tls requires STARTTLS and exits if TLS is unavailable. Leave out --auth-password and swaks asks for it, keeping it out of your history. To test Microsoft 365, point --server at smtp.office365.com:587 (the Office 365 SMTP settings list what the mailbox needs first). On port 465, use --tls-on-connect, which changes the default port from 25 to 465:
swaks --to [email protected] --from [email protected] \
--server smtp.example.com --tls-on-connect \
--auth --auth-user [email protected]
Useful variations, all from the swaks reference:
--header "Subject: SMTP test"sets or replaces a header.--attach @report.pdfturns the message into multipart/mixed.--quit-after RCPTstops after the recipient is accepted, so nothing is delivered.--output-file smtp-test.logsaves the transcript.
Step 4: Test whether your server is an open relay
An open relay accepts mail from anyone for any destination. A correctly configured server refuses an unauthenticated RCPT TO for a domain it does not host. RFC 5321 says that when a server declines to relay for policy reasons, “a 550 response SHOULD be returned”, usually with enhanced code 5.7.1 (“Delivery not authorized, message refused” in RFC 3463).
Run this from a machine outside your network, without credentials, against a server you own or are authorized to test:
swaks --to [email protected] --from [email protected] \
--server mail.example.com --quit-after RCPT
A 550 at the RCPT TO stage is a pass. A 250 means the server relays for strangers. Details on the rejection are in 550 relay denied, and the concept is covered in SMTP relay.
Step 5: Confirm delivery and authentication results
A 250 after the message body means the server accepted it, not that it reached the inbox. Send to a mailbox you control, open the raw message, and read the headers. The Authentication-Results header, defined in RFC 8601, records the outcome of SPF, DKIM, and DMARC checks, and the Received lines show each hop. If any check fails, review SPF, DKIM, and DMARC. Seed-list tools can check spam-folder placement across providers.
SMTP reply codes you will see during a test
Rule of thumb: per RFC 5321, 2xx means done, 3xx means send more, 4xx means temporary failure so retry, and 5xx means permanent failure so change something before retrying.
| Code | Meaning | What to check |
|---|---|---|
| 220 | Service ready (greeting) | Nothing, this is a pass |
| 250 | Requested action okay | Pass at each step |
| 334 | AUTH challenge (base64) | Answer with base64 text |
| 235 | Authentication succeeded | Pass |
| 354 | Start mail input, end with <CRLF>.<CRLF> | Send headers, body, then a lone . |
| 221 | Closing the channel | Normal end after QUIT |
| 421 | Service not available, closing | Server overloaded or shutting down; retry later |
| 450 | Mailbox unavailable (temporary) | Recipient mailbox temporarily unavailable; retry |
| 451 | Local error in processing | Server-side fault; retry later |
| 530 | Authentication required, or Must issue a STARTTLS command first | Run STARTTLS and AUTH before MAIL FROM |
| 535 | Authentication credentials invalid | Username, password, or app password |
| 550 | Mailbox unavailable or refused by policy | Address, relay rules, or blocklist |
| 552 | Exceeded storage allocation | Message too large or mailbox full |
| 554 | Transaction failed | Generic failure; read the text after the code |
Sources: RFC 5321 section 4.2, RFC 4954 for 334, 235, 530, 535, and RFC 3207 for the STARTTLS form of 530.
Test SMTP from Python with debug output
smtplib prints the whole session when you call set_debuglevel(1), which “results in debug messages for connection and for all messages sent to and received from the server”:
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg["From"] = "[email protected]"
msg["To"] = "[email protected]"
msg["Subject"] = "SMTP test"
msg.set_content("Hello from smtplib.")
with smtplib.SMTP("smtp.example.com", 587, timeout=15) as s:
s.set_debuglevel(1)
s.ehlo()
s.starttls()
s.ehlo() # required again after STARTTLS
s.login("[email protected]", "app-password")
s.send_message(msg)
For implicit TLS, use smtplib.SMTP_SSL (default port 465, no starttls()).
When an online SMTP tester is the better choice
Many ISPs and cloud providers block outbound port 25, so a local test can fail even when the server is fine. An online tester connects from outside your network. MxToolbox’s SMTP diagnostic, for example, says it will “connect to a mail server via SMTP, perform a simple Open Relay Test and verify the server has a reverse DNS (PTR) record.” Use one when you cannot reach the server yourself.
Frequently Asked Questions
How do I test if my SMTP server is working?
Connect on its submission port, read the 220 greeting, send EHLO, upgrade to TLS, authenticate, and send a message to a mailbox you control. One swaks command with --tls and --auth does it all. Every step should return a 2xx or 3xx code.
How do I test SMTP authentication?
Use swaks --auth --auth-user <user> --server <host>:587 --tls and enter the password when prompted, or type AUTH PLAIN <base64> in an openssl s_client session. A 235 reply means the credentials were accepted. A 535 means they were rejected.
Can I use telnet to test SMTP on port 587?
Only partly. Telnet can show that port 587 is open and print the 220 greeting, but it cannot perform STARTTLS, and port 587 servers normally require TLS before authentication. Use openssl s_client -starttls smtp -connect host:587 for a full test.
Why does my SMTP test time out?
A timeout usually means a firewall is dropping the connection, not that the server rejected you. Outbound port 25 is commonly blocked by ISPs and cloud hosts. Test 587 with nc -vz host 587, then try 465 if the provider supports it.
How do I check if my mail server is an open relay?
From outside your network, connect without authenticating, send MAIL FROM with any address, then RCPT TO for a domain your server does not host. A 550 (usually 5.7.1) is correct. A 250 means it relays for anyone. Only test servers you own or are authorized to test.
What does “530 Must issue a STARTTLS command first” mean?
The server requires an encrypted session before it accepts mail commands. RFC 3207 allows it to refuse everything except NOOP, EHLO, STARTTLS, and QUIT until TLS is negotiated. Run STARTTLS (or use openssl s_client -starttls smtp, or swaks --tls), then send EHLO again.
I’ve spent my career building software at scale with a soft spot for email: deliverability, lifecycle campaigns, and getting messages to actually land. I started Coldletter to fix what bugged me about transactional and marketing email tools. I’m based in Vancouver.
