D. J. Bernstein
Internet mail
SMTP: Simple Mail Transfer Protocol

The MAIL, RCPT, and DATA verbs

The server keeps track of an envelope for the client.

The envelope contains any number of envelope recipient addresses and at most one return path. The envelope is empty when it contains no addresses.

When the client connects to the server, the envelope is empty.

For example, after the following responses and requests, the envelope contains the return path djb@silverton.berkeley.edu, the recipient address God@heaven.af.mil, and the recipient address angels@heaven.af.mil:

     220 heaven.af.mil ESMTP
     MAIL FROM:<djb@silverton.berkeley.edu>
     250 ok
     RCPT TO:<God@heaven.af.mil>
     250 ok
     RCPT TO:<devils@heaven.af.mil>
     550 wrong address, buddy
     RCPT TO:<angels@heaven.af.mil>
     250 ok

The MAIL verb

The point of a MAIL request is to set the envelope return path and clear the list of envelope recipient addresses.

A MAIL request has a parameter containing

  1. the string "FROM:" in any combination of uppercase and lowercase;
  2. an encoded return path: either the empty string, encoded as <>, or an encoded address; and
  3. extra information.
If the server accepts the MAIL request, then the new envelope contains the return path specified in MAIL, and no recipient addresses. The server is required to use code 250 here.

If the server rejects the MAIL request, the client cannot make any assumptions about the envelope. The envelope could be empty, for example, or it could be the same as it was before the MAIL request. Klensin requires that the envelope be the same, but this is not always true in practice.

Beware that many servers incorrectly reject MAIL requests when the envelope is nonempty. For example, sendmail responds with code 503.

RFC 821 does not permit extra information at the end of a MAIL request. In practice, however, some clients (e.g., at least one version of the Netscape SDK) put extra spaces at the end of MAIL. Furthermore, extensions such as 8BITMIME make use of the extra information.

RFC 821 lets the server use codes 421, 451, 452, 500, 501, or 552 to reject a MAIL request; RFC 1869 also permits code 555. Typical examples:

     MAIL FROM:<angels@heaven.af.mil> blah blah blah blah blah
     500 line too long
     MAIL FROM:<angels@heaven.af.mil> garbage
     555 garbage not permitted
     MAIL FROM:>angels@heaven.af.mil<
     501 malformatted address
     MAIL FROM:<took.three.hours.to.send.this@heaven.af.mil>
     451 timeout

The RCPT verb

The point of a RCPT request is to add one address to the list of envelope recipient addresses.

A RCPT request has a parameter containing

  1. the string "TO:" in any combination of uppercase and lowercase;
  2. an encoded recipient address; and
  3. extra information.
If the server accepts the RCPT request, the new envelope is the same as the previous envelope, plus the recipient address specified in the RCPT request. The server is required to use code 250 or 251 here. 251 indicates that mail to this recipient will be forwarded, and gives the new forwarding address:
     RCPT TO:<God@heaven.af.mil>
     250 no problem
     RCPT TO:<angels@heaven.af.mil>
     251 okay; will forward your mail to <angels@sun.af.mil>
Today's clients discard the text, whether the code is 250 or 251, so this is not a good way to provide forwarding information. Code 251 is deprecated by Klensin. I use a simple "250 ok" in all cases.

If the server rejects the RCPT request, the envelope is unchanged.

MAIL must be used before RCPT. Servers reject RCPT requests (using code 503) when the envelope is empty.

It is a violation of RFC 821 for the client to send RCPT if the envelope already contains 100 recipient addresses. It is also a violation of RFC 821 for the server to limit its envelope to fewer than 100 recipient addresses. Nevertheless, some servers set much lower limits.

RFC 821 lets the server use codes 421, 450, 451, 452, 500, 501, 503, 550, 551, 552, or 553 to reject a RCPT request; RFC 1869 also permits code 555. Typical examples (out of context):

     450 mailbox busy, try again later
     452 recipient out of disk space, try again later
     452 too many recipients
     503 need MAIL before RCPT
     550 no such recipient here
     551 recipient has moved; try <aj@fires.af.mil>
     553 we don't relay mail to remote addresses

The DATA verb

The point of a DATA request is to send mail.

DATA parameters are prohibited. Some servers reject any DATA request with a nonempty parameter.

MAIL and RCPT must be used before DATA. Servers reject DATA requests (using code 503) unless the envelope contains a return path and at least one recipient address.

If the server accepts the DATA request (required code 354), the client sends an encoded message.

If the server accepts the message (required code 250), it is accepting responsibility for delivering the message to each of the recipient addresses in the envelope, or notifying the return path (if it is nonempty) if some deliveries are not made:

     MAIL FROM:<God@heaven.af.mil>
     250 ok
     RCPT TO:<angels@heaven.af.mil>
     250 ok
     DATA
     354 ok

     Hi, guys.
     Just testing our new mail system.
     .
     250 Written safely to disk. #902487694.289148.12219.
Many clients save this final 250 response as a receipt; I recommend that the server include enough information that the local system administrator can track down the message in his logs.

If the server accepts the DATA request and the message, the new envelope is empty. (Exception: A server called David reportedly leaves the envelope recipients alone through both DATA and MAIL.) Otherwise the client cannot make any assumptions about the envelope.

RFC 821 lets the server use codes 421, 451, 500, 501, 503, or 554 to reject a DATA request. Typical examples (out of context):

     451 unable to set up internal message buffer
     503 need RCPT before DATA
RFC 821 lets the server use codes 451, 452, 552, or 554 to reject a message. Typical examples (out of context):
     552 sorry, this message is too large for my disk
     554 too many hops, this message is looping