[Top] [All Lists]

Re: rfc2821bis-01 Issue 18: Usability of 1yz replies

2007-04-23 04:59:37

Tony Hansen wrote:
In order to help put this issue to bed, I'd like to get more input from
actual SMTP deployments.

For example, we've heard from one of the Exim developers that it uses
the first code returned. And sendmail's & Hector's code reportedly uses
the last.

So I decided to check out some of the accessible open source code bases,
focusing on the server code that *sends* email to the next MTA.


I appreciate you taking the time to explore this. Btw, Hector's code is called Wildcat! SMTP (wcSMTP)

Are you looking for CONTINUATION or NON-CONTINUATION lines?

I verified that sendmail definitely uses the last code and the Exim code
definitely uses the *first* code of the response set.

Already confirm with sendmail last week.

But with Exim, per specification Exim definitely uses the first *non-continuation* reply code. Below is the loop in the function smtp_read_response() with loop break based on the first non-dash line encountered. The behavior is also documented as such in the comment block:

for (;;)
  if ((count = read_response_line(inblock, ptr, size, timeout)) < 0)
    return FALSE;

    debug_printf("  %s %s\n",
           (ptr == buffer)? "SMTP<<" : "      ", ptr);

  /* Check the format of the response: it must start with three digits;
     if these are followed by a space or end of line, the response is
-->  complete. If they are followed by '-' this is a multi-line response
--> and we must look for another line until the final line is reached.
     The only use made of multi-line responses is to pass them back as
     error messages. We therefore just concatenate them all within the
     buffer, which should be large enough to accept any reasonable
     number of lines. */

  if (count < 3 ||
     !isdigit(ptr[0]) ||
     !isdigit(ptr[1]) ||
     !isdigit(ptr[2]) ||
     (ptr[3] != '-' && ptr[3] != ' ' && ptr[3] != 0))
    errno = ERRNO_SMTPFORMAT;    /* format error */
    return FALSE;

  /* If the line we have just read is a terminal line, line, we
     are done. Otherwise more data has to be read. */

  if (ptr[3] != '-') break;  <--------- BREAK OUT OF LOOP

  /* Move the reading pointer upwards in the buffer and
     insert \n between the components of a multiline response.
     Space is left for this by read_response_line(). */

  ptr += count;
  *ptr++ = '\n';
  size -= count + 1;

AT&T's own MTA's code uses the last code, ignoring the code on all
previous continuation lines.

Smail uses the *first* code.

Looking for source. Do you have a URL?

hMailServer appears to use the *first* code.

Per specification, it looks for the first NON-CONTINUATION reply code, however, this code is buggy and shouldn't be included in your test. It only looks for hard coded "250" values and it only supports 1 extra multiple line from what I can see. This would be the least of its problems. Throw this one out.

qmail uses the *first* code.

Yes it does - but it should noted it is doesn't care for continuation lines which is obvious broken code and n violation of the formal reply-code[sp] specification.

unsigned long smtpcode()
  unsigned char ch;
  unsigned long code;

  if (!stralloc_copys(&smtptext,"")) temp_nomem();

  get(&ch); code = ch - '0';
  get(&ch); code = code * 10 + (ch - '0');
  get(&ch); code = code * 10 + (ch - '0');
  for (;;) {
    if (ch != '-') break;   <---------- BREAK ON NON-DASH
    while (ch != '\n') get(&ch);
  while (ch != '\n') get(&ch);

  return code;  <--- return first code -- BROKEN CODE!

It simply isn't following specs.  Do you wish to encourage this behavior?

postfix appears to use the *last* code.
jsmtp uses the *last* code.

Courier generally uses the *first* code. In some cases it actually
treats 1yz, 2yz and 3yz as equivalent and will totally miss any
subsequent 4yz/5yz.

What about the first non-continuation for its reply?

The use of the first response code appears to be used just as often as
the last response code. The codes in between seem to be universally ignored.

IMO, that is not a valid conclusion.

With the exception of one package (QMAIL) which is clearly violating 821/2821 formal specifications, at least one of the codes (hMailServer) is very SMTP-buggy and is not worth any consideration. You were incorrect with Exim and it isn't clear if analysis s considering mixed non-continuation codes which is already conflictive with the specification. You also didn't analyze a good bit of other popular main stream packages in the market, including none of the major MUAs which we have tested.

It clearly indicates to me that at least the first and last reply codes
need to be the same. If they are NOT the same, >>>CODE BREAKS<<<. This
translates, to me, as indicating that we *NEED* to use "MUST" and not

IMO, his is precisely the reason why it should be SHOULD and not a MUST.

A MUST encourages broken code behavior by falsely encouraging poor logic and pre 2821bis non-compliant logic that it is OK to read the first code because there is NEW presumption that the codes will be persistent.

By using a MUST you are saying that FUTURE clients should use a persistent reply code when in fact it is very conceivable that it might encounter a failure.

The solution is quite simple - follow the 25 year old spec of looking for the first non-continuation line.

Maybe Postels conservative/liberal axiom should apply:

    Servers SHOULD send persistent reply codes, however, clients
    SHOULD be aware for mixed reply codes scenarios and SHOULD
    only react to the first non-continuation reply code.

This is consistent with Postel's rule, it is consistent with past, present and future considerations, backward compatible and it is not a functional change on the specs. On the other hand, a MUST will attempt to enforce change. The MUST should not imply that CLIENT should begin enforcing persistent reply codes or just rely on the first line. It encourage incorrect designs of not ignoring continuation lines.

The point again is that it has been POSSIBLE for 25 years and a MUST would be changing that now and also encourage designs that may not be honored.


<Prev in Thread] Current Thread [Next in Thread>