Valid HTML 4.0!

Introduction to SMTP

This is gonna be like a small info bulletin on how email is sent.

Copyright © 2000 by Philip S Tellis

Creative Commons License
This work is licensed under a Creative Commons License.

Important Commands

When one sends mail using the SMTP protocol, one has only the following commands:

HELO
Greet the mail server. Used once per session - at the beginning of the session.
MAIL FROM: <from>
Announce who the sender is. Used once per mail, before specifying any recipients for each mail, or after a RSET.
RCPT TO: <rcpt>
Announce who the mail is to. Multiple recipients are allowed, each must have its own RCPT TO: entered immediately after a MAIL FROM:
DATA
Starts mail entry mode. Everything entered on the lines following DATA is treated as the body of the message and is sent to the recipients. The DATA terminates with a . (period) on a line by itself. A mail may be queued or sent immediately when the . is entered. It cannot however be reset at this stage.
RSET
Reset the state of the current transaction. The MAIL FROM: and RCPT TO: for the current transaction are cleared.
QUIT
End the session. No commits happen here.

All other commands simply extend the usage of these. There are also commands that come under the ESMTP protocol (Extended) that I will not cover here.

Looking at the commands above, one notices a few things:

  1. Almost all commands need an argument. The exceptions are RSET and QUIT.
  2. DATA takes a multiline argument on the line after DATA has been acknowledged.
  3. If multiline arguments (like DATA) terminate with a . on a line by itself, then how does one enter a . on a line by itself?
  4. What about the other header fields? Subject:, Reply-To:, custom headers etc?
  5. There is no provision for attaching files.

I'll cover point 5 in a different discussion, but for now, let's look at points 1 through 4.

HELO, MAIL FROM: and RCPT TO: tell the SMTP server all it needs to know to get the mail through, and bounce it in case of error. HELO isn't really required, but ensures that the client and server are speaking the same language. (Ref: EHLO)

DATA tells the SMTP server what the contents of the mail are. The contents of /var/spool/mail/$USER or equivalent will show what was typed as DATA, with maybe a few lines added by the SMTP server and mail client.

Escaping a . is the same as escaping a \ in C. Preceed it with another . In fact, the SMTP protocol states that any line that starts with a . should be preceeded by another . So if I wanted to say this:

    . is a period

I would have to enter this:

    .. is a period

The MUA is supposed to translate .. at the start of a line into .

Mail Headers

Sending a mail directly using the SMTP protocol will produce a mail with only the From: and Date: header fields set. To enter other fields, they must be entered as the first part of the DATA, separated from the actual body by a completely blank line. Not even white space is allowed on this line. eg:

    DATA
    354 Enter Data end with .
    From: philip@mymachine
    To: linuxers@ilug-bom.org.in
    Subject: SMTP - [informational]

    This is gonna be like a small info bulletin on how...
    ...
    .
    250 Mail accepted for delivery

When the mail is received, the MUA separates the header from the rest of the body.

One might ask why the To: header field is not included. On the face of it, it seems logical that the To: header should be included along with the From and Date as default headers, but think closely about this. When sending a mail, recipients may be in the To: list, Cc: list and Bcc: list. The To and Cc list behave the same way, but the Bcc list is a list of all recipients whose addresses must not show up in the mail header. As already noted, all recipients are specified using the RCPT TO: command, and there is no way for the SMTP server to distinguish between different types of recipients - nor should it care. It is the responsibility of the origin MUA to properly format the mail header, including only those headers that should be included, and excluding those that shouldn't.

This should in theory always work, except that some old MTAs messed up, and included the To: header if none was specified. To work around it, many MUAs add a To: Undisclosed Recipients if no recipients are specified. This is done at the sender's end, not at the recipient's end.

Return Values

Now that we've had a look at the SMTP commands, and what each does, let's look at return values. All SMTP responses are three digit numbers followed by a single white space and an optional text message.

Multiline responses are signalled with a hyphen as the fourth character instead of a space. Every line of a multiline response starts with the three digit code and a hyphen. The last line has a space as the fourth character. As a general rule, a space as the fourth character signifies end of response.

On connect, an SMTP server responds with a 220 if it is able to serve the request. Any other return code should be considered an error.

HELO, MAIL FROM: and RCPT TO: are responded to with a 250 which is the catch-all success message. In general, responses that start with a 2 are successes and responses that start with a 5 are errors. Common errors for these are 501 - syntax error, 503 - duplicate command, 550 - user unkown. Other errors may be server specific.

The DATA command is not a complete command, since the SMTP server must await further data. It responds with a 354 signifying that it is awaiting further data. On receipt of this data (when it receives a single . on a line by itself), it responds with a 250 on success, or a 5xx on failure.

The QUIT command signs off from the SMTP server, and it responds with a 221.

Following is the complete list of SMTP replies ordered by functional group:

User Errors

500
Syntax error, command unrecognized [This may include errors such as command line too long]
501
Syntax error in parameters or arguments
502
Command not implemented
503
Bad sequence of commands
504
Command parameter not implemented

Status

211
System status, or system help reply
214
Help message [Information on how to use the receiver or the meaning of a particular non-standard command; this reply is useful only to the human user]

Success

220
<domain> Service ready
221
<domain> Service closing transmission channel
250
Requested mail action okay, completed
251
User not local; will forward to <forward-path>
354
Start mail input; end with <CRLF>.<CRLF>

System Errors

421
<domain> Service not available, closing transmission channel [This may be a reply to any command if the service knows it must shut down]
450
Requested mail action not taken: mailbox unavailable [E.g., mailbox busy]
550
Requested action not taken: mailbox unavailable [E.g., mailbox not found, no access]
451
Requested action aborted: error in processing
551
User not local; please try <forward-path>
452
Requested action not taken: insufficient system storage
552
Requested mail action aborted: exceeded storage allocation
553
Requested action not taken: mailbox name not allowed [E.g., mailbox syntax incorrect]
554
Transaction failed

Sample

Finally, I'll list a sample SMTP session. I'll use < to mark lines that the server sends back.

    $telnet localhost 25
 <  220 localhost ESMTP Sendmail 8.9.3/8.9.1
    HELO localhost
 <  250 localhost Hello localhost [127.0.0.1], pleased to meet you
    MAIL FROM: philip
 <  250 philip... Sender ok
    RCPT TO: philip
 <  250 philip... Recipient ok
    DATA
 <  354 Enter mail, end with "." on a line by itself
    Checking SMTP transactions.
    .
 <  250 SAA11703 Message accepted for delivery
    QUIT
 <  221 localhost closing connection

I hope that this little primer will help people understand how SMTP works.

Philip