From: Jeremy Harris Date: Sun, 16 Mar 2014 17:22:56 +0000 (+0000) Subject: Support transport-added headers under cutthrough delivery. Bug 1431 X-Git-Tag: exim-4_83_RC1~67 X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=511a6c1;p=exim.git Support transport-added headers under cutthrough delivery. Bug 1431 --- diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index ae4d75ecb..2b055c3e9 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -27330,8 +27330,12 @@ from one SMTP connection to another. If a recipient-verify callout connection i requested in the same ACL it is held open and used for the data, otherwise one is made after the ACL completes. -Note that routers are used in verify mode. Note also that headers cannot be +Note that routers are used in verify mode, +and cannot depend on content of received headers. +Note also that headers cannot be modified by any of the post-data ACLs (DATA, MIME and DKIM). +Headers may be modified by routers (subject to the above) and transports. + Cutthrough delivery is not supported via transport-filters or when DKIM signing of outgoing messages is done, because it sends data to the ultimate destination before the entire message has been received from the source. diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index c29f21cbf..8a55ceea9 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -56,7 +56,11 @@ JH/06 Log outbound-TLS and port details, subject to log selectors, for a JH/07 Add malware type "sock" for talking to simple daemon. -JH/08 Bugzilla 1371: Add tls_{,try_}verify_hosts to smtp transport. OpenSSL only. +JH/08 Bugzilla 1371: Add tls_{,try_}verify_hosts to smtp transport. + OpenSSL only. + +JH/09 Bugzilla 1431: Support (with limitations) headers_add/headers_remove in + routers/transports under cutthrough routing. Exim version 4.82 diff --git a/src/src/functions.h b/src/src/functions.h index e92c2455f..395961530 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -384,6 +384,8 @@ extern BOOL transport_set_up_command(uschar ***, uschar *, BOOL, int, extern void transport_update_waiting(host_item *, uschar *); extern BOOL transport_write_block(int, uschar *, int); extern BOOL transport_write_string(int, const char *, ...); +extern BOOL transport_headers_send(address_item *, int, uschar *, uschar *, + BOOL (*)(int, uschar *, int, BOOL), BOOL, rewrite_rule *, int); extern BOOL transport_write_message(address_item *, int, int, int, uschar *, uschar *, uschar *, uschar *, rewrite_rule *, int); extern void tree_add_duplicate(uschar *, address_item *); diff --git a/src/src/transport.c b/src/src/transport.c index ec4d0da92..549da4694 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -600,6 +600,175 @@ return write_chunk(fd, pp->address, Ustrlen(pp->address), use_crlf); +/* Add/remove/rewwrite headers, and send them plus the empty-line sparator. + +Globals: + header_list + +Arguments: + addr (chain of) addresses (for extra headers), or NULL; + only the first address is used + fd file descriptor to write the message to + sendfn function for output + use_crlf turn NL into CR LF + rewrite_rules chain of header rewriting rules + rewrite_existflags flags for the rewriting rules + +Returns: TRUE on success; FALSE on failure. +*/ +BOOL +transport_headers_send(address_item *addr, int fd, uschar *add_headers, uschar *remove_headers, + BOOL (*sendfn)(int fd, uschar * s, int len, BOOL use_crlf), + BOOL use_crlf, rewrite_rule *rewrite_rules, int rewrite_existflags) +{ +header_line *h; + +/* Then the message's headers. Don't write any that are flagged as "old"; +that means they were rewritten, or are a record of envelope rewriting, or +were removed (e.g. Bcc). If remove_headers is not null, skip any headers that +match any entries therein. Then check addr->p.remove_headers too, provided that +addr is not NULL. */ + +if (remove_headers) + { + uschar *s = expand_string(remove_headers); + if (!s && !expand_string_forcedfail) + { + errno = ERRNO_CHHEADER_FAIL; + return FALSE; + } + remove_headers = s; + } + +for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old) + { + int i; + uschar *list = remove_headers; + + BOOL include_header = TRUE; + + for (i = 0; i < 2; i++) /* For remove_headers && addr->p.remove_headers */ + { + if (list) + { + int sep = ':'; /* This is specified as a colon-separated list */ + uschar *s, *ss; + uschar buffer[128]; + while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) + { + int len = Ustrlen(s); + if (strncmpic(h->text, s, len) != 0) continue; + ss = h->text + len; + while (*ss == ' ' || *ss == '\t') ss++; + if (*ss == ':') break; + } + if (s != NULL) { include_header = FALSE; break; } + } + if (addr != NULL) list = addr->p.remove_headers; + } + + /* If this header is to be output, try to rewrite it if there are rewriting + rules. */ + + if (include_header) + { + if (rewrite_rules) + { + void *reset_point = store_get(0); + header_line *hh; + + if ((hh = rewrite_header(h, NULL, NULL, rewrite_rules, rewrite_existflags, FALSE))) + { + if (!sendfn(fd, hh->text, hh->slen, use_crlf)) return FALSE; + store_reset(reset_point); + continue; /* With the next header line */ + } + } + + /* Either no rewriting rules, or it didn't get rewritten */ + + if (!sendfn(fd, h->text, h->slen, use_crlf)) return FALSE; + } + + /* Header removed */ + + else + { + DEBUG(D_transport) debug_printf("removed header line:\n%s---\n", h->text); + } + } + +/* Add on any address-specific headers. If there are multiple addresses, +they will all have the same headers in order to be batched. The headers +are chained in reverse order of adding (so several addresses from the +same alias might share some of them) but we want to output them in the +opposite order. This is a bit tedious, but there shouldn't be very many +of them. We just walk the list twice, reversing the pointers each time, +but on the second time, write out the items. + +Headers added to an address by a router are guaranteed to end with a newline. +*/ + +if (addr) + { + int i; + header_line *hprev = addr->p.extra_headers; + header_line *hnext; + for (i = 0; i < 2; i++) + { + for (h = hprev, hprev = NULL; h != NULL; h = hnext) + { + hnext = h->next; + h->next = hprev; + hprev = h; + if (i == 1) + { + if (!sendfn(fd, h->text, h->slen, use_crlf)) return FALSE; + DEBUG(D_transport) + debug_printf("added header line(s):\n%s---\n", h->text); + } + } + } + } + +/* If a string containing additional headers exists, expand it and write +out the result. This is done last so that if it (deliberately or accidentally) +isn't in header format, it won't mess up any other headers. An empty string +or a forced expansion failure are noops. An added header string from a +transport may not end with a newline; add one if it does not. */ + +if (add_headers) + { + uschar *s = expand_string(add_headers); + if (s == NULL) + { + if (!expand_string_forcedfail) + { errno = ERRNO_CHHEADER_FAIL; return FALSE; } + } + else + { + int len = Ustrlen(s); + if (len > 0) + { + if (!sendfn(fd, s, len, use_crlf)) return FALSE; + if (s[len-1] != '\n' && !sendfn(fd, US"\n", 1, use_crlf)) + return FALSE; + DEBUG(D_transport) + { + debug_printf("added header line(s):\n%s", s); + if (s[len-1] != '\n') debug_printf("\n"); + debug_printf("---\n"); + } + } + } + } + +/* Separate headers from body with a blank line */ + +return sendfn(fd, US"\n", 1, use_crlf); +} + + /************************************************* * Write the message * *************************************************/ @@ -747,154 +916,9 @@ if ((options & topt_no_headers) == 0) were removed (e.g. Bcc). If remove_headers is not null, skip any headers that match any entries therein. Then check addr->p.remove_headers too, provided that addr is not NULL. */ - - if (remove_headers != NULL) - { - uschar *s = expand_string(remove_headers); - if (s == NULL && !expand_string_forcedfail) - { - errno = ERRNO_CHHEADER_FAIL; - return FALSE; - } - remove_headers = s; - } - - for (h = header_list; h != NULL; h = h->next) - { - int i; - uschar *list = NULL; - BOOL include_header; - - if (h->type == htype_old) continue; - - include_header = TRUE; - list = remove_headers; - - for (i = 0; i < 2; i++) /* For remove_headers && addr->p.remove_headers */ - { - if (list != NULL) - { - int sep = ':'; /* This is specified as a colon-separated list */ - uschar *s, *ss; - uschar buffer[128]; - while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) - != NULL) - { - int len = Ustrlen(s); - if (strncmpic(h->text, s, len) != 0) continue; - ss = h->text + len; - while (*ss == ' ' || *ss == '\t') ss++; - if (*ss == ':') break; - } - if (s != NULL) { include_header = FALSE; break; } - } - if (addr != NULL) list = addr->p.remove_headers; - } - - /* If this header is to be output, try to rewrite it if there are rewriting - rules. */ - - if (include_header) - { - if (rewrite_rules != NULL) - { - void *reset_point = store_get(0); - header_line *hh = - rewrite_header(h, NULL, NULL, rewrite_rules, rewrite_existflags, - FALSE); - if (hh != NULL) - { - if (!write_chunk(fd, hh->text, hh->slen, use_crlf)) return FALSE; - store_reset(reset_point); - continue; /* With the next header line */ - } - } - - /* Either no rewriting rules, or it didn't get rewritten */ - - if (!write_chunk(fd, h->text, h->slen, use_crlf)) return FALSE; - } - - /* Header removed */ - - else - { - DEBUG(D_transport) debug_printf("removed header line:\n%s---\n", - h->text); - } - } - - /* Add on any address-specific headers. If there are multiple addresses, - they will all have the same headers in order to be batched. The headers - are chained in reverse order of adding (so several addresses from the - same alias might share some of them) but we want to output them in the - opposite order. This is a bit tedious, but there shouldn't be very many - of them. We just walk the list twice, reversing the pointers each time, - but on the second time, write out the items. - - Headers added to an address by a router are guaranteed to end with a newline. - */ - - if (addr != NULL) - { - int i; - header_line *hprev = addr->p.extra_headers; - header_line *hnext; - for (i = 0; i < 2; i++) - { - for (h = hprev, hprev = NULL; h != NULL; h = hnext) - { - hnext = h->next; - h->next = hprev; - hprev = h; - if (i == 1) - { - if (!write_chunk(fd, h->text, h->slen, use_crlf)) return FALSE; - DEBUG(D_transport) - debug_printf("added header line(s):\n%s---\n", h->text); - } - } - } - } - - /* If a string containing additional headers exists, expand it and write - out the result. This is done last so that if it (deliberately or accidentally) - isn't in header format, it won't mess up any other headers. An empty string - or a forced expansion failure are noops. An added header string from a - transport may not end with a newline; add one if it does not. */ - - if (add_headers != NULL) - { - uschar *s = expand_string(add_headers); - if (s == NULL) - { - if (!expand_string_forcedfail) - { - errno = ERRNO_CHHEADER_FAIL; - return FALSE; - } - } - else - { - int len = Ustrlen(s); - if (len > 0) - { - if (!write_chunk(fd, s, len, use_crlf)) return FALSE; - if (s[len-1] != '\n' && !write_chunk(fd, US"\n", 1, use_crlf)) - return FALSE; - DEBUG(D_transport) - { - debug_printf("added header line(s):\n%s", s); - if (s[len-1] != '\n') debug_printf("\n"); - debug_printf("---\n"); - } - } - } - } - - /* Separate headers from body with a blank line */ - - if (!write_chunk(fd, US"\n", 1, use_crlf)) return FALSE; + if (!transport_headers_send(addr, fd, add_headers, remove_headers, &write_chunk, + use_crlf, rewrite_rules, rewrite_existflags)) + return FALSE; } /* If the body is required, ensure that the data for check strings (formerly @@ -2157,4 +2181,6 @@ if (expand_arguments) return TRUE; } +/* vi: aw ai sw=2 +*/ /* End of transport.c */ diff --git a/src/src/verify.c b/src/src/verify.c index cd91b0560..39f546ed6 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -976,6 +976,7 @@ else { cutthrough_fd= outblock.sock; /* We assume no buffer in use in the outblock */ cutthrough_addr = *addr; /* Save the address_item for later logging */ + cutthrough_addr.next = NULL; cutthrough_addr.host_used = store_get(sizeof(host_item)); cutthrough_addr.host_used->name = host->name; cutthrough_addr.host_used->address = host->address; @@ -1244,27 +1245,43 @@ return cutthrough_response('3', NULL) == '3'; } +/* fd and use_crlf args only to match write_chunk() */ +static BOOL +cutthrough_write_chunk(int fd, uschar * s, int len, BOOL use_crlf) +{ +uschar * s2; +while(s && (s2 = Ustrchr(s, '\n'))) + { + if(!cutthrough_puts(s, s2-s) || !cutthrough_put_nl()) + return FALSE; + s = s2+1; + } +return TRUE; +} + + /* Buffered send of headers. Return success boolean. */ /* Expands newlines to wire format (CR,NL). */ /* Also sends header-terminating blank line. */ BOOL cutthrough_headers_send( void ) { -header_line * h; -uschar * cp1, * cp2; - if(cutthrough_fd < 0) return FALSE; -for(h= header_list; h != NULL; h= h->next) - if(h->type != htype_old && h->text != NULL) - for (cp1 = h->text; *cp1 && (cp2 = Ustrchr(cp1, '\n')); cp1 = cp2+1) - if( !cutthrough_puts(cp1, cp2-cp1) - || !cutthrough_put_nl()) - return FALSE; +/* We share a routine with the mainline transport to handle header add/remove/rewrites, + but having a separate buffered-output function (for now) +*/ +HDEBUG(D_acl) debug_printf("----------- start cutthrough headers send -----------\n"); -HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP>>(nl)\n"); -return cutthrough_put_nl(); +if (!transport_headers_send(&cutthrough_addr, cutthrough_fd, + cutthrough_addr.transport->add_headers, cutthrough_addr.transport->remove_headers, + &cutthrough_write_chunk, TRUE, + cutthrough_addr.transport->rewrite_rules, cutthrough_addr.transport->rewrite_existflags)) + return FALSE; + +HDEBUG(D_acl) debug_printf("----------- done cutthrough headers send ------------\n"); +return TRUE; } @@ -3710,4 +3727,6 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL return FAIL; } +/* vi: aw ai sw=2 +*/ /* End of verify.c */ diff --git a/test/confs/5400 b/test/confs/5400 index 8f2e8b585..62466983c 100644 --- a/test/confs/5400 +++ b/test/confs/5400 @@ -34,6 +34,8 @@ all: route_list = * 127.0.0.1 self = send transport = smtp + headers_remove = X-hdr-rtr + headers_add = X-hdr-rtr-new: $h_X-hdr-rtr:+++ no_more @@ -45,6 +47,7 @@ smtp: driver = smtp interface = HOSTIPV4 port = PORT_S + headers_add = ${if def:h_X-hdr-rtr {X-hdr-tpt-new: new} {}} # End diff --git a/test/log/5400 b/test/log/5400 index 59f948c5f..6b51348c3 100644 --- a/test/log/5400 +++ b/test/log/5400 @@ -12,3 +12,7 @@ 1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" 1999-03-02 09:44:33 10HmaZ-0005vi-00 -> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed +1999-03-02 09:44:33 rcpt for userx@domain.com +1999-03-02 09:44:33 10HmbA-0005vi-00 >> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss +1999-03-02 09:44:33 10HmbA-0005vi-00 Completed diff --git a/test/scripts/5400-cutthrough/5400 b/test/scripts/5400-cutthrough/5400 index 56d6fec77..3e56b43b8 100644 --- a/test/scripts/5400-cutthrough/5400 +++ b/test/scripts/5400-cutthrough/5400 @@ -26,8 +26,6 @@ DATA QUIT **** # cutthrough_delivery into HELO-only server -need_ipv4 -# server PORT_S 220 SMTP only spoken here EHLO @@ -92,3 +90,36 @@ DATA QUIT **** sleep 1 +# +# +# +# +# +# cutthrough_delivery basic operation, again +server PORT_S +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 Recipient OK +DATA +354 Send data +. +250 OK +QUIT +250 OK +**** +exim -d-all+acl+transport -bs +EHLO myhost.test.ex +MAIL FROM: +RCPT TO: +DATA +X-hdr-rtr: qqq +X-hdr-tpt: zzz + +body +. +QUIT +**** diff --git a/test/scripts/5410-cutthrough-OpenSSL/5410 b/test/scripts/5410-cutthrough-OpenSSL/5410 index 9f5ff7196..5c9598c66 100644 --- a/test/scripts/5410-cutthrough-OpenSSL/5410 +++ b/test/scripts/5410-cutthrough-OpenSSL/5410 @@ -1,4 +1,4 @@ -# cutthrough_delivery to target oferring TLS +# cutthrough_delivery to target offerring TLS exim -DSERVER=server -bd -oX PORT_D **** # this one should succeed diff --git a/test/stderr/5400 b/test/stderr/5400 index 73934dd92..29ff83b42 100644 --- a/test/stderr/5400 +++ b/test/stderr/5400 @@ -26,7 +26,11 @@ processing "accept" accept: condition test succeeded in inline ACL SMTP>> DATA SMTP<< 354 Send data - SMTP>>(nl) +----------- start cutthrough headers send ----------- +added header line(s): +X-hdr-rtr-new: +++ +--- +----------- done cutthrough headers send ------------ SMTP>> . SMTP<< 250 OK LOG: MAIN @@ -69,7 +73,11 @@ processing "accept" accept: condition test succeeded in inline ACL SMTP>> DATA SMTP<< 354 Send data - SMTP>>(nl) +----------- start cutthrough headers send ----------- +added header line(s): +X-hdr-rtr-new: +++ +--- +----------- done cutthrough headers send ------------ SMTP>> . SMTP<< 250 OK LOG: MAIN @@ -147,6 +155,9 @@ not using PIPELINING SMTP>> DATA SMTP<< 354 Send data SMTP>> writing message and terminating "." +added header line(s): +X-hdr-rtr-new: +++ +--- writing data block fd=dddd size=sss timeout=300 SMTP<< 250 OK ok=1 send_quit=1 send_rset=0 continue_more=0 yield=0 first_address is NULL @@ -162,3 +173,54 @@ LOG: MAIN LOG: MAIN Completed >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> +Exim version x.yz .... +configuration file is TESTSUITE/test-config +admin user +LOG: smtp_connection MAIN + SMTP connection from CALLER +using ACL "ar" +processing "accept" +check control = cutthrough_delivery +check logwrite = rcpt for $local_part@$domain + = rcpt for userx@domain.com +LOG: MAIN + rcpt for userx@domain.com +accept: condition test succeeded in ACL "ar" +----------- start cutthrough setup ------------ +Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... connected + SMTP<< 220 ESMTP + SMTP>> EHLO myhost.test.ex + SMTP<< 250 OK + SMTP>> MAIL FROM: + SMTP<< 250 Sender OK + SMTP>> RCPT TO: + SMTP<< 250 Recipient OK +----------- end cutthrough setup ------------ +processing "accept" +accept: condition test succeeded in inline ACL + SMTP>> DATA + SMTP<< 354 Send data +----------- start cutthrough headers send ----------- +removed header line: +X-hdr-rtr: qqq +--- +added header line(s): +X-hdr-rtr-new: +++ +--- +added header line(s): +X-hdr-tpt-new: new +--- +----------- done cutthrough headers send ------------ + SMTP>> . + SMTP<< 250 OK +LOG: MAIN + >> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" + SMTP>> QUIT +----------- cutthrough shutdown (delivered) ------------ +LOG: MAIN + <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss +LOG: MAIN + Completed +LOG: smtp_connection MAIN + SMTP connection from CALLER closed by QUIT +>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> diff --git a/test/stderr/5401 b/test/stderr/5401 index 135c11ace..1bd14f8d5 100644 --- a/test/stderr/5401 +++ b/test/stderr/5401 @@ -23,7 +23,8 @@ processing "accept" accept: condition test succeeded in inline ACL SMTP>> DATA SMTP<< 354 Send data - SMTP>>(nl) +----------- start cutthrough headers send ----------- +----------- done cutthrough headers send ------------ SMTP>> . SMTP<< 250 OK LOG: MAIN diff --git a/test/stderr/5410 b/test/stderr/5410 index 40ef77c4a..334301139 100644 --- a/test/stderr/5410 +++ b/test/stderr/5410 @@ -137,7 +137,8 @@ expanding: for $received_for result: for userx@domain.com -PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +----------- start cutthrough headers send ----------- +----------- done cutthrough headers send ------------ expanding: ${tod_full} result: Tue, 2 Mar 1999 09:44:33 +0000 SMTP>> . @@ -270,7 +271,8 @@ expanding: for $received_for result: for usery@domain.com -PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +----------- start cutthrough headers send ----------- +----------- done cutthrough headers send ------------ expanding: ${tod_full} result: Tue, 2 Mar 1999 09:44:33 +0000 SMTP>> . @@ -403,7 +405,8 @@ expanding: for $received_for result: for usery@domain.com -PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +----------- start cutthrough headers send ----------- +----------- done cutthrough headers send ------------ expanding: ${tod_full} result: Tue, 2 Mar 1999 09:44:33 +0000 SMTP>> . diff --git a/test/stdout/5400 b/test/stdout/5400 index 74c2d2358..4895072a3 100644 --- a/test/stdout/5400 +++ b/test/stdout/5400 @@ -32,6 +32,17 @@ 354 Enter message, ending with "." on a line by itself 250 OK id=10HmaZ-0005vi-00 221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at myhost.test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmbA-0005vi-00 +221 myhost.test.ex closing connection ******** SERVER ******** Listening on port 1224 ... @@ -53,6 +64,7 @@ Received: from CALLER (helo=myhost.test.ex) Message-Id: From: CALLER_NAME Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ . 250 OK @@ -80,6 +92,7 @@ Received: from CALLER (helo=myhost.test.ex) Message-Id: From: CALLER_NAME Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ . 250 OK @@ -117,7 +130,37 @@ Received: from CALLER (helo=myhost.test.ex) Message-Id: From: CALLER_NAME Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ + +. +250 OK +QUIT +250 OK +End of script +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 Recipient OK +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmbA-0005vi-00 + for userx@domain.com; Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-tpt: zzz +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ + +body . 250 OK QUIT