break;
}
- addr->transport_return = *ptr++;
- addr->special_action = *ptr++;
- memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
- ptr += sizeof(addr->basic_errno);
- memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
- ptr += sizeof(addr->more_errno);
- memcpy(&(addr->flags), ptr, sizeof(addr->flags));
- ptr += sizeof(addr->flags);
- addr->message = (*ptr)? string_copy(ptr) : NULL;
- while(*ptr++);
- addr->user_message = (*ptr)? string_copy(ptr) : NULL;
- while(*ptr++);
-
- /* Always two strings for host information, followed by the port number and DNSSEC mark */
-
- if (*ptr != 0)
+ switch (subid)
{
- h = store_get(sizeof(host_item));
- h->name = string_copy(ptr);
- while (*ptr++);
- h->address = string_copy(ptr);
- while(*ptr++);
- memcpy(&(h->port), ptr, sizeof(h->port));
- ptr += sizeof(h->port);
- h->dnssec = *ptr == '2' ? DS_YES
- : *ptr == '1' ? DS_NO
- : DS_UNK;
- ptr++;
- addr->host_used = h;
- }
- else ptr++;
+#ifdef EXPERIMENTAL_DSN_INFO
+ case '1': /* must arrive before A0, and applies to that addr */
+ /* Two strings: smtp_greeting and helo_response */
+ addr->smtp_greeting = string_copy(ptr);
+ while(*ptr++);
+ addr->helo_response = string_copy(ptr);
+ while(*ptr++);
+ break;
+#endif
- /* Finished with this address */
+ case '0':
+ addr->transport_return = *ptr++;
+ addr->special_action = *ptr++;
+ memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
+ ptr += sizeof(addr->basic_errno);
+ memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
+ ptr += sizeof(addr->more_errno);
+ memcpy(&(addr->flags), ptr, sizeof(addr->flags));
+ ptr += sizeof(addr->flags);
+ addr->message = (*ptr)? string_copy(ptr) : NULL;
+ while(*ptr++);
+ addr->user_message = (*ptr)? string_copy(ptr) : NULL;
+ while(*ptr++);
- addr = addr->next;
+ /* Always two strings for host information, followed by the port number and DNSSEC mark */
+
+ if (*ptr != 0)
+ {
+ h = store_get(sizeof(host_item));
+ h->name = string_copy(ptr);
+ while (*ptr++);
+ h->address = string_copy(ptr);
+ while(*ptr++);
+ memcpy(&(h->port), ptr, sizeof(h->port));
+ ptr += sizeof(h->port);
+ h->dnssec = *ptr == '2' ? DS_YES
+ : *ptr == '1' ? DS_NO
+ : DS_UNK;
+ ptr++;
+ addr->host_used = h;
+ }
+ else ptr++;
+
+ /* Finished with this address */
+
+ addr = addr->next;
+ break;
+ }
break;
/* Local interface address/port */
for (r = addr->retries; r != NULL; r = r->next)
{
- uschar *ptr;
sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
memcpy(ptr, &(r->basic_errno), sizeof(r->basic_errno));
rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer);
}
- /* The rest of the information goes in an 'A' item. */
+#ifdef EXPERIMENTAL_DSN_INFO
+/*um, are they really per-addr? Other per-conn stuff is not (auth, tls). But host_used is! */
+ if (addr->smtp_greeting)
+ {
+ ptr = big_buffer;
+ DEBUG(D_deliver) debug_printf("smtp_greeting '%s'\n", addr->smtp_greeting);
+ sprintf(CS ptr, "%.128s", addr->smtp_greeting);
+ while(*ptr++);
+ if (addr->helo_response)
+ {
+ DEBUG(D_deliver) debug_printf("helo_response '%s'\n", addr->helo_response);
+ sprintf(CS ptr, "%.128s", addr->helo_response);
+ while(*ptr++);
+ }
+ else
+ *ptr++ = '\0';
+ rmt_dlv_checked_write(fd, 'A', '1', big_buffer, ptr - big_buffer);
+ }
+#endif
+
+ /* The rest of the information goes in an 'A0' item. */
- ptr = big_buffer + 2;
sprintf(CS big_buffer, "%c%c", addr->transport_return,
addr->special_action);
+ ptr = big_buffer + 2;
memcpy(ptr, &(addr->basic_errno), sizeof(addr->basic_errno));
ptr += sizeof(addr->basic_errno);
memcpy(ptr, &(addr->more_errno), sizeof(addr->more_errno));
}
/* Local interface address/port */
+#ifdef EXPERIMENTAL_DSN_INFO
+ if (sending_ip_address)
+#else
if (LOGGING(incoming_interface) && sending_ip_address)
+#endif
{
uschar * ptr = big_buffer;
sprintf(CS ptr, "%.128s", sending_ip_address);
for (addr = handled_addr; addr; addr = addr->next)
{
+ host_item * hu;
fprintf(f, "Action: failed\n"
"Final-Recipient: rfc822;%s\n"
"Status: 5.0.0\n",
addr->address);
- if (addr->host_used && addr->host_used->name)
- {
- fprintf(f, "Remote-MTA: dns; %s\n",
- addr->host_used->name);
- print_dsn_diagnostic_code(addr, f);
- }
+ if ((hu = addr->host_used) && hu->name)
+ {
+ const uschar * s;
+ fprintf(f, "Remote-MTA: dns; %s\n",
+ hu->name);
+#ifdef EXPERIMENTAL_DSN_INFO
+ if (hu->address)
+ {
+ uschar * p = hu->port == 25
+ ? US"" : string_sprintf(":%d", hu->port);
+ fprintf(f, "Remote-MTA: X-ip; [%s]%s\n", hu->address, p);
+ }
+ if ((s = addr->smtp_greeting) && *s)
+ fprintf(f, "X-Remote-MTA-smtp-greeting: X-str; %s\n", s);
+ if ((s = addr->helo_response) && *s)
+ fprintf(f, "X-Remote-MTA-helo-response: X-str; %s\n", s);
+ if ((s = addr->message) && *s)
+ fprintf(f, "X-Exim-Diagnostic: X-str; %s\n", s);
+#endif
+ print_dsn_diagnostic_code(addr, f);
+ }
fputc('\n', f);
}
rc to put in each address's transport_return field
pass_message if TRUE, set the "pass message" flag in the address
host if set, mark addrs as having used this host
+ smtp_greeting from peer
+ helo_response from peer
If errno_value has the special value ERRNO_CONNECTTIMEOUT, ETIMEDOUT is put in
the errno field, and RTEF_CTOUT is ORed into the more_errno field, to indicate
static void
set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
- BOOL pass_message, host_item * host)
+ BOOL pass_message, host_item * host
+#ifdef EXPERIMENTAL_DSN_INFO
+ , const uschar * smtp_greeting, const uschar * helo_response
+#endif
+ )
{
address_item *addr;
int orvalue = 0;
errno_value = ETIMEDOUT;
orvalue = RTEF_CTOUT;
}
-for (addr = addrlist; addr != NULL; addr = addr->next)
+for (addr = addrlist; addr; addr = addr->next)
if (addr->transport_return >= PENDING)
{
addr->basic_errno = errno_value;
}
addr->transport_return = rc;
if (host)
+ {
addr->host_used = host;
+#ifdef EXPERIMENTAL_DSN_INFO
+ if (smtp_greeting)
+ {uschar * s = Ustrchr(smtp_greeting, '\n'); if (s) *s = '\0';}
+ addr->smtp_greeting = smtp_greeting;
+
+ if (helo_response)
+ {uschar * s = Ustrchr(helo_response, '\n'); if (s) *s = '\0';}
+ addr->helo_response = helo_response;
+#endif
+ }
}
}
+static void
+set_errno_nohost(address_item *addrlist, int errno_value, uschar *msg, int rc,
+ BOOL pass_message)
+{
+set_errno(addrlist, errno_value, msg, rc, pass_message, NULL
+#ifdef EXPERIMENTAL_DSN_INFO
+ , NULL, NULL
+#endif
+ );
+}
/*************************************************
{
uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
transport_rcpt_address(addr, include_affixes));
- set_errno(addrlist, ETIMEDOUT, message, DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, ETIMEDOUT, message, DEFER, FALSE);
retry_add_item(addr, addr->address_retry_key, 0);
update_waiting = FALSE;
return -1;
/* Internal problem, message in buffer. */
case ERROR:
- set_errno(addrlist, ERRNO_AUTHPROB, string_copy(buffer),
- DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, ERRNO_AUTHPROB, string_copy(buffer),
+ DEFER, FALSE);
return ERROR;
}
if (require_auth == OK && !smtp_authenticated)
{
- set_errno(addrlist, ERRNO_AUTHFAIL,
+ set_errno_nohost(addrlist, ERRNO_AUTHFAIL,
string_sprintf("authentication required but %s", fail_reason), DEFER,
- FALSE, NULL);
+ FALSE);
return DEFER;
}
{
uschar *message = string_sprintf("failed to expand "
"authenticated_sender: %s", expand_string_message);
- set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE);
return TRUE;
}
}
int max_rcpt = tblock->max_addresses;
uschar *igquotstr = US"";
+#ifdef EXPERIMENTAL_DSN_INFO
+uschar *smtp_greeting = NULL;
+uschar *helo_response = NULL;
+#endif
uschar *helo_data = NULL;
uschar *message = NULL;
#ifndef SUPPORT_TLS
if (smtps)
{
- set_errno(addrlist, ERRNO_TLSFAILURE, US"TLS support not available",
- DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, ERRNO_TLSFAILURE, US"TLS support not available",
+ DEFER, FALSE);
return ERROR;
}
#endif
if (inblock.sock < 0)
{
- set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
- NULL, DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
+ NULL, DEFER, FALSE);
return DEFER;
}
&& dane_required /* do not error on only dane-requested */
)
{
- set_errno(addrlist, ERRNO_DNSDEFER,
+ set_errno_nohost(addrlist, ERRNO_DNSDEFER,
string_sprintf("DANE error: tlsa lookup %s",
rc == DEFER ? "DEFER" : "FAIL"),
- rc, FALSE, NULL);
+ rc, FALSE);
return rc;
}
}
else if (dane_required)
{
- set_errno(addrlist, ERRNO_DNSDEFER,
+ set_errno_nohost(addrlist, ERRNO_DNSDEFER,
string_sprintf("DANE error: %s lookup not DNSSEC", host->name),
- FAIL, FALSE, NULL);
+ FAIL, FALSE);
return FAIL;
}
if ((helo_data = string_domain_utf8_to_alabel(helo_data, &errstr)), errstr)
{
errstr = string_sprintf("failed to expand helo_data: %s", errstr);
- set_errno(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE);
yield = DEFER;
goto SEND_QUIT;
}
if (!smtps)
{
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
- ob->command_timeout)) goto RESPONSE_FAILED;
+ BOOL good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
+ '2', ob->command_timeout);
+#ifdef EXPERIMENTAL_DSN_INFO
+ smtp_greeting = string_copy(buffer);
+#endif
+ if (!good_response) goto RESPONSE_FAILED;
#ifdef EXPERIMENTAL_EVENT
{
s = event_raise(tblock->event_action, US"smtp:connect", buffer);
if (s)
{
- set_errno(addrlist, ERRNO_EXPANDFAIL,
+ set_errno_nohost(addrlist, ERRNO_EXPANDFAIL,
string_sprintf("deferred by smtp:connect event expansion: %s", s),
- DEFER, FALSE, NULL);
+ DEFER, FALSE);
yield = DEFER;
goto SEND_QUIT;
}
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
- set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE);
yield = DEFER;
goto SEND_QUIT;
}
if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
ob->command_timeout))
{
- if (errno != 0 || buffer[0] == 0 || lmtp) goto RESPONSE_FAILED;
+ if (errno != 0 || buffer[0] == 0 || lmtp)
+ {
+#ifdef EXPERIMENTAL_DSN_INFO
+ helo_response = string_copy(buffer);
+#endif
+ goto RESPONSE_FAILED;
+ }
esmtp = FALSE;
}
+#ifdef EXPERIMENTAL_DSN_INFO
+ helo_response = string_copy(buffer);
+#endif
}
else
{
if (!esmtp)
{
+ BOOL good_response;
+
if (smtp_write_command(&outblock, FALSE, "HELO %s\r\n", helo_data) < 0)
goto SEND_FAILED;
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
- ob->command_timeout)) goto RESPONSE_FAILED;
+ good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
+ '2', ob->command_timeout);
+#ifdef EXPERIMENTAL_DSN_INFO
+ helo_response = string_copy(buffer);
+#endif
+ if (!good_response) goto RESPONSE_FAILED;
}
/* Set IGNOREQUOTA if the response to LHLO specifies support and the
set from the command line if they were set in the process that passed the
connection on. */
+/*XXX continue case needs to propagate DSN_INFO, prob. in deliver.c
+as the contine goes via transport_pass_socket() and doublefork and exec.
+It does not wait. Unclear how we keep separate host's responses
+separate - we could match up by host ip+port as a bodge. */
+
else
{
inblock.sock = outblock.sock = fileno(stdin);
/* TLS session is set up */
- for (addr = addrlist; addr != NULL; addr = addr->next)
+ for (addr = addrlist; addr; addr = addr->next)
if (addr->transport_return == PENDING_DEFER)
{
addr->cipher = tls_out.cipher;
if (tls_out.active >= 0)
{
char *greeting_cmd;
+ BOOL good_response;
+
if (helo_data == NULL)
{
helo_data = expand_string(ob->helo_data);
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
- set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE);
yield = DEFER;
goto SEND_QUIT;
}
/* For SMTPS we need to wait for the initial OK response. */
if (smtps)
{
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
- ob->command_timeout)) goto RESPONSE_FAILED;
+ good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
+ '2', ob->command_timeout);
+#ifdef EXPERIMENTAL_DSN_INFO
+ smtp_greeting = string_copy(buffer);
+#endif
+ if (!good_response) goto RESPONSE_FAILED;
}
if (esmtp)
if (smtp_write_command(&outblock, FALSE, "%s %s\r\n",
lmtp? "LHLO" : greeting_cmd, helo_data) < 0)
goto SEND_FAILED;
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
- ob->command_timeout))
- goto RESPONSE_FAILED;
+ good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
+ '2', ob->command_timeout);
+#ifdef EXPERIMENTAL_DSN_INFO
+ helo_response = string_copy(buffer);
+#endif
+ if (!good_response) goto RESPONSE_FAILED;
}
/* If the host is required to use a secure channel, ensure that we
if (!rc)
{
- set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
- FALSE, NULL);
+ set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
+ FALSE);
yield = ERROR;
goto SEND_QUIT;
}
{
if (s = string_address_utf8_to_alabel(return_path, &errstr), errstr)
{
- set_errno(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE, NULL);
+ set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE);
yield = ERROR;
goto SEND_QUIT;
}
if (badaddr->transport_return != PENDING_OK)
{
/*XXX could we find a better errno than 0 here? */
- set_errno(addrlist, 0, badaddr->message, FAIL,
- testflag(badaddr, af_pass_message), NULL);
+ set_errno_nohost(addrlist, 0, badaddr->message, FAIL,
+ testflag(badaddr, af_pass_message));
ok = FALSE;
break;
}
else
sprintf(CS buffer, "%.500s\n", addr->unique);
- DEBUG(D_deliver) debug_printf("journalling %s", buffer);
+ DEBUG(D_deliver) debug_printf("journalling %s\n", buffer);
len = Ustrlen(CS buffer);
if (write(journal_fd, buffer, len) != len)
log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
else
sprintf(CS buffer, "%.500s\n", addr->unique);
- DEBUG(D_deliver) debug_printf("journalling(PRDR) %s", buffer);
+ DEBUG(D_deliver) debug_printf("journalling(PRDR) %s\n", buffer);
len = Ustrlen(CS buffer);
if (write(journal_fd, buffer, len) != len)
log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
if (!ok)
{
- int code;
+ int code, set_rc;
+ uschar * set_message;
RESPONSE_FAILED:
- save_errno = errno;
- message = NULL;
- send_quit = check_response(host, &save_errno, addrlist->more_errno,
- buffer, &code, &message, &pass_message);
- goto FAILED;
+ {
+ save_errno = errno;
+ message = NULL;
+ send_quit = check_response(host, &save_errno, addrlist->more_errno,
+ buffer, &code, &message, &pass_message);
+ goto FAILED;
+ }
SEND_FAILED:
- save_errno = errno;
- code = '4';
- message = US string_sprintf("send() to %s [%s] failed: %s",
- host->name, host->address, strerror(save_errno));
- send_quit = FALSE;
- goto FAILED;
+ {
+ save_errno = errno;
+ code = '4';
+ message = US string_sprintf("send() to %s [%s] failed: %s",
+ host->name, host->address, strerror(save_errno));
+ send_quit = FALSE;
+ goto FAILED;
+ }
/* This label is jumped to directly when a TLS negotiation has failed,
or was not done for a host for which it is required. Values will be set
FAILED:
ok = FALSE; /* For when reached by GOTO */
+ set_message = message;
if (setting_up)
{
if (code == '5')
- set_errno(addrlist, save_errno, message, FAIL, pass_message, host);
+ set_rc = FAIL;
else
- {
- set_errno(addrlist, save_errno, message, DEFER, pass_message, host);
- yield = DEFER;
- }
+ yield = set_rc = DEFER;
}
/* We want to handle timeouts after MAIL or "." and loss of connection after
if (message_error)
{
if (mua_wrapper) code = '5'; /* Force hard failure in wrapper mode */
- set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER,
- pass_message, host);
/* If there's an errno, the message contains just the identity of
the host. */
- if (code != '5') /* Anything other than 5 is treated as temporary */
+ if (code == '5')
+ set_rc = FAIL;
+ else /* Anything other than 5 is treated as temporary */
{
+ set_rc = DEFER;
if (save_errno > 0)
message = US string_sprintf("%s: %s", message, strerror(save_errno));
if (host->next != NULL) log_write(0, LOG_MAIN, "%s", message);
else
{
+ set_rc = DEFER;
yield = (save_errno == ERRNO_CHHEADER_FAIL ||
save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER;
- set_errno(addrlist, save_errno, message, DEFER, pass_message, host);
}
}
+
+ set_errno(addrlist, save_errno, set_message, set_rc, pass_message, host
+#ifdef EXPERIMENTAL_DSN_INFO
+ , smtp_greeting, helo_response
+#endif
+ );
}
/* If the socket is successfully passed, we musn't send QUIT (or
indeed anything!) from here. */
+/*XXX DSN_INFO: assume likely to do new HELO; but for greet we'll want to
+propagate it from the initial
+*/
if (ok && transport_pass_socket(tblock->name, host->name, host->address,
new_message_id, inblock.sock))
{
/* If RSET failed and there are addresses left, they get deferred. */
- else set_errno(first_addr, errno, msg, DEFER, FALSE, host);
+ else set_errno(first_addr, errno, msg, DEFER, FALSE, host
+#ifdef EXPERIMENTAL_DSN_INFO
+ , smtp_greeting, helo_response
+#endif
+ );
}
}
addr->peercert = NULL;
addr->peerdn = NULL;
addr->ocsp = OCSP_NOT_REQ;
+#endif
+#ifdef EXPERIMENTAL_DSN_INFO
+ addr->smtp_greeting = NULL;
+ addr->helo_response = NULL;
#endif
}
return first_addr;
if (dont_deliver)
{
host_item *host2;
- set_errno(addrlist, 0, NULL, OK, FALSE, NULL);
+ set_errno_nohost(addrlist, 0, NULL, OK, FALSE);
for (addr = addrlist; addr != NULL; addr = addr->next)
{
addr->host_used = host;
--- /dev/null
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from EXIMUSER by the.local.host.name with local (Exim x.yz)
+ id 10HmaY-0005vi-00
+ for CALLER@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+X-Failed-Recipients: userx@domain1
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@test.ex>
+To: CALLER@test.ex
+Content-Type: multipart/report; report-type=delivery-status; boundary=NNNNNNNNNN-eximdsn-MMMMMMMMMM
+MIME-Version: 1.0
+Subject: Mail delivery failed: returning message to sender
+Message-Id: <E10HmaY-0005vi-00@the.local.host.name>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: text/plain; charset=us-ascii
+
+This message was created automatically by mail delivery software.
+
+A message that you sent could not be delivered to one or more of its
+recipients. This is a permanent error. The following address(es) failed:
+
+ userx@domain1
+ host localhost4.test.ex [127.0.0.1]
+ SMTP error from remote mail server after initial connection:
+ 550 Go away
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/delivery-status
+
+Reporting-MTA: dns; the.local.host.name
+
+Action: failed
+Final-Recipient: rfc822;userx@domain1
+Status: 5.0.0
+Remote-MTA: dns; localhost4.test.ex
+Remote-MTA: X-ip; [127.0.0.1]:1111
+X-Remote-MTA-smtp-greeting: X-str; 550 Go away
+X-Exim-Diagnostic: X-str; SMTP error from remote mail server after initial connection: 550 Go away
+Diagnostic-Code: smtp; 550 Go away
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/rfc822
+
+Return-path: <CALLER@test.ex>
+Received: from CALLER by the.local.host.name with local (Exim x.yz)
+ (envelope-from <CALLER@test.ex>)
+ id 10HmaX-0005vi-00
+ for userx@domain1; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@the.local.host.name>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+Test message 1
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM--
+
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from EXIMUSER by the.local.host.name with local (Exim x.yz)
+ id 10HmbA-0005vi-00
+ for CALLER@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+X-Failed-Recipients: usery@domain2,
+ userx@domain1
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@test.ex>
+To: CALLER@test.ex
+Content-Type: multipart/report; report-type=delivery-status; boundary=NNNNNNNNNN-eximdsn-MMMMMMMMMM
+MIME-Version: 1.0
+Subject: Mail delivery failed: returning message to sender
+Message-Id: <E10HmbA-0005vi-00@the.local.host.name>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: text/plain; charset=us-ascii
+
+This message was created automatically by mail delivery software.
+
+A message that you sent could not be delivered to one or more of its
+recipients. This is a permanent error. The following address(es) failed:
+
+ usery@domain2
+ host localhost4.test.ex [127.0.0.1]
+ SMTP error from remote mail server after HELO the.local.host.name:
+ 550 Go away
+ userx@domain1
+ host localhost4.test.ex [127.0.0.1]
+ SMTP error from remote mail server after HELO the.local.host.name:
+ 550 Go away
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/delivery-status
+
+Reporting-MTA: dns; the.local.host.name
+
+Action: failed
+Final-Recipient: rfc822;userx@domain1
+Status: 5.0.0
+Remote-MTA: dns; localhost4.test.ex
+Remote-MTA: X-ip; [127.0.0.1]:1111
+X-Remote-MTA-smtp-greeting: X-str; 220 Connected OK
+X-Remote-MTA-helo-response: X-str; 550 Go away
+X-Exim-Diagnostic: X-str; SMTP error from remote mail server after HELO the.local.host.name: 550 Go away
+Diagnostic-Code: smtp; 550 Go away
+
+Action: failed
+Final-Recipient: rfc822;usery@domain2
+Status: 5.0.0
+Remote-MTA: dns; localhost4.test.ex
+Remote-MTA: X-ip; [127.0.0.1]:1111
+X-Remote-MTA-smtp-greeting: X-str; 220 Connected OK
+X-Remote-MTA-helo-response: X-str; 550 Go away
+X-Exim-Diagnostic: X-str; SMTP error from remote mail server after HELO the.local.host.name: 550 Go away
+Diagnostic-Code: smtp; 550 Go away
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/rfc822
+
+Return-path: <CALLER@test.ex>
+Received: from CALLER by the.local.host.name with local (Exim x.yz)
+ (envelope-from <CALLER@test.ex>)
+ id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@the.local.host.name>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+Test message 2
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM--
+