if Cyrus 2.1.13 sends reject or vacation messages generated by Sieve on Exim 3.36 Linux systems and being filed back from Exim into Cyrus, a blank line is added in the middle of the header lines causing the second part of the header being treated as the body of the mail.
An example of an extra blank line in the header is shown in [4].
I debugged the process of sending and delivering a reject message. The problem is caused in the end by using \r\r\n (!) as a line terminator in the LMTP transport from Exim to Cyrus.
Exim 4.20 has an option drop_cr [5] but not Exim 3.36.
To my knowlegde, a locally generated mail given to sendmail should use \n as the usual Unix line termination. The character pair \r\n is used in SMTP communication.
Cyrus uses \r\n when calling sendmail (locally, not using SMTP) to send a reject message.
Would it be advisable to
- patch Cyrus not to use \r\n as a line terminator
- patch Cyrus to use a wrapper for the sendmail binary stripping \r\n down to \n
- upgrade to Exim 4.20 and use the option drop_cr?
Cyrus source code to generate reject messages (imap/lmtpd.c) [1]:
smbuf[0] = "sendmail"; smbuf[1] = "-i"; /* ignore dots */ smbuf[2] = "-f"; smbuf[3] = "<>"; smbuf[4] = "--"; smbuf[5] = rejto; smbuf[6] = NULL; sm_pid = open_sendmail(smbuf, &sm); if (sm == NULL) { return -1; }
t = time(NULL); p = getpid(); snprintf(buf, sizeof(buf), "<[EMAIL PROTECTED]>", p, (int) t, global_outgoing_count++, config_servername);
namebuf = make_sieve_db(mailreceip); duplicate_mark(buf, strlen(buf), namebuf, strlen(namebuf), t); fprintf(sm, "Message-ID: %s\r\n", buf);
rfc822date_gen(datestr, sizeof(datestr), t); fprintf(sm, "Date: %s\r\n", datestr);
fprintf(sm, "X-Sieve: %s\r\n", SIEVE_VERSION); fprintf(sm, "From: Mail Sieve Subsystem <%s>\r\n", POSTMASTER); fprintf(sm, "To: <%s>\r\n", rejto); fprintf(sm, "MIME-Version: 1.0\r\n"); fprintf(sm, "Content-Type: " "multipart/report; report-type=disposition-notification;" "\r\n\tboundary=\"%d/%s\"\r\n", (int) p, config_servername); fprintf(sm, "Subject: Automatically rejected mail\r\n");
The mail header in Exim's queue is shown in [2].
Very interesting is the line termination. 14 lines end on LF (\n, 0x0a) and starting with "060I Message-ID" the lines terminate with CRLF (\r\n, 0x0d 0x0a).
"exim -Mvh 19dvc2-0000lu-00" [2]:
---- start ---- 19dvc2-0000lu-00-H cyrus 76 12 <> 1058636114 0 -ident cyrus -received_protocol local -body_linecount 46 XX 1 [EMAIL PROTECTED]
141P Received: from cyrus by ente.berdmann.de with local (Exim 3.36 #1) id 19dvc2-0000lu-00 for [EMAIL PROTECTED]; Sat, 19 Jul 2003 19:35:14 +0200 060I Message-ID: <[EMAIL PROTECTED]> 039 Date: Sat, 19 Jul 2003 19:35:14 +0200 024 X-Sieve: CMU Sieve 2.2 041* From: Mail Sieve Subsystem <postmaster> 053F From: Mail Sieve Subsystem <[EMAIL PROTECTED]> 022T To: <[EMAIL PROTECTED]> 019 MIME-Version: 1.0 106 Content-Type: multipart/report; report-type=disposition-notification; boundary="2906/ente.berdmann.de" 038 Subject: Automatically rejected mail 041 Auto-Submitted: auto-replied (rejected) ----- end -----
I configured Exim to deliver using LMTP over TCP/IP instead of using a socket. Then I attached tcpdump/ethereal to their communication.
The lines up to and including "Received: ... +0200" are terminated using \r\n. The following lines beginning with "Message-ID:" are terminated using \r\r\n (not being visible here, but shown by using "od -ch" oder emacs).
LMTP between Exim and Cyrus [3]:
220 ente.berdmann.de LMTP Cyrus v2.1.13 ready LHLO ente.berdmann.de 250-ente.berdmann.de 250-8BITMIME 250-ENHANCEDSTATUSCODES 250-PIPELINING 250-SIZE 250-AUTH EXTERNAL 250 IGNOREQUOTA MAIL FROM:<> SIZE=3054 RCPT TO:<[EMAIL PROTECTED]> DATA 250 2.1.0 ok 250 2.1.5 ok 354 go ahead Received: from cyrus by ente.berdmann.de with local (Exim 3.36 #1) id 19dwYQ-0000uw-00 for [EMAIL PROTECTED]; Sat, 19 Jul 2003 20:35:34 +0200 Message-ID: <[EMAIL PROTECTED]> Date: Sat, 19 Jul 2003 20:35:34 +0200 X-Sieve: CMU Sieve 2.2 From: Mail Sieve Subsystem <[EMAIL PROTECTED]> To: <[EMAIL PROTECTED]> MIME-Version: 1.0 Content-Type: multipart/report; report-type=disposition-notification; boundary="3529/ente.berdmann.de" Subject: Automatically rejected mail Auto-Submitted: auto-replied (rejected) [...]
The mail source accessed with IMAP [4] (each line in Cyrus's spool on disk is separated using \r\n):
reject mail source [4]:
Return-Path: <>
Received: from ente.berdmann.de (localhost [127.0.0.1])
by ente.berdmann.de (Cyrus v2.1.13) with LMTP; Sat, 19 Jul 2003 20:36:27 +0200
X-Sieve: CMU Sieve 2.2
Received: from cyrus by ente.berdmann.de with local (Exim 3.36 #1)
id 19dwYQ-0000uw-00
for [EMAIL PROTECTED]; Sat, 19 Jul 2003 20:35:34 +0200
Message-ID: <[EMAIL PROTECTED]>
Date: Sat, 19 Jul 2003 20:35:34 +0200 X-Sieve: CMU Sieve 2.2 From: Mail Sieve Subsystem <[EMAIL PROTECTED]> To: <[EMAIL PROTECTED]> MIME-Version: 1.0 Content-Type: multipart/report; report-type=disposition-notification; boundary="3529/ente.berdmann.de" Subject: Automatically rejected mail Auto-Submitted: auto-replied (rejected) [...]
Exim 4.20 documentation on drop_cr (http://www.exim.org/exim-html-4.20/doc/html/spec.html) [5]:
drop_cr Type: boolean Default: false
Setting drop_cr true affects non-SMTP messages that are submitted locally. It causes every carriage return character that immediately precedes a linefeed to be discarded. Other carriage returns are treated as data. This action can be requested for individual messages by means of the -dropcr command line option.