How IT Works
How Simple is SMTP?
SMTP, the Simple Mail Transfer Protocol, carries the electronic mail of the world. While other message transferring systems exist—some more efficient, some better at specific tasks, some privately owned and some public—none have won the widespread public acceptance of the venerable SMTP, first defined in RFC 821, all the way back in 1982.
But how does SMTP work? The "Simple" part of the name is pure truth in advertising. A message can be moved from one SMTP server to another using one of the simplest TCP/IP protocols (line-oriented telnet) and just a few simple text commands. One SMTP server makes a telnet-like connection to TCP port 25 on the other; it then sends commands and data, receiving numeric responses.
This process can be simulated with any telnet client. In fact, in the early days of the grand network unification of ARPAnet, Bitnet, Edunet, and several other major networks, a lot of testing was done this way, with developers connecting to an SMTP server and typing commands at it, just to see what would happen. To do this yourself, run telnet from a command prompt and connect to an online SMTP mail server on TCP port 25. The server will send back a response that looks a lot like this:
C:\> telnet newmoon.microsoft.net 25
Connected to newmoon.microsoft.net.
Escape character is ‘^]’.
220 newmoon.microsoft.net Microsoft ESMTP MAIL Service, Version:
6.0.3790.1830 ready at Sun, 15 May 2005 22:56:26 –0700
As easily as that, the client machine is ready to talk to that SMTP server as if it were an SMTP peer. Type commands, and they’ll be processed and responded to with numeric response codes.
These three-digit coded responses, in this case, 220, may look familiar to Webmasters. The first digit indicates success or failure. 1 indicates a success requiring confirmation, 2 indicates complete success, and 3 indicates success so far, but that more input is expected. 4, the first failure code, is used for failures that may be temporary, such as the mail account existing but being locked; 5 indicates that the failure condition is permanent, such as a syntax error in the command. The second and third digits provide further details, but at the top level, all that matters is that 1xx
, and 3xx
are good, and 4xx and 5xx indicate problems. (For further information on mail response codes, read RFC 1893
EHLO (or HELO) identifies the server initiating the connection (see the sidebar "The Difference Between HELO and EHLO?" to understand the difference between the two). It also tells the receiving server to clear its slate. The format is:
EHLO <network name of connecting machine>
The parameter is mandatory on all recent SMTP servers, despite the fact that all modern servers will also use DNS to identify your actual domain and machine name, if possible. It will also log the IP address before responding with another three-digit response code (250, in most cases), and a greeting message:
250 newmoon.microsoft.net Hello [127.0.0.1]
The receiving machine has now identified the sending server and is ready to continue.
The sending machine must next provide the mail’s individual sender—that might be the person on the From: line, but it often isn’t; it could, for example, be a mailing list software package, a redirector, or some other agent. This is envelope data, rather than header data:
MAIL FROM: <email address>
The e-mail address must be in a valid format, and with any modern e-mail server, must indicate a valid domain. Invalid MAIL FROM: addresses will be rejected, thusly:
MAIL FROM: sajkdflaef
553 5.5.4 sajkdflaef... Domain name required for sender address sajkdflaef
MAIL FROM: firstname.lastname@example.org
553 5.1.8 email@example.com... Domain of sender address firstname.lastname@example.org does not exist
MAIL FROM: email@example.com
250 2.1.0 firstname.lastname@example.org... Sender ok
Next, the address (or list of addresses) to receive the messages must be specified, as arguments to the RCPT TO: command:
Only one e-mail address may be specified with this command, but the command may be repeated as many times as needed with different addresses as parameters:
RCPT TO: email@example.com
250 2.1.5 firstname.lastname@example.org... Recipient ok
RCPT TO: email@example.com
250 2.1.5 firstname.lastname@example.org ... Recipient ok
Once all addresses have been specified, it’s time to send the actual mail! This includes the actual header as seen by the mail client, then a blank line, then the message body and any attachments. Describing all that is well beyond the scope of this column (see RFC 2822, for starters) but the command to tell the server that it’s time for the actual message isn’t. It’s one of the simplest SMTP commands:
There are no parameters for this command. Barring error, the server will reply:
354 Enter mail, end with "." on a line by itself
(Note a 3xx success code: "successful so far, more input expected.") Then the message header and body should be sent, followed by a period on a line by itself indicating message end. If all goes well, the server will respond to the standalone period with this response code:
250 2.0.0 Message accepted for delivery
And the message is on its way! The connecting server can then start another message (with another MAIL FROM: command), send other SMTP commands, or end the session by sending a QUIT command on a line by itself:
221 2.0.0 microsoft.net closing connection
QUIT must prompt a success error code and connection drop by the server. And that’s all you need to move a piece of mail.
However, there are several other standard commands available: NOOP, RSET, VRFY, and EXPN. These are neither optional nor obsolete, though they are of somewhat limited use in the modern corporate environment. For a complete list of all commands, including obsolete verbs, see RFC 2821, RFC 1123, and RFC 821, available via MSN® Search. Remember that later RFCs supersede earlier ones, and that some commands have been made obsolete, like the TURN, SEND, SOML, and SAML commands described in RFC 821. The simplest of these commands is NOOP, useful mostly in testing to avoid timeouts; it does nothing and can generate only a successful response, with no change in state, as shown here:
RSET clears the MAIL FROM: and RCPT TO: address stacks, throwing out any message delivery in progress, and resetting the connection back to the state it was in just after HELO or EHLO. The command should never cause the server to disconnect or require a new EHLO/HELO exchange. It takes no parameters:
250 2.0.0 Reset state
The command VRFY allows clients to validate individual e-mail addresses. Many postmasters disabled this command early in the spam wars, since some spammers began using it to clean their mailing lists. Support in some form, however, is still required by the SMTP specification. For servers supporting it as described in the RFC, the format is:
VRFY submitted with a valid address returns a canonical expansion of the e-mail address given, complete with friendly name. An invalid address, by contrast, triggers an error code 550:
250 2.1.5 Dara Korra’ti <email@example.com>
550 5.1.1 firstname.lastname@example.org ... User unknown
R'ykandar Korra'ti, postmaster for a small co-op ISP, lives near Seattle with her partner Anna. Having previously shipped mail products at Microsoft, she is now looking at grad school in a CS-related field so esoteric it doesn’t really have a name. Potential faculty advisors can reach her at email@example.com.
© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited
Finally, EXPN historically provided a way to expand a mailing list into its component members. This allowed e-mail clients and servers to identify all the members of such a list. As can be easily imagined, this command, too, was an early casualty of the spam wars. Independently of that, it also became less and less useful as mailing list management software changed, and became less integrated with the MTA (or Message Transfer Agent). Many third-party mailing list management software packages do not provide mail servers with ways of supporting EXPN correctly at all. However, servers that do support it as intended should return all the e-mail addresses of the list members, each prefixed with a success code, or a 550 failure if the list name doesn’t exist:
250 2.1.5 firstname.lastname@example.org
250 2.1.5 email@example.com
250 2.1.5 firstname.lastname@example.org
550 5.1.1 bogus-list ... User unknown
Collectively, these commands complete the minimum required set for SMTP servers. Simple, isn’t it?