500 is a permanent failure meaning the SMTP server could not recognise the command you sent at all. This sits one level more basic than 501 (command recognised, but its parameters have a syntax error) or 504 (command recognised, but a specific parameter is unimplemented). A 500 means the verb itself - the first word of the line - did not match anything in the server's command table, commonly because of a typo, a stray control character, a line-ending problem, or a command the destination server simply never implemented.
Who is at fault
This is a sending-client fault, full stop. Nothing about the recipient, their mailbox, or your domain reputation is involved. A custom script with a typo, a malformed template that inserted garbage into the command stream, or line-ending corruption (CRLF vs LF) in a hand-built SMTP session are the usual causes. A less obvious variant worth checking: some templating engines insert invisible formatting
characters - a byte-order mark, a non-breaking space copied from a word processor, or a
zero-width character from a pasted Unicode string - directly into what is supposed to be a plain
SMTP command line. These characters are invisible in most text editors and terminal output, so a
visual inspection of the logged command can look completely correct even when it contains the
exact character causing the 500. A byte-level dump (xxd or equivalent) is the only reliable way
to rule this out when a command looks fine but still fails. Keep a small library of known-bad
byte sequences you have encountered before - a particular smart-quote character, a specific
non-breaking space - so future incidents can be matched against a pattern you have already solved
rather than re-diagnosed from scratch each time. Most of these recur because the same upstream
source (a particular spreadsheet template, a particular copy-paste habit) keeps producing them,
so fixing the source eventually matters more than catching each individual occurrence downstream.
The exchange
220 mx.example.com ESMTP ready EHLO mail.yourdomain.com 250-mx.example.com 250 SIZE 35882577 MIAL FROM:<sender@yourdomain.com> 500 5.5.1 Command unrecognized: "MIAL FROM:<sender@yourdomain.com>"
The single transposed letter (MIAL instead of MAIL) is enough for the server to reject the entire line - SMTP command verbs must match exactly.
How Gmail, Microsoft 365 and Yahoo word the same condition
| Provider | Wording |
|---|---|
| Gmail | 500 5.5.1 Unrecognized command |
| Microsoft 365 | 500 5.3.3 Unrecognized command |
| Yahoo | 500 5.5.2 Command not recognized |
The wording is nearly identical across all three because this part of the protocol is implemented almost verbatim from the RFC across every mainstream mail server.
Diagnostic commands
Capture the literal bytes your client sends; a subtle encoding issue (bare LF instead of CRLF, or a hidden character from a copy-paste) is the usual cause and is invisible in most application logs:
$ nc -C mx.example.com 25 220 mx.example.com ESMTP ready EHLO test.local 250-mx.example.com MIAL FROM:<test@example.com> 500 5.5.1 Command unrecognized $ echo -e "EHLO test\r\nMAIL FROM:<test@example.com>\r\n" | xxd | head -5
nc -C translates LF to CRLF automatically, which also helps rule out a line-ending bug versus a genuine typo - if the command works through nc -C but not through your application, the bug is in how your application terminates lines.
The ordered fix
- Capture the exact bytes your application sends with a raw TCP tool, not an application-level log that may already be "cleaning up" the string.
- Check for a typo in the command verb itself. Confirm
MAIL,RCPT,DATA,EHLOare spelled and cased correctly - SMTP commands are case-insensitive but must be spelled correctly. - Check line termination. SMTP requires CRLF (
\r\n); a client emitting bare\ncan produce malformed commands on strict servers. - Check for template injection. If the command string is built from a template, confirm no stray text or whitespace is being inserted before the verb.
- Re-test against a local debug SMTP server (e.g.
python3 -m smtpd -n -c DebuggingServer) before resuming live sends.
What not to do
- Do not retry the exact same command. A hardcoded typo or encoding bug will reproduce the same 500 every single time.
- Do not treat this as a deliverability or blocklist issue. It will never appear in a blocklist query or affect your sending reputation; it is a local protocol bug.
- Do not add retry delays or backoff logic. Waiting does nothing when the problem is a malformed command string.
- Do not assume this is provider-specific. Because command parsing is nearly identical across providers, a 500 reproducing against one destination will almost always reproduce against any destination with the same buggy client.
Spotting this bug before it reaches production
A 500 from a typo or encoding issue is one of the easiest SMTP bugs to catch early, because it is
completely deterministic - the same malformed input always produces the same rejection. Add a
smoke test that sends one message through your actual client code against a local debug SMTP
server as part of your deployment pipeline, and compare the command sequence byte-for-byte against
a known-good reference session. Catching this in a test environment costs minutes; catching it
after a batch has already partially failed in production costs considerably more.
MailPilot's warm-up and sending paths use maintained SMTP libraries with correct line termination and command formatting for every connection type it supports, which is why protocol-level errors like this never originate from MailPilot's own traffic.
Ready to reach the inbox every time?
Automated email warmup across real peer mailboxes. Live inbox placement monitoring. Free 7-day trial - no credit card required.
Start free trial