summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2015-04-13 00:18:54 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2015-04-13 00:18:54 +0100
commit6023a6ad2ac0294879b14127f62795095da573b5 (patch)
tree0e1f0f4071a58949ba7ee1c4d50a52c01202a6c1
parent0ebc4d69b3211e47f0df60ebc43e1735d91286f8 (diff)
parentc5b8e8e93ea6a54f526a9faaf0bc6ea7e813d650 (diff)
Merge branch 'SMTPUTF8_1516'. Bug 1516
This adds limited support for the ESMTP option SMTPUTF8 under the EXPERIMENTAL_INTERNATIONAL compile define
-rw-r--r--doc/doc-txt/experimental-spec.txt45
-rw-r--r--src/OS/Makefile-Base3
-rwxr-xr-xsrc/scripts/MakeLinks1
-rw-r--r--src/src/EDITME5
-rw-r--r--src/src/acl.c14
-rw-r--r--src/src/config.h.defaults1
-rw-r--r--src/src/deliver.c176
-rw-r--r--src/src/dns.c17
-rw-r--r--src/src/exim.c41
-rw-r--r--src/src/expand.c91
-rw-r--r--src/src/filter.c2
-rw-r--r--src/src/functions.h11
-rw-r--r--src/src/globals.c13
-rw-r--r--src/src/globals.h7
-rw-r--r--src/src/macros.h6
-rw-r--r--src/src/parse.c6
-rw-r--r--src/src/queue.c6
-rw-r--r--src/src/rda.c4
-rw-r--r--src/src/readconf.c3
-rw-r--r--src/src/receive.c14
-rw-r--r--src/src/route.c14
-rw-r--r--src/src/routers/accept.c6
-rw-r--r--src/src/routers/dnslookup.c6
-rw-r--r--src/src/routers/ipliteral.c6
-rw-r--r--src/src/routers/iplookup.c8
-rw-r--r--src/src/routers/manualroute.c6
-rw-r--r--src/src/routers/queryprogram.c10
-rw-r--r--src/src/routers/redirect.c27
-rw-r--r--src/src/routers/rf_change_domain.c2
-rw-r--r--src/src/routers/rf_get_errors_address.c2
-rw-r--r--src/src/routers/rf_get_munge_headers.c4
-rw-r--r--src/src/routers/rf_queue_add.c10
-rw-r--r--src/src/sieve.c2
-rw-r--r--src/src/smtp_in.c209
-rw-r--r--src/src/spool_in.c8
-rw-r--r--src/src/spool_out.c4
-rw-r--r--src/src/structs.h5
-rw-r--r--src/src/transport.c10
-rw-r--r--src/src/transports/smtp.c115
-rw-r--r--src/src/utf8.c152
-rw-r--r--src/src/verify.c62
-rw-r--r--test/confs/420012
-rw-r--r--test/confs/4201120
-rw-r--r--test/confs/4211126
-rw-r--r--test/confs/4221126
-rw-r--r--test/dnszones-src/db.test.ex8
-rw-r--r--test/log/420195
-rw-r--r--test/log/421174
-rw-r--r--test/log/422174
-rw-r--r--test/mail/4201.यहलोगहिन्दीक्योंनहींबोलसकतेहैं59
-rw-r--r--test/mail/4211.यहलोगहिन्दीक्योंनहींबोलसकतेहैं59
-rw-r--r--test/mail/4221.यहलोगहिन्दीक्योंनहींबोलसकतेहैं59
-rw-r--r--test/rejectlog/42018
-rw-r--r--test/rejectlog/42118
-rw-r--r--test/rejectlog/42218
-rwxr-xr-xtest/runtest7
-rw-r--r--test/scripts/4200-International/420096
-rw-r--r--test/scripts/4200-International/4201265
-rw-r--r--test/scripts/4200-International/REQUIRES1
-rw-r--r--test/scripts/4210-GnuTLS-International/4211246
-rw-r--r--test/scripts/4210-GnuTLS-International/REQUIRES2
-rw-r--r--test/scripts/4220-OpenSSL-International/4221245
-rw-r--r--test/scripts/4220-OpenSSL-International/REQUIRES2
-rw-r--r--test/stderr/02752
-rw-r--r--test/stderr/02782
-rw-r--r--test/stderr/03614
-rw-r--r--test/stderr/03864
-rw-r--r--test/stderr/040214
-rw-r--r--test/stderr/04034
-rw-r--r--test/stderr/04046
-rw-r--r--test/stderr/04082
-rw-r--r--test/stderr/04872
-rw-r--r--test/stderr/26002
-rw-r--r--test/stderr/50044
-rw-r--r--test/stderr/50054
-rw-r--r--test/stderr/50062
-rw-r--r--test/stdout/04055
-rw-r--r--test/stdout/420069
-rw-r--r--test/stdout/4201208
-rw-r--r--test/stdout/4211223
-rw-r--r--test/stdout/4221223
81 files changed, 3309 insertions, 305 deletions
diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt
index e6e066c04..819b47fd5 100644
--- a/doc/doc-txt/experimental-spec.txt
+++ b/doc/doc-txt/experimental-spec.txt
@@ -1270,6 +1270,51 @@ in combination with EXPERIMENTAL_EVENT), and a new variable
$tls_out_tlsa_usage (detailed above).
+
+SMTPUTF8
+------------------------------------------------------------
+Internationalised mail name handling.
+RFCs 6530, 6533, 5890
+
+Compile with EXPERIMENTAL_INTERNATIONAL and libidn.
+
+New main config option smtputf8_advertise_hosts, default '*',
+a host list. If this matches the sending host and
+accept_8bitmime is true (the default) then the ESMTP option
+SMTPUTF8 will be advertised.
+
+If the sender specifies the SMTPUTF8 option on a MAIL command
+international handling for the message is enabled and
+the expansion variable $message_smtputf8 will have value TRUE.
+
+The option allow_utf8_domains is set to true for this
+message. All DNS lookups are converted to a-label form
+whatever the setting of allow_utf8_domains.
+
+Both localparts and domain are maintained as the original
+utf8 form internally; any matching or regex use will
+require appropriate care. Filenames created, eg. by
+the appendfile transport, will have utf8 name.
+
+Helo names sent by the smtp transport will have any utf8
+components expanded to a-label form.
+
+Log lines and Received-by: header lines will aquire a "utf8"
+prefix on the protocol element, eg. utf8esmtp.
+
+New expansion operators:
+ ${utf8_domain_to_alabel:str}
+ ${utf8_domain_from_alabel:str}
+ ${utf8_localpart_to_alabel:str}
+ ${utf8_localpart_from_alabel:str}
+
+Known issues:
+ - Currently LMTP is not supported.
+ - DSN unitext handling is not present
+ - no provision for converting logging from UTF-8
+ - VRFY and EXPN not handled
+ - MSA mode not handled (!)
+
--------------------------------------------------------------
End of file
--------------------------------------------------------------
diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
index 38d719837..63646e218 100644
--- a/src/OS/Makefile-Base
+++ b/src/OS/Makefile-Base
@@ -295,7 +295,7 @@ convert4r4: Makefile ../src/convert4r4.src
OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o
OBJ_WITH_OLD_DEMIME = demime.o
-OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dcc.o dmarc.o dane.o
+OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dcc.o dmarc.o dane.o utf8.o
# Targets for final binaries; the main one has a build number which is
# updated each time. We don't bother with that for the auxiliaries.
@@ -604,6 +604,7 @@ dcc.o: $(HDRS) dcc.h dcc.c
dmarc.o: $(HDRS) dmarc.h dmarc.c
spf.o: $(HDRS) spf.h spf.c
srs.o: $(HDRS) srs.h srs.c
+utf8.o: $(HDRS) utf8.c
# The module containing tables of available lookups, routers, auths, and
# transports must be rebuilt if any of them are. However, because the makefiles
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index f68fd6f4b..f9cc27c2e 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -276,6 +276,7 @@ ln -s ../src/dane.c dane.c
ln -s ../src/dane-gnu.c dane-gnu.c
ln -s ../src/dane-openssl.c dane-openssl.c
ln -s ../src/danessl.h danessl.h
+ln -s ../src/utf8.c utf8.c
# End of MakeLinks
diff --git a/src/src/EDITME b/src/src/EDITME
index d48f268b9..426033577 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -497,6 +497,11 @@ EXIM_MONITOR=eximon.bin
# Uncomment the following line to add SOCKS support
# EXPERIMENTAL_SOCKS=yes
+# Uncomment the following to add Internationalisation features. You need to
+# have the IDN library installed.
+EXPERIMENTAL_INTERNATIONAL=yes
+LDFLAGS += -lidn
+
###############################################################################
# THESE ARE THINGS YOU MIGHT WANT TO SPECIFY #
###############################################################################
diff --git a/src/src/acl.c b/src/src/acl.c
index ea078f6fd..3f513c328 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -2079,6 +2079,9 @@ else if (verify_sender_address != NULL)
uschar *save_address_data = deliver_address_data;
sender_vaddr = deliver_make_addr(verify_sender_address, TRUE);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ sender_vaddr->prop.utf8 = message_smtputf8;
+#endif
if (no_details) setflag(sender_vaddr, af_sverify_told);
if (verify_sender_address[0] != 0)
{
@@ -2135,7 +2138,7 @@ else if (verify_sender_address != NULL)
/* Put the sender address_data value into $sender_address_data */
- sender_address_data = sender_vaddr->p.address_data;
+ sender_address_data = sender_vaddr->prop.address_data;
}
/* A recipient address just gets a straightforward verify; again we must handle
@@ -2165,7 +2168,7 @@ else
if (testflag((&addr2), af_pass_message)) acl_temp_details = TRUE;
/* Make $address_data visible */
- deliver_address_data = addr2.p.address_data;
+ deliver_address_data = addr2.prop.address_data;
}
/* We have a result from the relevant test. Handle defer overrides first. */
@@ -2184,13 +2187,9 @@ sender_verified_failed to the address item that actually failed. */
if (rc != OK && verify_sender_address != NULL)
{
if (rc != DEFER)
- {
*log_msgptr = *user_msgptr = US"Sender verify failed";
- }
else if (*basic_errno != ERRNO_CALLOUTDEFER)
- {
*log_msgptr = *user_msgptr = US"Could not complete sender verify";
- }
else
{
*log_msgptr = US"Could not complete sender verify callout";
@@ -4382,6 +4381,9 @@ if (where == ACL_WHERE_RCPT)
*log_msgptr = US"defer in percent_hack_domains check";
return DEFER;
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ addr->prop.utf8 = message_smtputf8;
+#endif
deliver_domain = addr->domain;
deliver_localpart = addr->local_part;
}
diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
index ac4994a3e..d31f11548 100644
--- a/src/src/config.h.defaults
+++ b/src/src/config.h.defaults
@@ -171,6 +171,7 @@ it's a default value. */
#define EXPERIMENTAL_DCC
#define EXPERIMENTAL_DMARC
#define EXPERIMENTAL_EVENT
+#define EXPERIMENTAL_INTERNATIONAL
#define EXPERIMENTAL_PROXY
#define EXPERIMENTAL_REDIS
#define EXPERIMENTAL_SOCKS
diff --git a/src/src/deliver.c b/src/src/deliver.c
index 1cdecc6e9..85a379c1b 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -149,9 +149,9 @@ else
}
deliver_recipients = addr;
-deliver_address_data = addr->p.address_data;
-deliver_domain_data = addr->p.domain_data;
-deliver_localpart_data = addr->p.localpart_data;
+deliver_address_data = addr->prop.address_data;
+deliver_domain_data = addr->prop.domain_data;
+deliver_localpart_data = addr->prop.localpart_data;
/* These may be unset for multiple addresses */
@@ -825,8 +825,8 @@ if ((log_extra_selector & LX_sender_on_delivery) != 0 || msg)
s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
#ifdef EXPERIMENTAL_SRS
-if(addr->p.srs_sender)
- s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->p.srs_sender, US">");
+if(addr->prop.srs_sender)
+ s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->prop.srs_sender, US">");
#endif
/* You might think that the return path must always be set for a successful
@@ -1093,7 +1093,7 @@ if (addr->return_file >= 0 && addr->return_filename != NULL)
/* Handle returning options, but only if there is an address to return
the text to. */
- if (sender_address[0] != 0 || addr->p.errors_address != NULL)
+ if (sender_address[0] != 0 || addr->prop.errors_address != NULL)
{
if (tb->return_output)
{
@@ -1310,7 +1310,7 @@ else
if (!testflag(addr, af_ignore_error) &&
(addr->special_action == SPECIAL_FREEZE ||
- (sender_address[0] == 0 && addr->p.errors_address == NULL)
+ (sender_address[0] == 0 && addr->prop.errors_address == NULL)
))
{
frozen_info = (addr->special_action == SPECIAL_FREEZE)? US"" :
@@ -1810,11 +1810,11 @@ transport_instance *tp = addr->transport;
/* Set up the return path from the errors or sender address. If the transport
has its own return path setting, expand it and replace the existing value. */
-if(addr->p.errors_address != NULL)
- return_path = addr->p.errors_address;
+if(addr->prop.errors_address != NULL)
+ return_path = addr->prop.errors_address;
#ifdef EXPERIMENTAL_SRS
-else if(addr->p.srs_sender != NULL)
- return_path = addr->p.srs_sender;
+else if(addr->prop.srs_sender != NULL)
+ return_path = addr->prop.srs_sender;
#endif
else
return_path = sender_address;
@@ -2426,9 +2426,9 @@ while (addr_local != NULL)
(addr->flags & (af_pfr|af_file)) == (next->flags & (af_pfr|af_file)) &&
(!uses_lp || Ustrcmp(next->local_part, addr->local_part) == 0) &&
(!uses_dom || Ustrcmp(next->domain, addr->domain) == 0) &&
- same_strings(next->p.errors_address, addr->p.errors_address) &&
- same_headers(next->p.extra_headers, addr->p.extra_headers) &&
- same_strings(next->p.remove_headers, addr->p.remove_headers) &&
+ same_strings(next->prop.errors_address, addr->prop.errors_address) &&
+ same_headers(next->prop.extra_headers, addr->prop.extra_headers) &&
+ same_strings(next->prop.remove_headers, addr->prop.remove_headers) &&
same_ugid(tp, addr, next) &&
((addr->host_list == NULL && next->host_list == NULL) ||
(addr->host_list != NULL && next->host_list != NULL &&
@@ -3950,13 +3950,13 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
if ( (multi_domain || Ustrcmp(next->domain, addr->domain) == 0)
&& tp == next->transport
&& same_hosts(next->host_list, addr->host_list)
- && same_strings(next->p.errors_address, addr->p.errors_address)
- && same_headers(next->p.extra_headers, addr->p.extra_headers)
+ && same_strings(next->prop.errors_address, addr->prop.errors_address)
+ && same_headers(next->prop.extra_headers, addr->prop.extra_headers)
&& same_ugid(tp, next, addr)
- && ( next->p.remove_headers == addr->p.remove_headers
- || ( next->p.remove_headers != NULL
- && addr->p.remove_headers != NULL
- && Ustrcmp(next->p.remove_headers, addr->p.remove_headers) == 0
+ && ( next->prop.remove_headers == addr->prop.remove_headers
+ || ( next->prop.remove_headers
+ && addr->prop.remove_headers
+ && Ustrcmp(next->prop.remove_headers, addr->prop.remove_headers) == 0
) )
&& ( !multi_domain
|| ( (
@@ -4000,11 +4000,11 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
/* Compute the return path, expanding a new one if required. The old one
must be set first, as it might be referred to in the expansion. */
- if(addr->p.errors_address != NULL)
- return_path = addr->p.errors_address;
+ if(addr->prop.errors_address != NULL)
+ return_path = addr->prop.errors_address;
#ifdef EXPERIMENTAL_SRS
- else if(addr->p.srs_sender != NULL)
- return_path = addr->p.srs_sender;
+ else if(addr->prop.srs_sender != NULL)
+ return_path = addr->prop.srs_sender;
#endif
else
return_path = sender_address;
@@ -5593,7 +5593,11 @@ if (process_recipients != RECIP_IGNORE)
{
recipient_item *r = recipients_list + i;
address_item *new = deliver_make_addr(r->address, FALSE);
- new->p.errors_address = r->errors_to;
+ new->prop.errors_address = r->errors_to;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ new->prop.utf8 = message_smtputf8;
+ DEBUG(D_deliver) if (message_smtputf8) debug_printf("utf8\n");
+#endif
if (r->pno >= 0)
new->onetime_parent = recipients_list[r->pno].address;
@@ -5602,7 +5606,8 @@ if (process_recipients != RECIP_IGNORE)
to be passed on to other DSN enabled MTAs */
new->dsn_flags = r->dsn_flags & rf_dsnflags;
new->dsn_orcpt = r->orcpt;
- DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: %d\n", new->dsn_orcpt, new->dsn_flags);
+ DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: %d\n",
+ new->dsn_orcpt, new->dsn_flags);
switch (process_recipients)
{
@@ -6189,8 +6194,8 @@ while (addr_new != NULL) /* Loop until all addresses dealt with */
/* Just in case some router parameter refers to it. */
- return_path = (addr->p.errors_address != NULL)?
- addr->p.errors_address : sender_address;
+ return_path = (addr->prop.errors_address != NULL)?
+ addr->prop.errors_address : sender_address;
/* If a router defers an address, add a retry item. Whether or not to
use the local part in the key is a property of the router. */
@@ -6260,8 +6265,8 @@ while (addr_new != NULL) /* Loop until all addresses dealt with */
if (addr_remote == addr &&
addr->router->same_domain_copy_routing &&
- addr->p.extra_headers == NULL &&
- addr->p.remove_headers == NULL &&
+ addr->prop.extra_headers == NULL &&
+ addr->prop.remove_headers == NULL &&
old_domain == addr->domain)
{
address_item **chain = &addr_route;
@@ -6288,7 +6293,7 @@ while (addr_new != NULL) /* Loop until all addresses dealt with */
addr2->transport = addr->transport;
addr2->host_list = addr->host_list;
addr2->fallback_hosts = addr->fallback_hosts;
- addr2->p.errors_address = addr->p.errors_address;
+ addr2->prop.errors_address = addr->prop.errors_address;
copyflag(addr2, addr, af_hide_child | af_local_host_removed);
DEBUG(D_deliver|D_route)
@@ -6660,29 +6665,36 @@ else if (!dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed);
addr_dsntmp = addr_succeed;
addr_senddsn = NULL;
-while(addr_dsntmp != NULL)
+while(addr_dsntmp)
{
- DEBUG(D_deliver)
- debug_printf("DSN: processing router : %s\n", addr_dsntmp->router->name);
-
- DEBUG(D_deliver)
- debug_printf("DSN: processing successful delivery address: %s\n", addr_dsntmp->address);
-
/* af_ignore_error not honored here. it's not an error */
-
- DEBUG(D_deliver) debug_printf("DSN: Sender_address: %s\n", sender_address);
- DEBUG(D_deliver) debug_printf("DSN: orcpt: %s flags: %d\n", addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags);
- DEBUG(D_deliver) debug_printf("DSN: envid: %s ret: %d\n", dsn_envid, dsn_ret);
- DEBUG(D_deliver) debug_printf("DSN: Final recipient: %s\n", addr_dsntmp->address);
- DEBUG(D_deliver) debug_printf("DSN: Remote SMTP server supports DSN: %d\n", addr_dsntmp->dsn_aware);
+ DEBUG(D_deliver)
+ {
+ debug_printf("DSN: processing router : %s\n"
+ "DSN: processing successful delivery address: %s\n"
+ "DSN: Sender_address: %s\n"
+ "DSN: orcpt: %s flags: %d\n"
+ "DSN: envid: %s ret: %d\n"
+ "DSN: Final recipient: %s\n"
+ "DSN: Remote SMTP server supports DSN: %d\n",
+ addr_dsntmp->router->name,
+ addr_dsntmp->address,
+ sender_address,
+ addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags,
+ dsn_envid, dsn_ret,
+ addr_dsntmp->address,
+ addr_dsntmp->dsn_aware
+ );
+ }
/* send report if next hop not DSN aware or a router flagged "last DSN hop"
and a report was requested */
- if (((addr_dsntmp->dsn_aware != dsn_support_yes) ||
- ((addr_dsntmp->dsn_flags & rf_dsnlasthop) != 0))
- &&
- (((addr_dsntmp->dsn_flags & rf_dsnflags) != 0) &&
- ((addr_dsntmp->dsn_flags & rf_notify_success) != 0)))
+ if ( ( addr_dsntmp->dsn_aware != dsn_support_yes
+ || addr_dsntmp->dsn_flags & rf_dsnlasthop
+ )
+ && addr_dsntmp->dsn_flags & rf_dsnflags
+ && addr_dsntmp->dsn_flags & rf_notify_success
+ )
{
/* copy and relink address_item and send report with all of them at once later */
address_item *addr_next;
@@ -6692,14 +6704,12 @@ while(addr_dsntmp != NULL)
addr_senddsn->next = addr_next;
}
else
- {
- DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message ***\n");
- }
+ DEBUG(D_deliver) debug_printf("DSN: not sending DSN success message\n");
addr_dsntmp = addr_dsntmp->next;
}
-if (addr_senddsn != NULL)
+if (addr_senddsn)
{
pid_t pid;
int fd;
@@ -6854,10 +6864,10 @@ while (addr_failed != NULL)
If neither of these cases obtains, something has gone wrong. Log the
incident, but then ignore the error. */
- if (sender_address[0] == 0 && addr_failed->p.errors_address == NULL)
+ if (sender_address[0] == 0 && addr_failed->prop.errors_address == NULL)
{
- if (!testflag(addr_failed, af_retry_timedout) &&
- !testflag(addr_failed, af_ignore_error))
+ if ( !testflag(addr_failed, af_retry_timedout)
+ && !testflag(addr_failed, af_ignore_error))
{
log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message "
"failure is neither frozen nor ignored (it's been ignored)");
@@ -6870,8 +6880,8 @@ while (addr_failed != NULL)
mark the recipient done. */
if ( testflag(addr_failed, af_ignore_error)
- || ( ((addr_failed->dsn_flags & rf_dsnflags) != 0)
- && ((addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure))
+ || ( addr_failed->dsn_flags & rf_dsnflags
+ && (addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure)
)
{
addr = addr_failed;
@@ -6898,8 +6908,8 @@ while (addr_failed != NULL)
else
{
- bounce_recipient = addr_failed->p.errors_address
- ? addr_failed->p.errors_address : sender_address;
+ bounce_recipient = addr_failed->prop.errors_address
+ ? addr_failed->prop.errors_address : sender_address;
/* Make a subprocess to send a message */
@@ -6934,8 +6944,8 @@ while (addr_failed != NULL)
paddr = &addr_failed;
for (addr = addr_failed; addr != NULL; addr = *paddr)
- if (Ustrcmp(bounce_recipient, addr->p.errors_address
- ? addr->p.errors_address : sender_address) == 0)
+ if (Ustrcmp(bounce_recipient, addr->prop.errors_address
+ ? addr->prop.errors_address : sender_address) == 0)
{ /* The same - dechain */
*paddr = addr->next;
*pmsgchain = addr;
@@ -7136,10 +7146,18 @@ wording. */
}
/* output machine readable part */
- fprintf(f, "--%s\n"
- "Content-type: message/delivery-status\n\n"
- "Reporting-MTA: dns; %s\n",
- bound, smtp_active_hostname);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if (message_smtputf8)
+ fprintf(f, "--%s\n"
+ "Content-type: message/global-delivery-status\n\n"
+ "Reporting-MTA: dns; %s\n",
+ bound, smtp_active_hostname);
+ else
+#endif
+ fprintf(f, "--%s\n"
+ "Content-type: message/delivery-status\n\n"
+ "Reporting-MTA: dns; %s\n",
+ bound, smtp_active_hostname);
if (dsn_envid)
{
@@ -7214,9 +7232,16 @@ wording. */
}
}
- fputs(topt & topt_no_body ? "Content-type: text/rfc822-headers\n\n"
- : "Content-type: message/rfc822\n\n",
- f);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if (message_smtputf8)
+ fputs(topt & topt_no_body ? "Content-type: message/global-headers\n\n"
+ : "Content-type: message/global\n\n",
+ f);
+ else
+#endif
+ fputs(topt & topt_no_body ? "Content-type: text/rfc822-headers\n\n"
+ : "Content-type: message/rfc822\n\n",
+ f);
fflush(f);
transport_filter_argv = NULL; /* Just in case */
@@ -7431,7 +7456,7 @@ else if (addr_defer != (address_item *)(+1))
DEBUG(D_deliver) debug_printf("one_time: adding %s in place of %s\n",
otaddr->address, otaddr->parent->address);
receive_add_recipient(otaddr->address, t);
- recipients_list[recipients_count-1].errors_to = otaddr->p.errors_address;
+ recipients_list[recipients_count-1].errors_to = otaddr->prop.errors_address;
tree_add_nonrecipient(otaddr->parent->address);
update_spool = TRUE;
}
@@ -7443,7 +7468,7 @@ else if (addr_defer != (address_item *)(+1))
if (sender_address[0] != 0)
{
- if (addr->p.errors_address == NULL)
+ if (addr->prop.errors_address == NULL)
{
if (Ustrstr(recipients, sender_address) == NULL)
recipients = string_sprintf("%s%s%s", recipients,
@@ -7451,9 +7476,9 @@ else if (addr_defer != (address_item *)(+1))
}
else
{
- if (Ustrstr(recipients, addr->p.errors_address) == NULL)
+ if (Ustrstr(recipients, addr->prop.errors_address) == NULL)
recipients = string_sprintf("%s%s%s", recipients,
- (recipients[0] == 0)? "" : ",", addr->p.errors_address);
+ (recipients[0] == 0)? "" : ",", addr->prop.errors_address);
}
}
}
@@ -7857,6 +7882,11 @@ if (!regex_PRDR) regex_PRDR =
regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
#endif
+#ifdef SUPPORT_TLS
+if (!regex_UTF8) regex_UTF8 =
+ regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE);
+#endif
+
if (!regex_DSN) regex_DSN =
regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
diff --git a/src/src/dns.c b/src/src/dns.c
index a2f430993..6f75386ed 100644
--- a/src/src/dns.c
+++ b/src/src/dns.c
@@ -576,6 +576,23 @@ if (previous != NULL)
return previous->data.val;
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+/* Convert all names to a-label form before doing lookup */
+ {
+ uschar * alabel;
+ uschar * errstr = NULL;
+ if ((alabel = string_domain_utf8_to_alabel(name, &errstr)), errstr)
+ {
+ DEBUG(D_dns)
+ debug_printf("DNS name '%s' utf8 conversion to alabel failed: %s\n", name,
+ errstr);
+ host_find_failed_syntax = TRUE;
+ return DNS_NOMATCH;
+ }
+ name = alabel;
+ }
+#endif
+
/* If configured, check the hygene of the name passed to lookup. Otherwise,
although DNS lookups may give REFUSED at the lower level, some resolvers
turn this into TRY_AGAIN, which is silly. Give a NOMATCH return, since such
diff --git a/src/src/exim.c b/src/src/exim.c
index 54725ef37..cae296477 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -856,6 +856,9 @@ fprintf(f, "Support for:");
#ifdef EXPERIMENTAL_SOCKS
fprintf(f, " Experimental_SOCKS");
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ fprintf(f, " Experimental_International");
+#endif
fprintf(f, "\n");
fprintf(f, "Lookups (built-in):");
@@ -1019,6 +1022,9 @@ DEBUG(D_any) do {
#ifdef SUPPORT_TLS
tls_version_report(f);
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ utf8_version_report(f);
+#endif
for (authi = auths_available; *authi->driver_name != '\0'; ++authi) {
if (authi->version_report) {
@@ -2516,7 +2522,7 @@ for (i = 1; i < argc; i++)
case 'f':
{
- int start, end;
+ int dummy_start, dummy_end;
uschar *errmess;
if (*argrest == 0)
{
@@ -2524,9 +2530,7 @@ for (i = 1; i < argc; i++)
{ badarg = TRUE; break; }
}
if (*argrest == 0)
- {
sender_address = string_sprintf(""); /* Ensure writeable memory */
- }
else
{
uschar *temp = argrest + Ustrlen(argrest) - 1;
@@ -2534,8 +2538,15 @@ for (i = 1; i < argc; i++)
if (temp >= argrest && *temp == '.') f_end_dot = TRUE;
allow_domain_literals = TRUE;
strip_trailing_dot = TRUE;
- sender_address = parse_extract_address(argrest, &errmess, &start, &end,
- &sender_address_domain, TRUE);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ allow_utf8_domains = TRUE;
+#endif
+ sender_address = parse_extract_address(argrest, &errmess,
+ &dummy_start, &dummy_end, &sender_address_domain, TRUE);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ message_smtputf8 = string_is_utf8(sender_address);
+ allow_utf8_domains = FALSE;
+#endif
allow_domain_literals = FALSE;
strip_trailing_dot = FALSE;
if (sender_address == NULL)
@@ -3702,6 +3713,10 @@ is equivalent to the ability to modify a setuid binary!
This needs to happen before we read the main configuration. */
init_lookup_list();
+#ifdef EXPERIMENTAL_INTERNATIONAL
+if (running_in_test_harness) smtputf8_advertise_hosts = NULL;
+#endif
+
/* Read the main runtime configuration data; this gives up if there
is a failure. It leaves the configuration file open so that the subsequent
configuration data for delivery can be read if needed. */
@@ -5351,7 +5366,6 @@ while (more)
if (recipients_max > 0 && ++rcount > recipients_max &&
!extract_recipients)
- {
if (error_handling == ERRORS_STDERR)
{
fprintf(stderr, "exim: too many recipients\n");
@@ -5363,11 +5377,22 @@ while (more)
moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)?
errors_sender_rc : EXIT_FAILURE;
}
- }
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ {
+ BOOL b = allow_utf8_domains;
+ allow_utf8_domains = TRUE;
+#endif
recipient =
parse_extract_address(s, &errmess, &start, &end, &domain, FALSE);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if (string_is_utf8(recipient))
+ message_smtputf8 = TRUE;
+ else
+ allow_utf8_domains = b;
+ }
+#endif
if (domain == 0 && !allow_unqualified_recipient)
{
recipient = NULL;
@@ -5467,9 +5492,7 @@ while (more)
return_path = string_copy(sender_address);
}
else
- {
printf("Return-path = %s\n", (return_path[0] == 0)? US"<>" : return_path);
- }
printf("Sender = %s\n", (sender_address[0] == 0)? US"<>" : sender_address);
receive_add_recipient(
diff --git a/src/src/expand.c b/src/src/expand.c
index 8a7a27e8a..ad97f6fef 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -168,7 +168,14 @@ static uschar *op_table_underscore[] = {
US"quote_local_part",
US"reverse_ip",
US"time_eval",
- US"time_interval"};
+ US"time_interval"
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ ,US"utf8_domain_from_alabel",
+ US"utf8_domain_to_alabel",
+ US"utf8_localpart_from_alabel",
+ US"utf8_localpart_to_alabel"
+#endif
+ };
enum {
EOP_FROM_UTF8,
@@ -176,7 +183,14 @@ enum {
EOP_QUOTE_LOCAL_PART,
EOP_REVERSE_IP,
EOP_TIME_EVAL,
- EOP_TIME_INTERVAL };
+ EOP_TIME_INTERVAL
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ ,EOP_UTF8_DOMAIN_FROM_ALABEL,
+ EOP_UTF8_DOMAIN_TO_ALABEL,
+ EOP_UTF8_LOCALPART_FROM_ALABEL,
+ EOP_UTF8_LOCALPART_TO_ALABEL
+#endif
+ };
static uschar *op_table_main[] = {
US"address",
@@ -549,6 +563,9 @@ static var_entry var_table[] = {
{ "message_id", vtype_stringptr, &message_id },
{ "message_linecount", vtype_int, &message_linecount },
{ "message_size", vtype_int, &message_size },
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ { "message_smtputf8", vtype_bool, &message_smtputf8 },
+#endif
#ifdef WITH_CONTENT_SCAN
{ "mime_anomaly_level", vtype_int, &mime_anomaly_level },
{ "mime_anomaly_text", vtype_stringptr, &mime_anomaly_text },
@@ -6552,16 +6569,13 @@ while (*s != 0)
if (bytes_left)
{
if ((c & 0xc0) != 0x80)
- {
/* wrong continuation byte; invalidate all bytes */
complete = 1; /* error */
- }
else
{
codepoint = (codepoint << 6) | (c & 0x3f);
seq_buff[index++] = c;
if (--bytes_left == 0) /* codepoint complete */
- {
if(codepoint > 0x10FFFF) /* is it too large? */
complete = -1; /* error (RFC3629 limit) */
else
@@ -6569,7 +6583,6 @@ while (*s != 0)
yield = string_cat(yield, &size, &ptr, seq_buff, seq_len);
index = 0;
}
- }
}
}
else /* no bytes left: new sequence */
@@ -6612,13 +6625,75 @@ while (*s != 0)
yield = string_cat(yield, &size, &ptr, UTF8_REPLACEMENT_CHAR, 1);
}
if ((complete == 1) && ((c & 0x80) == 0))
- { /* ASCII character follows incomplete sequence */
+ /* ASCII character follows incomplete sequence */
yield = string_cat(yield, &size, &ptr, &c, 1);
- }
}
continue;
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ case EOP_UTF8_DOMAIN_TO_ALABEL:
+ {
+ uschar * error = NULL;
+ uschar * s = string_domain_utf8_to_alabel(sub, &error);
+ if (error)
+ {
+ expand_string_message = string_sprintf(
+ "error converting utf8 (%s) to alabel: %s",
+ string_printing(sub), error);
+ goto EXPAND_FAILED;
+ }
+ yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+ continue;
+ }
+
+ case EOP_UTF8_DOMAIN_FROM_ALABEL:
+ {
+ uschar * error = NULL;
+ uschar * s = string_domain_alabel_to_utf8(sub, &error);
+ if (error)
+ {
+ expand_string_message = string_sprintf(
+ "error converting alabel (%s) to utf8: %s",
+ string_printing(sub), error);
+ goto EXPAND_FAILED;
+ }
+ yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+ continue;
+ }
+
+ case EOP_UTF8_LOCALPART_TO_ALABEL:
+ {
+ uschar * error = NULL;
+ uschar * s = string_localpart_utf8_to_alabel(sub, &error);
+ if (error)
+ {
+ expand_string_message = string_sprintf(
+ "error converting utf8 (%s) to alabel: %s",
+ string_printing(sub), error);
+ goto EXPAND_FAILED;
+ }
+ yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+ DEBUG(D_expand) debug_printf("yield: '%s'\n", yield);
+ continue;
+ }
+
+ case EOP_UTF8_LOCALPART_FROM_ALABEL:
+ {
+ uschar * error = NULL;
+ uschar * s = string_localpart_alabel_to_utf8(sub, &error);
+ if (error)
+ {
+ expand_string_message = string_sprintf(
+ "error converting alabel (%s) to utf8: %s",
+ string_printing(sub), error);
+ goto EXPAND_FAILED;
+ }
+ yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+ continue;
+ }
+#endif /* EXPERIMENTAL_INTERNATIONAL */
+
/* escape turns all non-printing characters into escape sequences. */
case EOP_ESCAPE:
diff --git a/src/src/filter.c b/src/src/filter.c
index 9ee7acbe0..a28e5f9f8 100644
--- a/src/src/filter.c
+++ b/src/src/filter.c
@@ -1821,7 +1821,7 @@ while (commands != NULL)
set in a system filter and to the local address in user filters. */
addr = deliver_make_addr(expargs[0], TRUE); /* TRUE => copy s */
- addr->p.errors_address = (s == NULL)?
+ addr->prop.errors_address = (s == NULL)?
s : string_copy(s); /* Default is NULL */
if (commands->noerror) setflag(addr, af_ignore_error);
addr->next = *generated;
diff --git a/src/src/functions.h b/src/src/functions.h
index 7195afa88..d1ada3844 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -412,12 +412,23 @@ extern BOOL string_format(uschar *, int, const char *, ...) ALMOST_PRINTF(3,4
extern uschar *string_format_size(int, uschar *);
extern int string_interpret_escape(const uschar **);
extern int string_is_ip_address(const uschar *, int *);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+extern BOOL string_is_utf8(const uschar *);
+#endif
extern uschar *string_log_address(address_item *, BOOL, BOOL);
extern uschar *string_nextinlist(const uschar **, int *, uschar *, int);
extern uschar *string_open_failed(int, const char *, ...) PRINTF_FUNCTION(2,3);
extern const uschar *string_printing2(const uschar *, BOOL);
extern uschar *string_split_message(uschar *);
extern uschar *string_unprinting(uschar *);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+extern uschar *string_address_alabel_to_utf8(const uschar *, uschar **);
+extern uschar *string_address_utf8_to_alabel(uschar *, uschar **, int *);
+extern uschar *string_domain_alabel_to_utf8(const uschar *, uschar **);
+extern uschar *string_domain_utf8_to_alabel(const uschar *, uschar **);
+extern uschar *string_localpart_alabel_to_utf8(const uschar *, uschar **);
+extern uschar *string_localpart_utf8_to_alabel(const uschar *, uschar **);
+#endif
extern BOOL string_vformat(uschar *, int, const char *, va_list);
extern int strcmpic(const uschar *, const uschar *);
extern int strncmpic(const uschar *, const uschar *, int);
diff --git a/src/src/globals.c b/src/src/globals.c
index b68ed7e5f..2bf4d0a02 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -175,6 +175,10 @@ BOOL prdr_requested = FALSE;
const pcre *regex_PRDR = NULL;
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+const pcre *regex_UTF8 = NULL;
+#endif
+
/* Input-reading functions for messages, so we can use special ones for
incoming TCP/IP. The defaults use stdin. We never need these for any
stand-alone tests. */
@@ -384,6 +388,9 @@ address_item address_defaults = {
#ifdef EXPERIMENTAL_SRS
NULL, /* srs_sender */
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ FALSE, /* utf8 */
+#endif
}
};
@@ -906,6 +913,9 @@ int message_linecount = 0;
BOOL message_logs = TRUE;
int message_size = 0;
uschar *message_size_limit = US"50M";
+#ifdef EXPERIMENTAL_INTERNATIONAL
+BOOL message_smtputf8 = FALSE;
+#endif
uschar message_subdir[2] = { 0, 0 };
uschar *message_reference = NULL;
@@ -1270,6 +1280,9 @@ int smtp_rlr_limit = 0;
int smtp_rlr_threshold = INT_MAX;
BOOL smtp_use_pipelining = FALSE;
BOOL smtp_use_size = FALSE;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+uschar *smtputf8_advertise_hosts = US"*"; /* overridden under test-harness */
+#endif
#ifdef WITH_CONTENT_SCAN
uschar *spamd_address = US"127.0.0.1 783";
diff --git a/src/src/globals.h b/src/src/globals.h
index 5c0022041..7cbf7bfab 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -570,6 +570,10 @@ extern int message_linecount; /* As it says */
extern BOOL message_logs; /* TRUE to write message logs */
extern int message_size; /* Size of message */
extern uschar *message_size_limit; /* As it says */
+#ifdef EXPERIMENTAL_INTERNATIONAL
+extern BOOL message_smtputf8; /* Internationalized mail handling */
+const extern pcre *regex_UTF8; /* For recognizing SMTPUTF8 settings */
+#endif
extern uschar message_subdir[]; /* Subdirectory for messages */
extern uschar *message_reference; /* Reference for error messages */
@@ -822,6 +826,9 @@ extern int smtp_rlr_limit; /* Max delay */
extern int smtp_rlr_threshold; /* Threshold for RCPT rate limit */
extern BOOL smtp_use_pipelining; /* Global for passed connections */
extern BOOL smtp_use_size; /* Global for passed connections */
+#ifdef EXPERIMENTAL_INTERNATIONAL
+extern uschar *smtputf8_advertise_hosts; /* ingress control */
+#endif
#ifdef WITH_CONTENT_SCAN
extern uschar *spamd_address; /* address for the spamassassin daemon */
diff --git a/src/src/macros.h b/src/src/macros.h
index 0f893e812..a8ab4f7ae 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -503,7 +503,11 @@ to conflict with system errno values. */
#define ERRNO_MAIL4XX (-45) /* MAIL gave 4xx error */
#define ERRNO_DATA4XX (-46) /* DATA gave 4xx error */
#define ERRNO_PROXYFAIL (-47) /* Negotiation failed for proxy configured host */
-#define ERRNO_AUTHPROB (-48) /* Autheticator "other" failure */
+#define ERRNO_AUTHPROB (-48) /* Authenticator "other" failure */
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+# define ERRNO_UTF8_FWD (-49) /* target not supporting SMTPUTF8 */
+#endif
/* These must be last, so all retry deferments can easily be identified */
diff --git a/src/src/parse.c b/src/src/parse.c
index ff814e738..9e57365be 100644
--- a/src/src/parse.c
+++ b/src/src/parse.c
@@ -550,9 +550,7 @@ read_addr_spec(uschar *s, uschar *t, int term, uschar **errorptr,
{
s = read_local_part(s, t, errorptr, FALSE);
if (*errorptr == NULL)
- {
if (*s != term)
- {
if (*s != '@')
*errorptr = string_sprintf("\"@\" or \".\" expected after \"%s\"", t);
else
@@ -562,8 +560,6 @@ if (*errorptr == NULL)
*domainptr = t;
s = read_domain(s, t, errorptr);
}
- }
- }
return s;
}
@@ -817,7 +813,7 @@ if (*end - *start > ADDRESS_MAXLENGTH)
return NULL;
}
-return (uschar *)yield;
+return yield;
/* Use goto (via the macro FAILED) to get to here from a variety of places.
We might have an empty address in a group - the caller can choose to ignore
diff --git a/src/src/queue.c b/src/src/queue.c
index ca6c47f44..5f7781c8e 100644
--- a/src/src/queue.c
+++ b/src/src/queue.c
@@ -1274,6 +1274,9 @@ switch(action)
{
if (action == MSG_ADD_RECIPIENT)
{
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE;
+#endif
receive_add_recipient(recipient, -1);
log_write(0, LOG_MAIN, "recipient <%s> added by %s",
recipient, username);
@@ -1297,6 +1300,9 @@ switch(action)
}
else /* MSG_EDIT_SENDER */
{
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE;
+#endif
sender_address = recipient;
log_write(0, LOG_MAIN, "sender address changed to <%s> by %s",
recipient, username);
diff --git a/src/src/rda.c b/src/src/rda.c
index 99c5513b2..3359275d6 100644
--- a/src/src/rda.c
+++ b/src/src/rda.c
@@ -723,7 +723,7 @@ if ((pid = fork()) == 0)
!= sizeof(addr->mode)
|| write(fd, &(addr->flags), sizeof(addr->flags))
!= sizeof(addr->flags)
- || rda_write_string(fd, addr->p.errors_address) != 0
+ || rda_write_string(fd, addr->prop.errors_address) != 0
)
goto bad;
@@ -892,7 +892,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
if (read(fd, &(addr->mode), sizeof(addr->mode)) != sizeof(addr->mode) ||
read(fd, &(addr->flags), sizeof(addr->flags)) != sizeof(addr->flags) ||
- !rda_read_string(fd, &(addr->p.errors_address))) goto DISASTER;
+ !rda_read_string(fd, &(addr->prop.errors_address))) goto DISASTER;
/* Next comes a possible setting for $thisaddress and any numerical
variables for pipe expansion, terminated by a NULL string. The maximum
diff --git a/src/src/readconf.c b/src/src/readconf.c
index e2d3c518f..67241cb36 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -398,6 +398,9 @@ static optionlist optionlist_config[] = {
{ "smtp_receive_timeout", opt_func, &fn_smtp_receive_timeout },
{ "smtp_reserve_hosts", opt_stringptr, &smtp_reserve_hosts },
{ "smtp_return_error_details",opt_bool, &smtp_return_error_details },
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ { "smtputf8_advertise_hosts", opt_stringptr, &smtputf8_advertise_hosts },
+#endif
#ifdef WITH_CONTENT_SCAN
{ "spamd_address", opt_stringptr, &spamd_address },
#endif
diff --git a/src/src/receive.c b/src/src/receive.c
index 0b3546317..7c56f47ba 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -2303,9 +2303,23 @@ if (extract_recip)
pp = recipient = store_get(ss - s + 1);
for (p = s; p < ss; p++) if (*p != '\n') *pp++ = *p;
*pp = 0;
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ {
+ BOOL b = allow_utf8_domains;
+ allow_utf8_domains = TRUE;
+#endif
recipient = parse_extract_address(recipient, &errmess, &start, &end,
&domain, FALSE);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if (string_is_utf8(recipient))
+ message_smtputf8 = TRUE;
+ else
+ allow_utf8_domains = b;
+ }
+#endif
+
/* Keep a list of all the bad addresses so we can send a single
error message at the end. However, an empty address is not an error;
just ignore it. This can come from an empty group list like
diff --git a/src/src/route.c b/src/src/route.c
index 764f0a140..ec188801c 100644
--- a/src/src/route.c
+++ b/src/src/route.c
@@ -1342,8 +1342,8 @@ from the original address' parent, if present, otherwise unset. */
*parent = *addr;
parent->child_count = 2;
-parent->p.errors_address =
- (addr->parent == NULL)? NULL : addr->parent->p.errors_address;
+parent->prop.errors_address =
+ (addr->parent == NULL)? NULL : addr->parent->prop.errors_address;
/* The routed address gets a new parent. */
@@ -1354,12 +1354,12 @@ was set from the original parent (or to NULL) - see above. We do NOT want to
take the errors address from the unseen router. */
new->parent = parent;
-new->p.errors_address = parent->p.errors_address;
+new->prop.errors_address = parent->prop.errors_address;
/* Copy the propagated flags and address_data from the original. */
copyflag(new, addr, af_propagate);
-new->p.address_data = addr->p.address_data;
+new->prop.address_data = addr->prop.address_data;
new->dsn_flags = addr->dsn_flags;
new->dsn_orcpt = addr->dsn_orcpt;
@@ -1645,7 +1645,7 @@ for (r = (addr->start_router == NULL)? routers : addr->start_router;
goto ROUTE_EXIT;
}
}
- addr->p.address_data = deliver_address_data;
+ addr->prop.address_data = deliver_address_data;
}
/* We are finally cleared for take-off with this router. Clear the the flag
@@ -1891,8 +1891,8 @@ DEBUG(D_route)
debug_printf(" transport: %s\n", (addr->transport == NULL)?
US"<none>" : addr->transport->name);
- if (addr->p.errors_address != NULL)
- debug_printf(" errors to %s\n", addr->p.errors_address);
+ if (addr->prop.errors_address != NULL)
+ debug_printf(" errors to %s\n", addr->prop.errors_address);
for (h = addr->host_list; h != NULL; h = h->next)
{
diff --git a/src/src/routers/accept.c b/src/src/routers/accept.c
index 8049eaffd..ef2a2854a 100644
--- a/src/src/routers/accept.c
+++ b/src/src/routers/accept.c
@@ -118,9 +118,9 @@ if (!rf_get_transport(rblock->transport_name, &(rblock->transport),
addr, rblock->name, NULL)) return DEFER;
addr->transport = rblock->transport;
-addr->p.errors_address = errors_to;
-addr->p.extra_headers = extra_headers;
-addr->p.remove_headers = remove_headers;
+addr->prop.errors_address = errors_to;
+addr->prop.extra_headers = extra_headers;
+addr->prop.remove_headers = remove_headers;
return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)? OK : DEFER;
}
diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c
index 8ef4e0da9..650e56d33 100644
--- a/src/src/routers/dnslookup.c
+++ b/src/src/routers/dnslookup.c
@@ -421,13 +421,13 @@ else if (ob->check_secondary_mx && !testflag(addr, af_local_host_removed))
/* Set up the errors address, if any. */
-rc = rf_get_errors_address(addr, rblock, verify, &(addr->p.errors_address));
+rc = rf_get_errors_address(addr, rblock, verify, &addr->prop.errors_address);
if (rc != OK) return rc;
/* Set up the additional and removeable headers for this address. */
-rc = rf_get_munge_headers(addr, rblock, &(addr->p.extra_headers),
- &(addr->p.remove_headers));
+rc = rf_get_munge_headers(addr, rblock, &addr->prop.extra_headers,
+ &addr->prop.remove_headers);
if (rc != OK) return rc;
/* Get store in which to preserve the original host item, chained on
diff --git a/src/src/routers/ipliteral.c b/src/src/routers/ipliteral.c
index e9c18658b..f9a8c0cac 100644
--- a/src/src/routers/ipliteral.c
+++ b/src/src/routers/ipliteral.c
@@ -165,13 +165,13 @@ addr->host_list = h;
/* Set up the errors address, if any. */
-rc = rf_get_errors_address(addr, rblock, verify, &(addr->p.errors_address));
+rc = rf_get_errors_address(addr, rblock, verify, &addr->prop.errors_address);
if (rc != OK) return rc;
/* Set up the additional and removeable headers for this address. */
-rc = rf_get_munge_headers(addr, rblock, &(addr->p.extra_headers),
- &(addr->p.remove_headers));
+rc = rf_get_munge_headers(addr, rblock, &addr->prop.extra_headers,
+ &addr->prop.remove_headers);
if (rc != OK) return rc;
/* Fill in the transport, queue the address for local or remote delivery, and
diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c
index d48cfb900..33329f887 100644
--- a/src/src/routers/iplookup.c
+++ b/src/src/routers/iplookup.c
@@ -377,7 +377,7 @@ new_addr = deliver_make_addr(reroute, TRUE);
new_addr->parent = addr;
copyflag(new_addr, addr, af_propagate);
-new_addr->p = addr->p;
+new_addr->prop = addr->prop;
if (addr->child_count == SHRT_MAX)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
@@ -389,11 +389,11 @@ new_addr->next = *addr_new;
/* Set up the errors address, if any, and the additional and removeable headers
for this new address. */
-rc = rf_get_errors_address(addr, rblock, verify, &(new_addr->p.errors_address));
+rc = rf_get_errors_address(addr, rblock, verify, &new_addr->prop.errors_address);
if (rc != OK) return rc;
-rc = rf_get_munge_headers(addr, rblock, &(new_addr->p.extra_headers),
- &(new_addr->p.remove_headers));
+rc = rf_get_munge_headers(addr, rblock, &new_addr->prop.extra_headers,
+ &new_addr->prop.remove_headers);
if (rc != OK) return rc;
return OK;
diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c
index 7cbe5db6c..add55de1e 100644
--- a/src/src/routers/manualroute.c
+++ b/src/src/routers/manualroute.c
@@ -358,13 +358,13 @@ while (*options != 0)
/* Set up the errors address, if any. */
-rc = rf_get_errors_address(addr, rblock, verify, &(addr->p.errors_address));
+rc = rf_get_errors_address(addr, rblock, verify, &addr->prop.errors_address);
if (rc != OK) return rc;
/* Set up the additional and removeable headers for this address. */
-rc = rf_get_munge_headers(addr, rblock, &(addr->p.extra_headers),
- &(addr->p.remove_headers));
+rc = rf_get_munge_headers(addr, rblock, &addr->prop.extra_headers,
+ &addr->prop.remove_headers);
if (rc != OK) return rc;
/* If an individual transport is not set, get the transport for this router, if
diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c
index bf0f4c43e..71f4915ab 100644
--- a/src/src/routers/queryprogram.c
+++ b/src/src/routers/queryprogram.c
@@ -114,7 +114,7 @@ while (generated != NULL)
next->parent = addr;
orflag(next, addr, af_propagate);
- next->p = *addr_prop;
+ next->prop = *addr_prop;
next->start_router = rblock->redirect_router;
next->next = *addr_new;
@@ -216,11 +216,11 @@ errors address and extra header stuff. */
addr_prop.address_data = deliver_address_data;
-rc = rf_get_errors_address(addr, rblock, verify, &(addr_prop.errors_address));
+rc = rf_get_errors_address(addr, rblock, verify, &addr_prop.errors_address);
if (rc != OK) return rc;
-rc = rf_get_munge_headers(addr, rblock, &(addr_prop.extra_headers),
- &(addr_prop.remove_headers));
+rc = rf_get_munge_headers(addr, rblock, &addr_prop.extra_headers,
+ &addr_prop.remove_headers);
if (rc != OK) return rc;
/* Get the fixed or expanded uid under which the command is to run
@@ -526,7 +526,7 @@ lookup_value = NULL;
/* Put the errors address, extra headers, and address_data into this address */
-addr->p = addr_prop;
+addr->prop = addr_prop;
/* Queue the address for local or remote delivery. */
diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c
index 0189d237a..8f1c2c3d2 100644
--- a/src/src/routers/redirect.c
+++ b/src/src/routers/redirect.c
@@ -277,11 +277,11 @@ sort_errors_and_headers(router_instance *rblock, address_item *addr,
int verify, address_item_propagated *addr_prop)
{
int frc = rf_get_errors_address(addr, rblock, verify,
- &(addr_prop->errors_address));
+ &addr_prop->errors_address);
if (frc != OK) return frc;
-addr->p.errors_address = addr_prop->errors_address;
-return rf_get_munge_headers(addr, rblock, &(addr_prop->extra_headers),
- &(addr_prop->remove_headers));
+addr->prop.errors_address = addr_prop->errors_address;
+return rf_get_munge_headers(addr, rblock, &addr_prop->extra_headers,
+ &addr_prop->remove_headers);
}
@@ -329,7 +329,7 @@ while (generated != NULL)
{
address_item *parent;
address_item *next = generated;
- uschar *errors_address = next->p.errors_address;
+ uschar *errors_address = next->prop.errors_address;
generated = next->next;
next->parent = addr;
@@ -378,8 +378,8 @@ while (generated != NULL)
If so, we must take care to re-instate it when we copy in the propagated
data so that it overrides any errors_to setting on the router. */
- next->p = *addr_prop;
- if (errors_address != NULL) next->p.errors_address = errors_address;
+ next->prop = *addr_prop;
+ if (errors_address != NULL) next->prop.errors_address = errors_address;
/* For pipes, files, and autoreplies, record this router as handling them,
because they don't go through the routing process again. Then set up uid,
@@ -451,13 +451,18 @@ while (generated != NULL)
}
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ next->prop.utf8 = string_is_utf8(next->address)
+ || (sender_address && string_is_utf8(sender_address));
+#endif
+
DEBUG(D_route)
{
debug_printf("%s router generated %s\n %serrors_to=%s transport=%s\n",
rblock->name,
next->address,
testflag(next, af_pfr)? "pipe, file, or autoreply\n " : "",
- next->p.errors_address,
+ next->prop.errors_address,
(next->transport == NULL)? US"NULL" : next->transport->name);
if (testflag(next, af_uid_set))
@@ -470,6 +475,10 @@ while (generated != NULL)
else
debug_printf("gid=unset ");
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if (next->prop.utf8) debug_printf("utf8 ");
+#endif
+
debug_printf("home=%s\n", next->home_dir);
}
}
@@ -891,7 +900,7 @@ else
data that propagates. */
copyflag(next, addr, af_propagate);
- next->p = addr_prop;
+ next->prop = addr_prop;
DEBUG(D_route) debug_printf("%s router autogenerated %s\n%s%s%s",
rblock->name,
diff --git a/src/src/routers/rf_change_domain.c b/src/src/routers/rf_change_domain.c
index e891b84b2..049e6ab8c 100644
--- a/src/src/routers/rf_change_domain.c
+++ b/src/src/routers/rf_change_domain.c
@@ -52,7 +52,7 @@ domain cache. Then copy over the propagating fields from the parent. Then set
up the new fields. */
*addr = address_defaults;
-addr->p = parent->p;
+addr->prop = parent->prop;
addr->address = address;
addr->unique = string_copy(address);
diff --git a/src/src/routers/rf_get_errors_address.c b/src/src/routers/rf_get_errors_address.c
index a0ea9f2ff..f52059427 100644
--- a/src/src/routers/rf_get_errors_address.c
+++ b/src/src/routers/rf_get_errors_address.c
@@ -38,7 +38,7 @@ rf_get_errors_address(address_item *addr, router_instance *rblock,
{
uschar *s;
-*errors_to = addr->p.errors_address;
+*errors_to = addr->prop.errors_address;
if (rblock->errors_to == NULL) return OK;
s = expand_string(rblock->errors_to);
diff --git a/src/src/routers/rf_get_munge_headers.c b/src/src/routers/rf_get_munge_headers.c
index a6c039eb3..d4af84f6d 100644
--- a/src/src/routers/rf_get_munge_headers.c
+++ b/src/src/routers/rf_get_munge_headers.c
@@ -32,7 +32,7 @@ rf_get_munge_headers(address_item *addr, router_instance *rblock,
header_line **extra_headers, uschar **remove_headers)
{
/* Default is to retain existing headers */
-*extra_headers = addr->p.extra_headers;
+*extra_headers = addr->prop.extra_headers;
if (rblock->extra_headers)
{
@@ -82,7 +82,7 @@ if (rblock->extra_headers)
}
/* Default is to retain existing removes */
-*remove_headers = addr->p.remove_headers;
+*remove_headers = addr->prop.remove_headers;
/* Expand items from colon-sep list separately, then build new list */
if (rblock->remove_headers)
diff --git a/src/src/routers/rf_queue_add.c b/src/src/routers/rf_queue_add.c
index 06cdb6c6d..273780f2e 100644
--- a/src/src/routers/rf_queue_add.c
+++ b/src/src/routers/rf_queue_add.c
@@ -36,8 +36,8 @@ BOOL
rf_queue_add(address_item *addr, address_item **paddr_local,
address_item **paddr_remote, router_instance *rblock, struct passwd *pw)
{
-addr->p.domain_data = deliver_domain_data; /* Save these values for */
-addr->p.localpart_data = deliver_localpart_data; /* use in the transport */
+addr->prop.domain_data = deliver_domain_data; /* Save these values for */
+addr->prop.localpart_data = deliver_localpart_data; /* use in the transport */
/* Handle a local transport */
@@ -95,9 +95,9 @@ DEBUG(D_route)
debug_printf("queued for %s transport: local_part = %s\ndomain = %s\n"
" errors_to=%s\n",
(addr->transport == NULL)? US"<unset>" : addr->transport->name,
- addr->local_part, addr->domain, addr->p.errors_address);
- debug_printf(" domain_data=%s localpart_data=%s\n", addr->p.domain_data,
- addr->p.localpart_data);
+ addr->local_part, addr->domain, addr->prop.errors_address);
+ debug_printf(" domain_data=%s localpart_data=%s\n", addr->prop.domain_data,
+ addr->prop.localpart_data);
}
return TRUE;
diff --git a/src/src/sieve.c b/src/src/sieve.c
index 262367ef2..7653993da 100644
--- a/src/src/sieve.c
+++ b/src/src/sieve.c
@@ -1072,7 +1072,7 @@ if (file)
setflag(new_addr, af_pfr|af_file);
new_addr->mode = 0;
}
-new_addr->p.errors_address = NULL;
+new_addr->prop.errors_address = NULL;
new_addr->next = *generated;
*generated = new_addr;
}
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index 9b7c59d62..9fa2ae6ed 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -133,6 +133,9 @@ static BOOL rcpt_smtp_response_same;
static BOOL rcpt_in_progress;
static int nonmail_command_count;
static BOOL smtp_exit_function_called = 0;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+static BOOL smtputf8_advertised;
+#endif
static int synprot_error_count;
static int unknown_command_count;
static int sync_cmd_limit;
@@ -158,6 +161,8 @@ QUIT is also "falsely" labelled as a mail command so that it doesn't up the
count of non-mail commands and possibly provoke an error. */
static smtp_cmd_list cmd_list[] = {
+ /* name len cmd has_arg is_mail_cmd */
+
{ "rset", sizeof("rset")-1, RSET_CMD, FALSE, FALSE }, /* First */
{ "helo", sizeof("helo")-1, HELO_CMD, TRUE, FALSE },
{ "ehlo", sizeof("ehlo")-1, EHLO_CMD, TRUE, FALSE },
@@ -197,7 +202,7 @@ static uschar *smtp_names[] =
US"HELP", US"MAIL", US"NOOP", US"QUIT", US"RCPT", US"RSET", US"STARTTLS",
US"VRFY" };
-static uschar *protocols[] = {
+static uschar *protocols_local[] = {
US"local-smtp", /* HELO */
US"local-smtps", /* The rare case EHLO->STARTTLS->HELO */
US"local-esmtp", /* EHLO */
@@ -205,12 +210,19 @@ static uschar *protocols[] = {
US"local-esmtpa", /* EHLO->AUTH */
US"local-esmtpsa" /* EHLO->STARTTLS->EHLO->AUTH */
};
+static uschar *protocols[] = {
+ US"smtp", /* HELO */
+ US"smtps", /* The rare case EHLO->STARTTLS->HELO */
+ US"esmtp", /* EHLO */
+ US"esmtps", /* EHLO->STARTTLS->EHLO */
+ US"esmtpa", /* EHLO->AUTH */
+ US"esmtpsa" /* EHLO->STARTTLS->EHLO->AUTH */
+ };
#define pnormal 0
#define pextend 2
#define pcrpted 1 /* added to pextend or pnormal */
#define pauthed 2 /* added to pextend */
-#define pnlocal 6 /* offset to remove "local" */
/* Sanity check and validate optional args to MAIL FROM: envelope */
enum {
@@ -219,6 +231,9 @@ enum {
ENV_MAIL_OPT_PRDR,
#endif
ENV_MAIL_OPT_RET, ENV_MAIL_OPT_ENVID,
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ ENV_MAIL_OPT_UTF8,
+#endif
ENV_MAIL_OPT_NULL
};
typedef struct {
@@ -236,6 +251,9 @@ static env_mail_type_t env_mail_type_list[] = {
#endif
{ US"RET", ENV_MAIL_OPT_RET, TRUE },
{ US"ENVID", ENV_MAIL_OPT_ENVID, TRUE },
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ { US"SMTPUTF8",ENV_MAIL_OPT_UTF8, FALSE }, /* rfc6531 */
+#endif
{ US"NULL", ENV_MAIL_OPT_NULL, FALSE }
};
@@ -1494,6 +1512,8 @@ sender_verified_list = NULL; /* No senders verified */
memset(sender_address_cache, 0, sizeof(sender_address_cache));
memset(sender_domain_cache, 0, sizeof(sender_domain_cache));
+prdr_requested = FALSE;
+
/* Reset the DSN flags */
dsn_ret = 0;
dsn_envid = NULL;
@@ -1514,6 +1534,9 @@ spf_received = NULL;
spf_result = NULL;
spf_smtp_comment = NULL;
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+message_smtputf8 = FALSE;
+#endif
body_linecount = body_zerocount = 0;
sender_rate = sender_rate_limit = sender_rate_period = NULL;
@@ -1848,6 +1871,9 @@ tls_in.ocsp = OCSP_NOT_REQ;
tls_advertised = FALSE;
#endif
dsn_advertised = FALSE;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+smtputf8_advertised = FALSE;
+#endif
/* Reset ACL connection variables */
@@ -1875,7 +1901,7 @@ reset later if any of EHLO/AUTH/STARTTLS are received. */
else
received_protocol =
- protocols[pnormal] + ((sender_host_address != NULL)? pnlocal : 0);
+ (sender_host_address ? protocols : protocols_local) [pnormal];
/* Set up the buffer for inputting using direct read() calls, and arrange to
call the local functions instead of the standard C ones. */
@@ -3295,9 +3321,10 @@ while (done <= 0)
sender_host_authenticated = au->name;
authentication_failed = FALSE;
authenticated_fail_id = NULL; /* Impossible to already be set? */
+
received_protocol =
- protocols[pextend + pauthed + ((tls_in.active >= 0)? pcrpted:0)] +
- ((sender_host_address != NULL)? pnlocal : 0);
+ (sender_host_address ? protocols : protocols_local)
+ [pextend + pauthed + (tls_in.active >= 0 ? pcrpted:0)];
s = ss = US"235 Authentication succeeded";
authenticated_by = au;
break;
@@ -3493,10 +3520,13 @@ while (done <= 0)
auth_advertised = FALSE;
pipelining_advertised = FALSE;
- #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
tls_advertised = FALSE;
- #endif
+#endif
dsn_advertised = FALSE;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ smtputf8_advertised = FALSE;
+#endif
smtp_code = US"250 "; /* Default response code plus space*/
if (user_msg == NULL)
@@ -3667,7 +3697,7 @@ while (done <= 0)
tls_advertise_hosts. We must *not* advertise if we are already in a
secure connection. */
- #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
if (tls_in.active < 0 &&
verify_check_host(&tls_advertise_hosts) != FAIL)
{
@@ -3675,16 +3705,26 @@ while (done <= 0)
s = string_cat(s, &size, &ptr, US"-STARTTLS\r\n", 11);
tls_advertised = TRUE;
}
- #endif
+#endif
- #ifndef DISABLE_PRDR
+#ifndef DISABLE_PRDR
/* Per Recipient Data Response, draft by Eric A. Hall extending RFC */
if (prdr_enable)
{
s = string_cat(s, &size, &ptr, smtp_code, 3);
s = string_cat(s, &size, &ptr, US"-PRDR\r\n", 7);
}
- #endif
+#endif
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if ( accept_8bitmime
+ && verify_check_host(&smtputf8_advertise_hosts) != FAIL)
+ {
+ s = string_cat(s, &size, &ptr, smtp_code, 3);
+ s = string_cat(s, &size, &ptr, US"-SMTPUTF8\r\n", 11);
+ smtputf8_advertised = TRUE;
+ }
+#endif
/* Finish off the multiline reply with one that is always available. */
@@ -3697,9 +3737,9 @@ while (done <= 0)
s[ptr] = 0;
- #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
if (tls_in.active >= 0) (void)tls_write(TRUE, s, ptr); else
- #endif
+#endif
{
int i = fwrite(s, 1, ptr, smtp_out); i = i; /* compiler quietening */
@@ -3714,16 +3754,13 @@ while (done <= 0)
helo_seen = TRUE;
/* Reset the protocol and the state, abandoning any previous message. */
-
- received_protocol = (esmtp?
- protocols[pextend +
- ((sender_host_authenticated != NULL)? pauthed : 0) +
- ((tls_in.active >= 0)? pcrpted : 0)]
- :
- protocols[pnormal + ((tls_in.active >= 0)? pcrpted : 0)])
- +
- ((sender_host_address != NULL)? pnlocal : 0);
-
+ received_protocol =
+ (sender_host_address ? protocols : protocols_local)
+ [ (esmtp
+ ? pextend + (sender_host_authenticated ? pauthed : 0)
+ : pnormal)
+ + (tls_in.active >= 0 ? pcrpted : 0)
+ ];
smtp_reset(reset_point);
toomany = FALSE;
break; /* HELO/EHLO */
@@ -3796,10 +3833,8 @@ while (done <= 0)
(char *)mail_args < (char *)env_mail_type_list + sizeof(env_mail_type_list);
mail_args++
)
- {
if (strcmpic(name, mail_args->name) == 0)
break;
- }
if (mail_args->need_value && strcmpic(value, US"") == 0)
break;
@@ -3827,16 +3862,17 @@ while (done <= 0)
and "7BIT" as body types, but take no action. */
case ENV_MAIL_OPT_BODY:
if (accept_8bitmime) {
- if (strcmpic(value, US"8BITMIME") == 0) {
+ if (strcmpic(value, US"8BITMIME") == 0)
body_8bitmime = 8;
- } else if (strcmpic(value, US"7BIT") == 0) {
+ else if (strcmpic(value, US"7BIT") == 0)
body_8bitmime = 7;
- } else {
+ else
+ {
body_8bitmime = 0;
done = synprot_error(L_smtp_syntax_error, 501, NULL,
US"invalid data for BODY");
goto COMMAND_LOOP;
- }
+ }
DEBUG(D_receive) debug_printf("8BITMIME: %d\n", body_8bitmime);
break;
}
@@ -3848,35 +3884,43 @@ while (done <= 0)
is included only if configured in at build time. */
case ENV_MAIL_OPT_RET:
- if (dsn_advertised) {
+ if (dsn_advertised)
+ {
/* Check if RET has already been set */
- if (dsn_ret > 0) {
+ if (dsn_ret > 0)
+ {
synprot_error(L_smtp_syntax_error, 501, NULL,
US"RET can be specified once only");
goto COMMAND_LOOP;
- }
- dsn_ret = (strcmpic(value, US"HDRS") == 0)? dsn_ret_hdrs :
- (strcmpic(value, US"FULL") == 0)? dsn_ret_full : 0;
+ }
+ dsn_ret = strcmpic(value, US"HDRS") == 0
+ ? dsn_ret_hdrs
+ : strcmpic(value, US"FULL") == 0
+ ? dsn_ret_full
+ : 0;
DEBUG(D_receive) debug_printf("DSN_RET: %d\n", dsn_ret);
/* Check for invalid invalid value, and exit with error */
- if (dsn_ret == 0) {
+ if (dsn_ret == 0)
+ {
synprot_error(L_smtp_syntax_error, 501, NULL,
US"Value for RET is invalid");
goto COMMAND_LOOP;
- }
- }
+ }
+ }
break;
case ENV_MAIL_OPT_ENVID:
- if (dsn_advertised) {
+ if (dsn_advertised)
+ {
/* Check if the dsn envid has been already set */
- if (dsn_envid != NULL) {
+ if (dsn_envid != NULL)
+ {
synprot_error(L_smtp_syntax_error, 501, NULL,
US"ENVID can be specified once only");
goto COMMAND_LOOP;
- }
+ }
dsn_envid = string_copy(value);
DEBUG(D_receive) debug_printf("DSN_ENVID: %s\n", dsn_envid);
- }
+ }
break;
/* Handle the AUTH extension. If the value given is not "<>" and either
@@ -3916,34 +3960,34 @@ while (done <= 0)
switch (rc)
{
case OK:
- if (authenticated_by == NULL ||
- authenticated_by->mail_auth_condition == NULL ||
- expand_check_condition(authenticated_by->mail_auth_condition,
- authenticated_by->name, US"authenticator"))
- break; /* Accept the AUTH */
-
- ignore_msg = US"server_mail_auth_condition failed";
- if (authenticated_id != NULL)
- ignore_msg = string_sprintf("%s: authenticated ID=\"%s\"",
- ignore_msg, authenticated_id);
+ if (authenticated_by == NULL ||
+ authenticated_by->mail_auth_condition == NULL ||
+ expand_check_condition(authenticated_by->mail_auth_condition,
+ authenticated_by->name, US"authenticator"))
+ break; /* Accept the AUTH */
+
+ ignore_msg = US"server_mail_auth_condition failed";
+ if (authenticated_id != NULL)
+ ignore_msg = string_sprintf("%s: authenticated ID=\"%s\"",
+ ignore_msg, authenticated_id);
/* Fall through */
case FAIL:
- authenticated_sender = NULL;
- log_write(0, LOG_MAIN, "ignoring AUTH=%s from %s (%s)",
- value, host_and_ident(TRUE), ignore_msg);
- break;
+ authenticated_sender = NULL;
+ log_write(0, LOG_MAIN, "ignoring AUTH=%s from %s (%s)",
+ value, host_and_ident(TRUE), ignore_msg);
+ break;
/* Should only get DEFER or ERROR here. Put back terminator
overrides for error message */
default:
- value[-1] = '=';
- name[-1] = ' ';
- (void)smtp_handle_acl_fail(ACL_WHERE_MAILAUTH, rc, user_msg,
- log_msg);
- goto COMMAND_LOOP;
+ value[-1] = '=';
+ name[-1] = ' ';
+ (void)smtp_handle_acl_fail(ACL_WHERE_MAILAUTH, rc, user_msg,
+ log_msg);
+ goto COMMAND_LOOP;
}
}
break;
@@ -3955,6 +3999,16 @@ while (done <= 0)
break;
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ case ENV_MAIL_OPT_UTF8:
+ if (smtputf8_advertised)
+ {
+ DEBUG(D_receive) debug_printf("smtputf8 requested\n");
+ message_smtputf8 = allow_utf8_domains = TRUE;
+ received_protocol = string_sprintf("utf8%s", received_protocol);
+ }
+ break;
+#endif
/* Unknown option. Stick back the terminator characters and break
the loop. Do the name-terminator second as extract_option sets
value==name when it found no equal-sign.
@@ -3987,9 +4041,10 @@ while (done <= 0)
/* Now extract the address, first applying any SMTP-time rewriting. The
TRUE flag allows "<>" as a sender address. */
- raw_sender = ((rewrite_existflags & rewrite_smtp) != 0)?
- rewrite_one(smtp_cmd_data, rewrite_smtp, NULL, FALSE, US"",
- global_rewrite_rules) : smtp_cmd_data;
+ raw_sender = rewrite_existflags & rewrite_smtp
+ ? rewrite_one(smtp_cmd_data, rewrite_smtp, NULL, FALSE, US"",
+ global_rewrite_rules)
+ : smtp_cmd_data;
/* rfc821_domains = TRUE; << no longer needed */
raw_sender =
@@ -4354,16 +4409,12 @@ while (done <= 0)
receive_add_recipient(recipient, -1);
/* Set the dsn flags in the recipients_list */
- if (orcpt != NULL)
- recipients_list[recipients_count-1].orcpt = orcpt;
- else
- recipients_list[recipients_count-1].orcpt = NULL;
+ recipients_list[recipients_count-1].orcpt = orcpt;
+ recipients_list[recipients_count-1].dsn_flags = flags;
- if (flags != 0)
- recipients_list[recipients_count-1].dsn_flags = flags;
- else
- recipients_list[recipients_count-1].dsn_flags = 0;
- DEBUG(D_receive) debug_printf("DSN: orcpt: %s flags: %d\n", recipients_list[recipients_count-1].orcpt, recipients_list[recipients_count-1].dsn_flags);
+ DEBUG(D_receive) debug_printf("DSN: orcpt: %s flags: %d\n",
+ recipients_list[recipients_count-1].orcpt,
+ recipients_list[recipients_count-1].dsn_flags);
}
/* The recipient was discarded */
@@ -4624,13 +4675,13 @@ while (done <= 0)
set_process_info("handling incoming TLS connection from %s",
host_and_ident(FALSE));
}
- received_protocol = (esmtp?
- protocols[pextend + pcrpted +
- ((sender_host_authenticated != NULL)? pauthed : 0)]
- :
- protocols[pnormal + pcrpted])
- +
- ((sender_host_address != NULL)? pnlocal : 0);
+ received_protocol =
+ (sender_host_address ? protocols : protocols_local)
+ [ (esmtp
+ ? pextend + (sender_host_authenticated ? pauthed : 0)
+ : pnormal)
+ + (tls_in.active >= 0 ? pcrpted : 0)
+ ];
sender_host_authenticated = NULL;
authenticated_id = NULL;
diff --git a/src/src/spool_in.c b/src/src/spool_in.c
index 79970cb40..742f4b579 100644
--- a/src/src/spool_in.c
+++ b/src/src/spool_in.c
@@ -299,6 +299,10 @@ tls_in.ocsp = OCSP_NOT_REQ;
spam_score_int = NULL;
#endif
+#if defined(EXPERIMENTAL_INTERNATIONAL) && !defined(COMPILE_UTILITY)
+message_smtputf8 = FALSE;
+#endif
+
dsn_ret = 0;
dsn_envid = NULL;
@@ -569,6 +573,10 @@ for (;;)
else if (Ustrncmp(p, "pam_score_int ", 14) == 0)
spam_score_int = string_copy(big_buffer + 16);
#endif
+#if defined(EXPERIMENTAL_INTERNATIONAL) && !defined(COMPILE_UTILITY)
+ else if (Ustrncmp(p, "mtputf8", 7) == 0)
+ message_smtputf8 = TRUE;
+#endif
break;
#ifdef SUPPORT_TLS
diff --git a/src/src/spool_out.c b/src/src/spool_out.c
index fc56057c1..6d22bff2c 100644
--- a/src/src/spool_out.c
+++ b/src/src/spool_out.c
@@ -245,6 +245,10 @@ if (tls_in.ourcert)
if (tls_in.ocsp) fprintf(f, "-tls_ocsp %d\n", tls_in.ocsp);
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+if (message_smtputf8) fprintf(f, "-smtputf8\n");
+#endif
+
/* Write the dsn flags to the spool header file */
DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid);
if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid);
diff --git a/src/src/structs.h b/src/src/structs.h
index 6ec52e1ec..99d65cfae 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -459,6 +459,9 @@ typedef struct address_item_propagated {
#ifdef EXPERIMENTAL_SRS
uschar *srs_sender; /* Change return path when delivering */
#endif
+ #ifdef EXPERIMENTAL_INTERNATIONAL
+ BOOL utf8; /* requires SMTPUTF8 processing */
+ #endif
} address_item_propagated;
/* Bits for the flags field below */
@@ -581,7 +584,7 @@ typedef struct address_item {
/* ( also */
/* ( contains verify rc in sender verify cache */
short int transport_return; /* result of delivery attempt */
- address_item_propagated p; /* fields that are propagated to children */
+ address_item_propagated prop; /* fields that are propagated to children */
} address_item;
/* The table of header names consists of items of this type */
diff --git a/src/src/transport.c b/src/src/transport.c
index c76873698..78d9d517f 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -628,7 +628,7 @@ 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. It is a colon-sep list; expand the items
separately and squash any empty ones.
-Then check addr->p.remove_headers too, provided that addr is not NULL. */
+Then check addr->prop.remove_headers too, provided that addr is not NULL. */
for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old)
{
@@ -637,7 +637,7 @@ for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old)
BOOL include_header = TRUE;
- for (i = 0; i < 2; i++) /* For remove_headers && addr->p.remove_headers */
+ for (i = 0; i < 2; i++) /* For remove_headers && addr->prop.remove_headers */
{
if (list)
{
@@ -661,7 +661,7 @@ for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old)
}
if (s != NULL) { include_header = FALSE; break; }
}
- if (addr != NULL) list = addr->p.remove_headers;
+ if (addr != NULL) list = addr->prop.remove_headers;
}
/* If this header is to be output, try to rewrite it if there are rewriting
@@ -709,7 +709,7 @@ 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 *hprev = addr->prop.extra_headers;
header_line *hnext;
for (i = 0; i < 2; i++)
{
@@ -914,7 +914,7 @@ if ((options & topt_no_headers) == 0)
/* 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
+ match any entries therein. Then check addr->prop.remove_headers too, provided that
addr is not NULL. */
if (!transport_headers_send(addr, fd, add_headers, remove_headers, &write_chunk,
use_crlf, rewrite_rules, rewrite_existflags))
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index b0fe177e9..65bb1de22 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -570,6 +570,16 @@ if (*errno_value == ERRNO_WRITEINCOMPLETE)
return FALSE;
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+/* Handle lack of advertised SMTPUTF8, for international message */
+if (*errno_value == ERRNO_UTF8_FWD)
+ {
+ *message = US string_sprintf("utf8 support required but not offered for forwarding");
+ DEBUG(D_deliver|D_transport) debug_printf("%s\n", *message);
+ return TRUE;
+ }
+#endif
+
/* Handle error responses from the remote mailer. */
if (buffer[0] != 0)
@@ -1355,6 +1365,9 @@ BOOL pass_message = FALSE;
BOOL prdr_offered = FALSE;
BOOL prdr_active;
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+BOOL utf8_offered = FALSE;
+#endif
BOOL dsn_all_lasthop = TRUE;
#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
BOOL dane = FALSE;
@@ -1473,6 +1486,19 @@ if (continue_hostname == NULL)
delayed till here so that $sending_interface and $sending_port are set. */
helo_data = expand_string(ob->helo_data);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if (helo_data)
+ {
+ uschar * errstr = NULL;
+ 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);
+ yield = DEFER;
+ goto SEND_QUIT;
+ }
+ }
+#endif
/* The first thing is to wait for an initial OK response. The dreaded "goto"
is nevertheless a reasonably clean way of programming this kind of logic,
@@ -1614,6 +1640,13 @@ goto SEND_QUIT;
if (prdr_offered)
{DEBUG(D_transport) debug_printf("PRDR usable\n");}
#endif
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ utf8_offered = esmtp
+ && addrlist->prop.utf8
+ && pcre_exec(regex_UTF8, NULL, CS buffer, Ustrlen(buffer), 0,
+ PCRE_EOPT, NULL, 0) >= 0;
+#endif
}
/* For continuing deliveries down the same channel, the socket is the standard
@@ -1821,16 +1854,24 @@ if (continue_hostname == NULL
#ifndef DISABLE_PRDR
prdr_offered = esmtp
&& pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(CS buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0
+ PCRE_EOPT, NULL, 0) >= 0
&& verify_check_given_host(&ob->hosts_try_prdr, host) == OK;
if (prdr_offered)
{DEBUG(D_transport) debug_printf("PRDR usable\n");}
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ utf8_offered = esmtp
+ && addrlist->prop.utf8
+ && pcre_exec(regex_UTF8, NULL, CS buffer, Ustrlen(buffer), 0,
+ PCRE_EOPT, NULL, 0) >= 0;
+#endif
+
/* Note if the server supports DSN */
- smtp_use_dsn = esmtp && pcre_exec(regex_DSN, NULL, CS buffer, (int)Ustrlen(CS buffer), 0,
- PCRE_EOPT, NULL, 0) >= 0;
+ smtp_use_dsn = esmtp
+ && pcre_exec(regex_DSN, NULL, CS buffer, Ustrlen(CS buffer), 0,
+ PCRE_EOPT, NULL, 0) >= 0;
DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn);
/* Note if the response to EHLO specifies support for the AUTH extension.
@@ -1853,6 +1894,15 @@ message-specific. */
setting_up = FALSE;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+/* If this is an international message we need the host to speak SMTPUTF8 */
+if (addrlist->prop.utf8 && !utf8_offered)
+ {
+ errno = ERRNO_UTF8_FWD;
+ goto RESPONSE_FAILED;
+ }
+#endif
+
/* If there is a filter command specified for this transport, we can now
set it up. This cannot be done until the identify of the host is known. */
@@ -1929,18 +1979,25 @@ if (prdr_offered)
}
#endif
+#ifdef EXPERIMENTAL_INTERNATIONAL
+if (addrlist->prop.utf8)
+ sprintf(CS p, " SMTPUTF8"), p += 9;
+#endif
+
/* check if all addresses have lasthop flag */
/* do not send RET and ENVID if true */
-dsn_all_lasthop = TRUE;
-for (addr = first_addr;
+for (dsn_all_lasthop = TRUE, addr = first_addr;
address_count < max_rcpt && addr != NULL;
addr = addr->next)
if ((addr->dsn_flags & rf_dsnlasthop) != 1)
+ {
dsn_all_lasthop = FALSE;
+ break;
+ }
/* Add any DSN flags to the mail command */
-if ((smtp_use_dsn) && (dsn_all_lasthop == FALSE))
+if (smtp_use_dsn && !dsn_all_lasthop)
{
if (dsn_ret == dsn_ret_hdrs)
{
@@ -1981,27 +2038,27 @@ buffer. */
pending_MAIL = TRUE; /* The block starts with MAIL */
rc = smtp_write_command(&outblock, smtp_use_pipelining,
- "MAIL FROM:<%s>%s\r\n", return_path, buffer);
+ "MAIL FROM:<%s>%s\r\n", return_path, buffer);
mail_command = string_copy(big_buffer); /* Save for later error message */
switch(rc)
{
case -1: /* Transmission error */
- goto SEND_FAILED;
+ goto SEND_FAILED;
case +1: /* Block was sent */
- if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
+ if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
ob->command_timeout))
- {
- if (errno == 0 && buffer[0] == '4')
{
- errno = ERRNO_MAIL4XX;
- addrlist->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
+ if (errno == 0 && buffer[0] == '4')
+ {
+ errno = ERRNO_MAIL4XX;
+ addrlist->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
+ }
+ goto RESPONSE_FAILED;
}
- goto RESPONSE_FAILED;
- }
- pending_MAIL = FALSE;
- break;
+ pending_MAIL = FALSE;
+ break;
}
/* Pass over all the relevant recipient addresses for this host, which are the
@@ -2490,24 +2547,29 @@ if (!ok)
switch(save_errno)
{
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ case ERRNO_UTF8_FWD:
+ code = '5';
+ /*FALLTHROUGH*/
+#endif
case 0:
case ERRNO_MAIL4XX:
case ERRNO_DATA4XX:
- message_error = TRUE;
- break;
+ message_error = TRUE;
+ break;
case ETIMEDOUT:
- message_error = Ustrncmp(smtp_command,"MAIL",4) == 0 ||
- Ustrncmp(smtp_command,"end ",4) == 0;
- break;
+ message_error = Ustrncmp(smtp_command,"MAIL",4) == 0 ||
+ Ustrncmp(smtp_command,"end ",4) == 0;
+ break;
case ERRNO_SMTPCLOSED:
- message_error = Ustrncmp(smtp_command,"end ",4) == 0;
- break;
+ message_error = Ustrncmp(smtp_command,"end ",4) == 0;
+ break;
default:
- message_error = FALSE;
- break;
+ message_error = FALSE;
+ break;
}
/* Handle the cases that are treated as message errors. These are:
@@ -2515,6 +2577,7 @@ if (!ok)
(a) negative response or timeout after MAIL
(b) negative response after DATA
(c) negative response or timeout or dropped connection after "."
+ (d) utf8 support required and not offered
It won't be a negative response or timeout after RCPT, as that is dealt
with separately above. The action in all cases is to set an appropriate
diff --git a/src/src/utf8.c b/src/src/utf8.c
new file mode 100644
index 000000000..6bc0c2ed5
--- /dev/null
+++ b/src/src/utf8.c
@@ -0,0 +1,152 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2015 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+
+#include "exim.h"
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+
+#include <idna.h>
+#include <punycode.h>
+#include <stringprep.h>
+
+BOOL
+string_is_utf8(const uschar * s)
+{
+uschar c;
+while ((c = *s++)) if (c & 0x80) return TRUE;
+return FALSE;
+}
+
+/**************************************************/
+/* Domain conversions */
+
+uschar *
+string_domain_utf8_to_alabel(const uschar * utf8, uschar ** err)
+{
+uschar * s1;
+uschar * s;
+int rc;
+
+s = US stringprep_utf8_nfkc_normalize(CCS utf8, -1);
+if ( (rc = idna_to_ascii_8z(CCS s, CSS &s1, IDNA_ALLOW_UNASSIGNED))
+ != IDNA_SUCCESS)
+ {
+ free(s);
+ if (err) *err = US idna_strerror(rc);
+ return NULL;
+ }
+free(s);
+s = string_copy(s1);
+free(s1);
+return s;
+}
+
+
+
+uschar *
+string_domain_alabel_to_utf8(const uschar * alabel, uschar ** err)
+{
+uschar * s1;
+uschar * s;
+int rc;
+
+if ( (rc = idna_to_unicode_8z8z(CCS alabel, CSS &s1, IDNA_USE_STD3_ASCII_RULES))
+ != IDNA_SUCCESS)
+ {
+ if (err) *err = US idna_strerror(rc);
+ return NULL;
+ }
+s = string_copy(s1);
+free(s1);
+return s;
+}
+
+/**************************************************/
+/* localpart conversions */
+
+
+uschar *
+string_localpart_utf8_to_alabel(const uschar * utf8, uschar ** err)
+{
+size_t ucs4_len;
+punycode_uint * p = (punycode_uint *) stringprep_utf8_to_ucs4(CCS utf8, -1, &ucs4_len);
+size_t p_len = ucs4_len*4; /* this multiplier is pure guesswork */
+uschar * res = store_get(p_len+5);
+int rc;
+
+res[0] = 'x'; res[1] = 'n'; res[2] = res[3] = '-';
+
+if ((rc = punycode_encode(ucs4_len, p, NULL, &p_len, res+4)) != PUNYCODE_SUCCESS)
+ {
+ DEBUG(D_expand) debug_printf("l_u2a: bad '%s'\n", punycode_strerror(rc));
+ free(p);
+ if (err) *err = US punycode_strerror(rc);
+ return NULL;
+ }
+p_len += 4;
+free(p);
+res[p_len] = '\0';
+return res;
+}
+
+
+uschar *
+string_localpart_alabel_to_utf8(const uschar * alabel, uschar ** err)
+{
+size_t p_len = strlen(alabel);
+punycode_uint * p;
+uschar * s;
+uschar * res;
+int rc;
+
+if (alabel[0] != 'x' || alabel[1] != 'n' || alabel[2] != '-' || alabel[3] != '-')
+ {
+ if (err) *err = US"bad alabel prefix";
+ return NULL;
+ }
+
+p_len -= 4;
+p = (punycode_uint *) store_get((p_len+1) * sizeof(*p));
+
+if ((rc = punycode_decode(p_len, CCS alabel+4, &p_len, p, NULL)) != PUNYCODE_SUCCESS)
+ {
+ if (err) *err = US punycode_strerror(rc);
+ return NULL;
+ }
+
+s = stringprep_ucs4_to_utf8(p, p_len, NULL, &p_len);
+res = string_copyn(s, p_len);
+free(s);
+return res;
+}
+
+
+/*************************************************
+* Report the library versions. *
+*************************************************/
+
+/* See a description in tls-openssl.c for an explanation of why this exists.
+
+Arguments: a FILE* to print the results to
+Returns: nothing
+*/
+
+void
+utf8_version_report(FILE *f)
+{
+fprintf(f, "Library version: IDN: Compile: %s\n"
+ " Runtime: %s\n",
+ STRINGPREP_VERSION,
+ stringprep_check_version(NULL));
+}
+
+#endif /* whole file */
+
+/* vi: aw ai sw=2
+*/
+/* End of utf8.c */
diff --git a/src/src/verify.c b/src/src/verify.c
index 678ee6315..4e9b563fa 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -920,6 +920,25 @@ can do it there for the non-rcpt-verify case. For this we keep an addresscount.
}
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ else if ( addr->prop.utf8
+ && !( esmtp
+ && ( regex_UTF8
+ || ( (regex_UTF8 = regex_must_compile(
+ US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE)),
+ TRUE
+ ) )
+ && pcre_exec(regex_UTF8, NULL, CS responsebuffer,
+ Ustrlen(responsebuffer), 0, PCRE_EOPT, NULL, 0) >= 0
+ ) )
+ {
+ HDEBUG(D_acl|D_v) debug_printf("utf8 required but not offered\n");
+ errno = ERRNO_UTF8_FWD;
+ setflag(addr, af_verify_nsfail);
+ done = FALSE;
+ }
+#endif
+
/* If we haven't authenticated, but are required to, give up. */
/* Try to AUTH */
@@ -937,7 +956,13 @@ can do it there for the non-rcpt-verify case. For this we keep an addresscount.
( (addr->auth_sndr = client_authenticated_sender),
/* Send the MAIL command */
- (smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>%s\r\n",
+ (smtp_write_command(&outblock, FALSE,
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ addr->prop.utf8
+ ? "MAIL FROM:<%s>%s SMTPUTF8\r\n"
+ :
+#endif
+ "MAIL FROM:<%s>%s\r\n",
from_address, responsebuffer) >= 0)
) &&
@@ -1022,7 +1047,13 @@ can do it there for the non-rcpt-verify case. For this we keep an addresscount.
smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
'2', callout) &&
- smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>\r\n",
+ smtp_write_command(&outblock, FALSE,
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ addr->prop.utf8
+ ? "MAIL FROM:<%s> SMTPUTF8\r\n"
+ :
+#endif
+ "MAIL FROM:<%s>\r\n",
from_address) >= 0 &&
smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
'2', callout);
@@ -1146,6 +1177,21 @@ can do it there for the non-rcpt-verify case. For this we keep an addresscount.
HDEBUG(D_verify) debug_printf("SMTP timeout\n");
send_quit = FALSE;
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ else if (errno == ERRNO_UTF8_FWD)
+ {
+ extern int acl_where; /* src/acl.c */
+ errno = 0;
+ addr->message = string_sprintf(
+ "response to \"%s\" from %s [%s] did not include SMTPUTF8",
+ big_buffer, host->name, host->address);
+ addr->user_message = acl_where == ACL_WHERE_RCPT
+ ? US"533 mailbox name not allowed"
+ : US"550 mailbox unavailable";
+ yield = FAIL;
+ done = TRUE;
+ }
+#endif
else if (errno == 0)
{
if (*responsebuffer == 0) Ustrcpy(responsebuffer, US"connection dropped");
@@ -1616,7 +1662,7 @@ if (addr != vaddr)
vaddr->user_message = addr->user_message;
vaddr->basic_errno = addr->basic_errno;
vaddr->more_errno = addr->more_errno;
- vaddr->p.address_data = addr->p.address_data;
+ vaddr->prop.address_data = addr->prop.address_data;
copyflag(vaddr, addr, af_pass_message);
}
return yield;
@@ -1877,8 +1923,8 @@ while (addr_new != NULL)
/* Just in case some router parameter refers to it. */
- return_path = (addr->p.errors_address != NULL)?
- addr->p.errors_address : sender_address;
+ return_path = (addr->prop.errors_address != NULL)?
+ addr->prop.errors_address : sender_address;
/* Split the address into domain and local part, handling the %-hack if
necessary, and then route it. While routing a sender address, set
@@ -2171,7 +2217,7 @@ while (addr_new != NULL)
/* If we have carried on to verify a child address, we want the value
of $address_data to be that of the child */
- vaddr->p.address_data = addr->p.address_data;
+ vaddr->prop.address_data = addr->prop.address_data;
yield = OK;
goto out;
}
@@ -2203,8 +2249,8 @@ for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
fprintf(f, "%s", CS addr->address);
#ifdef EXPERIMENTAL_SRS
- if(addr->p.srs_sender)
- fprintf(f, " [srs = %s]", addr->p.srs_sender);
+ if(addr->prop.srs_sender)
+ fprintf(f, " [srs = %s]", addr->prop.srs_sender);
#endif
/* If the address is a duplicate, show something about it. */
diff --git a/test/confs/4200 b/test/confs/4200
new file mode 100644
index 000000000..bce8e551f
--- /dev/null
+++ b/test/confs/4200
@@ -0,0 +1,12 @@
+# Exim test configuration 4200
+
+exim_path = EXIM_PATH
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+# ----- ACL -----
+
+# End
diff --git a/test/confs/4201 b/test/confs/4201
new file mode 100644
index 000000000..b34c7c1f9
--- /dev/null
+++ b/test/confs/4201
@@ -0,0 +1,120 @@
+# Exim test configuration 4201
+# SMTPUTF8 handling
+
+OPTION = *
+CONTROL =
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : cname
+
+acl_smtp_rcpt = check_recipient
+acl_not_smtp = non_smtp
+
+trusted_users = CALLER
+log_selector = +received_recipients +sender_on_delivery
+
+.ifdef SERVER
+queue_only
+queue_run_in_order
+.endif
+
+smtputf8_advertise_hosts = OPTION
+
+
+# ----- ACL -----
+
+begin acl
+
+
+.ifdef SERVER
+
+check_recipient:
+ accept hosts = :
+ accept domains = +local_domains
+ local_parts = ^user.*\$
+ deny message = relay not permitted
+
+.else
+
+sub:
+.ifdef CONTROL
+ require CONTROL
+.endif
+ accept
+
+check_recipient:
+ accept domains = *
+ acl = sub
+
+non_smtp:
+ accept senders = :
+ control = queue_only
+ accept
+
+.endif
+
+# ----- Routers -----
+
+begin routers
+
+.ifdef SERVER
+
+fail_remote_domains:
+ driver = redirect
+ domains = ! +local_domains
+ data = :fail: unrouteable mail domain "$domain"
+
+bounces:
+ driver = redirect
+ condition = ${if eq {} {$sender_address}}
+ data = DIR/test-mail/$local_part
+ file_transport = local_delivery
+
+localuser:
+ driver = redirect
+ data = :blackhole:
+
+.else
+
+bounces:
+ driver = redirect
+ domains = *.local
+ data = DIR/test-mail/$local_part
+ file_transport = local_delivery
+
+rmt:
+ driver = manualroute
+ domains = +local_domains
+ route_data = <;[127.0.0.1]:PORT_D
+ transport = rmt_smtp
+ self = send
+
+.endif
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ user = CALLER
+ delivery_date_add
+ envelope_to_add
+ file = DIR/test-mail/$local_part
+ headers_add = "X-body-linecount: $body_linecount\n\
+ X-message-linecount: $message_linecount\n\
+ X-received-count: $received_count"
+ return_path_add
+
+rmt_smtp:
+ driver = smtp
+
+# End
diff --git a/test/confs/4211 b/test/confs/4211
new file mode 100644
index 000000000..085fecc72
--- /dev/null
+++ b/test/confs/4211
@@ -0,0 +1,126 @@
+# Exim test configuration 4201
+# SMTPUTF8 handling
+
+OPTION = *
+CONTROL =
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : cname
+
+acl_smtp_rcpt = check_recipient
+acl_not_smtp = non_smtp
+
+trusted_users = CALLER
+log_selector = +received_recipients +sender_on_delivery
+
+.ifdef SERVER
+queue_only
+queue_run_in_order
+.endif
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_advertise_hosts = *
+
+smtputf8_advertise_hosts = OPTION
+
+
+# ----- ACL -----
+
+begin acl
+
+
+.ifdef SERVER
+
+check_recipient:
+ accept hosts = :
+ accept domains = +local_domains
+ local_parts = ^user.*\$
+ deny message = relay not permitted
+
+.else
+
+sub:
+.ifdef CONTROL
+ require CONTROL
+.endif
+ accept
+
+check_recipient:
+ accept domains = *
+ acl = sub
+
+non_smtp:
+ accept senders = :
+ control = queue_only
+ accept
+
+.endif
+
+# ----- Routers -----
+
+begin routers
+
+.ifdef SERVER
+
+fail_remote_domains:
+ driver = redirect
+ domains = ! +local_domains
+ data = :fail: unrouteable mail domain "$domain"
+
+bounces:
+ driver = redirect
+ condition = ${if eq {} {$sender_address}}
+ data = DIR/test-mail/$local_part
+ file_transport = local_delivery
+
+localuser:
+ driver = redirect
+ data = :blackhole:
+
+.else
+
+bounces:
+ driver = redirect
+ domains = *.local
+ data = DIR/test-mail/$local_part
+ file_transport = local_delivery
+
+rmt:
+ driver = manualroute
+ domains = +local_domains
+ route_data = <;[127.0.0.1]:PORT_D
+ transport = rmt_smtp
+ self = send
+
+.endif
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ user = CALLER
+ delivery_date_add
+ envelope_to_add
+ file = DIR/test-mail/$local_part
+ headers_add = "X-body-linecount: $body_linecount\n\
+ X-message-linecount: $message_linecount\n\
+ X-received-count: $received_count"
+ return_path_add
+
+rmt_smtp:
+ driver = smtp
+ hosts_require_tls = *
+ tls_try_verify_hosts = :
+
+# End
diff --git a/test/confs/4221 b/test/confs/4221
new file mode 100644
index 000000000..085fecc72
--- /dev/null
+++ b/test/confs/4221
@@ -0,0 +1,126 @@
+# Exim test configuration 4201
+# SMTPUTF8 handling
+
+OPTION = *
+CONTROL =
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : cname
+
+acl_smtp_rcpt = check_recipient
+acl_not_smtp = non_smtp
+
+trusted_users = CALLER
+log_selector = +received_recipients +sender_on_delivery
+
+.ifdef SERVER
+queue_only
+queue_run_in_order
+.endif
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_advertise_hosts = *
+
+smtputf8_advertise_hosts = OPTION
+
+
+# ----- ACL -----
+
+begin acl
+
+
+.ifdef SERVER
+
+check_recipient:
+ accept hosts = :
+ accept domains = +local_domains
+ local_parts = ^user.*\$
+ deny message = relay not permitted
+
+.else
+
+sub:
+.ifdef CONTROL
+ require CONTROL
+.endif
+ accept
+
+check_recipient:
+ accept domains = *
+ acl = sub
+
+non_smtp:
+ accept senders = :
+ control = queue_only
+ accept
+
+.endif
+
+# ----- Routers -----
+
+begin routers
+
+.ifdef SERVER
+
+fail_remote_domains:
+ driver = redirect
+ domains = ! +local_domains
+ data = :fail: unrouteable mail domain "$domain"
+
+bounces:
+ driver = redirect
+ condition = ${if eq {} {$sender_address}}
+ data = DIR/test-mail/$local_part
+ file_transport = local_delivery
+
+localuser:
+ driver = redirect
+ data = :blackhole:
+
+.else
+
+bounces:
+ driver = redirect
+ domains = *.local
+ data = DIR/test-mail/$local_part
+ file_transport = local_delivery
+
+rmt:
+ driver = manualroute
+ domains = +local_domains
+ route_data = <;[127.0.0.1]:PORT_D
+ transport = rmt_smtp
+ self = send
+
+.endif
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ user = CALLER
+ delivery_date_add
+ envelope_to_add
+ file = DIR/test-mail/$local_part
+ headers_add = "X-body-linecount: $body_linecount\n\
+ X-message-linecount: $message_linecount\n\
+ X-received-count: $received_count"
+ return_path_add
+
+rmt_smtp:
+ driver = smtp
+ hosts_require_tls = *
+ tls_try_verify_hosts = :
+
+# End
diff --git a/test/dnszones-src/db.test.ex b/test/dnszones-src/db.test.ex
index fec2a0d78..ebf9a4021 100644
--- a/test/dnszones-src/db.test.ex
+++ b/test/dnszones-src/db.test.ex
@@ -38,9 +38,9 @@ dontqualify A V4NET.255.255.254
UpperCase A 127.0.0.1
-; A host with UTF-8 characters in its name
+; A host with UTF-8 characters used for its lookup ( π.test.ex )
-mx.π A V4NET.255.255.255
+mx.xn--1xa A V4NET.255.255.255
; A non-standard name for localhost
@@ -358,9 +358,9 @@ mxt97 MX 1 ten-1.test.ex.
mxt1c MX 1 dontqualify.
-; MX with UTF-8 characters in its name
+; MX with UTF-8 characters used for its lookup ( π.test.ex )
-π MX 0 mx.π.test.ex.
+xn--1xa MX 0 mx.xn--1xa.test.ex.
; -------- Testing SRV records --------
diff --git a/test/log/4201 b/test/log/4201
new file mode 100644
index 000000000..82f19c844
--- /dev/null
+++ b/test/log/4201
@@ -0,0 +1,95 @@
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= someone@some.domain H=(client) [127.0.0.1] P=utf8esmtp S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com H=(client) [127.0.0.1] P=utf8esmtp S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= 他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com U=CALLER P=utf8local-esmtp S=sss for usery@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= 他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmaZ-0005vi-00@the.local.host.name for usery@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery@test.ex F=<他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <usery@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= user.dontcare@test1.com U=CALLER P=local S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= user.dontcare@test1.com H=localhost (the.local.host.name) [127.0.0.1] P=esmtp S=sss id=E10HmbB-0005vi-00@the.local.host.name for userx@test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 => userx@test.ex F=<user.dontcare@test1.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= user.dontcare@test1.com U=CALLER P=local S=sss for user.他们为什么不说中文@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= user.dontcare@test1.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmbD-0005vi-00@the.local.host.name for user.他们为什么不说中文@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 => user.他们为什么不说中文@test.ex F=<user.dontcare@test1.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbE-0005vi-00"
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= 他们为什么不说中文@test1.com U=CALLER P=local S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= 他们为什么不说中文@test1.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmbF-0005vi-00@the.local.host.name for userx@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 => userx@test.ex F=<他们为什么不说中文@test1.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbG-0005vi-00"
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: <user.他们为什么不说中文@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbG-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= <> R=10HmbH-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+1999-03-02 09:44:33 10HmbI-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qfl
+1999-03-02 09:44:33 10HmbI-0005vi-00 => TESTSUITE/test-mail/यहलोगहिन्दीक्योंनहींबोलसकतेहैं <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> F=<> R=bounces T=local_delivery
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qfl
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbJ-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com U=CALLER P=utf8local-esmtp S=sss for userQ@test.ex
+1999-03-02 09:44:33 10HmbK-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmbJ-0005vi-00@the.local.host.name for userQ@test.ex
+1999-03-02 09:44:33 10HmbJ-0005vi-00 => userq@test.ex <userQ@test.ex> F=<세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbK-0005vi-00"
+1999-03-02 09:44:33 10HmbJ-0005vi-00 Completed
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 10HmbL-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com U=CALLER P=utf8local-esmtp S=sss for userR@test.ex
+1999-03-02 09:44:33 10HmbM-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmbL-0005vi-00@the.local.host.name for userR@test.ex
+1999-03-02 09:44:33 10HmbL-0005vi-00 => userr@test.ex <userR@test.ex> F=<세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbM-0005vi-00"
+1999-03-02 09:44:33 10HmbL-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbK-0005vi-00 => :blackhole: <userQ@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbK-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbM-0005vi-00 => :blackhole: <userR@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbM-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 U=CALLER F=<CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> rejected RCPT <userS@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> rejected RCPT <userT@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbN-0005vi-00 <= userU@test.ex U=CALLER P=utf8local-esmtp S=sss for user.γλυκύρριζα@test.ex
+1999-03-02 09:44:33 10HmbO-0005vi-00 <= userU@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmbN-0005vi-00@the.local.host.name for user.γλυκύρριζα@test.ex
+1999-03-02 09:44:33 10HmbN-0005vi-00 => user.γλυκύρριζα@test.ex F=<userU@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbO-0005vi-00"
+1999-03-02 09:44:33 10HmbN-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbO-0005vi-00 => :blackhole: <user.γλυκύρριζα@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbO-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbP-0005vi-00 <= userV.වැල්_මී@test.ex U=CALLER P=utf8local-esmtp S=sss for user.அதிமதுரம்@test.ex
+1999-03-02 09:44:33 10HmbQ-0005vi-00 <= userV.වැල්_මී@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmbP-0005vi-00@the.local.host.name for user.அதிமதுரம்@test.ex
+1999-03-02 09:44:33 10HmbP-0005vi-00 => user.அதிமதுரம்@test.ex F=<userV.වැල්_මී@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbQ-0005vi-00"
+1999-03-02 09:44:33 10HmbP-0005vi-00 Completed
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 10HmbR-0005vi-00 <= userW@test.ex U=CALLER P=utf8local-esmtp S=sss for user.ഇരട്ടിമധുരം@test.ex
+1999-03-02 09:44:33 10HmbS-0005vi-00 <= userW@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtp S=sss id=E10HmbR-0005vi-00@the.local.host.name for user.ഇരട്ടിമധുരം@test.ex
+1999-03-02 09:44:33 10HmbR-0005vi-00 => user.ഇരട്ടിമധുരം@test.ex F=<userW@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmbS-0005vi-00"
+1999-03-02 09:44:33 10HmbR-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbQ-0005vi-00 => :blackhole: <user.அதிமதுரம்@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbQ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbS-0005vi-00 => :blackhole: <user.ഇരട്ടിമധുരം@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbS-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userA@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userA@test.ex> rejected RCPT <user.यष्टिमधु@test.ex>: Sender verify failed
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userB.જેઠીમધ@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userB.જેઠીમધ@test.ex> rejected RCPT <user.ქართული@test.ex>: Sender verify failed
diff --git a/test/log/4211 b/test/log/4211
new file mode 100644
index 000000000..345337583
--- /dev/null
+++ b/test/log/4211
@@ -0,0 +1,74 @@
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= someone@some.domain H=(client) [127.0.0.1] P=utf8esmtp S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com H=(client) [127.0.0.1] P=utf8esmtp S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= 他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com U=CALLER P=utf8local-esmtp S=sss for usery@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= 他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaZ-0005vi-00@the.local.host.name for usery@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery@test.ex F=<他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <usery@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no: utf8 support required but not offered for forwarding
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= <> R=10HmbB-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+1999-03-02 09:44:33 10HmbC-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qfl
+1999-03-02 09:44:33 10HmbC-0005vi-00 => TESTSUITE/test-mail/यहलोगहिन्दीक्योंनहींबोलसकतेहैं <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> F=<> R=bounces T=local_delivery
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qfl
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com U=CALLER P=utf8local-esmtp S=sss for userQ@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbD-0005vi-00@the.local.host.name for userQ@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 => userq@test.ex <userQ@test.ex> F=<세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbE-0005vi-00"
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com U=CALLER P=utf8local-esmtp S=sss for userR@test.ex
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbF-0005vi-00@the.local.host.name for userR@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 => userr@test.ex <userR@test.ex> F=<세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbG-0005vi-00"
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: <userQ@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbG-0005vi-00 => :blackhole: <userR@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 U=CALLER F=<CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> rejected RCPT <userS@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> rejected RCPT <userT@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= userU@test.ex U=CALLER P=utf8local-esmtp S=sss for user.γλυκύρριζα@test.ex
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= userU@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbH-0005vi-00@the.local.host.name for user.γλυκύρριζα@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 => user.γλυκύρριζα@test.ex F=<userU@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbI-0005vi-00"
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbI-0005vi-00 => :blackhole: <user.γλυκύρριζα@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbJ-0005vi-00 <= userV.වැල්_මී@test.ex U=CALLER P=utf8local-esmtp S=sss for user.அதிமதுரம்@test.ex
+1999-03-02 09:44:33 10HmbK-0005vi-00 <= userV.වැල්_මී@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbJ-0005vi-00@the.local.host.name for user.அதிமதுரம்@test.ex
+1999-03-02 09:44:33 10HmbJ-0005vi-00 => user.அதிமதுரம்@test.ex F=<userV.වැල්_මී@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbK-0005vi-00"
+1999-03-02 09:44:33 10HmbJ-0005vi-00 Completed
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 10HmbL-0005vi-00 <= userW@test.ex U=CALLER P=utf8local-esmtp S=sss for user.ഇരട്ടിമധുരം@test.ex
+1999-03-02 09:44:33 10HmbM-0005vi-00 <= userW@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbL-0005vi-00@the.local.host.name for user.ഇരട്ടിമധുരം@test.ex
+1999-03-02 09:44:33 10HmbL-0005vi-00 => user.ഇരട്ടിമധുരം@test.ex F=<userW@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbM-0005vi-00"
+1999-03-02 09:44:33 10HmbL-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbK-0005vi-00 => :blackhole: <user.அதிமதுரம்@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbK-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbM-0005vi-00 => :blackhole: <user.ഇരട്ടിമധുരം@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbM-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userA@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userA@test.ex> rejected RCPT <user.यष्टिमधु@test.ex>: Sender verify failed
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userB.જેઠીમધ@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userB.જેઠીમધ@test.ex> rejected RCPT <user.ქართული@test.ex>: Sender verify failed
diff --git a/test/log/4221 b/test/log/4221
new file mode 100644
index 000000000..ddbbe8c11
--- /dev/null
+++ b/test/log/4221
@@ -0,0 +1,74 @@
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= someone@some.domain H=(client) [127.0.0.1] P=utf8esmtp S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com H=(client) [127.0.0.1] P=utf8esmtp S=sss for userx@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= 他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com U=CALLER P=utf8local-esmtp S=sss for usery@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= 他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@the.local.host.name for usery@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery@test.ex F=<他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userx@test.ex> R=localuser
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <usery@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no: utf8 support required but not offered for forwarding
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= <> R=10HmbB-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+1999-03-02 09:44:33 10HmbC-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qfl
+1999-03-02 09:44:33 10HmbC-0005vi-00 => TESTSUITE/test-mail/यहलोगहिन्दीक्योंनहींबोलसकतेहैं <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> F=<> R=bounces T=local_delivery
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qfl
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com U=CALLER P=utf8local-esmtp S=sss for userQ@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbD-0005vi-00@the.local.host.name for userQ@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 => userq@test.ex <userQ@test.ex> F=<세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbE-0005vi-00"
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com U=CALLER P=utf8local-esmtp S=sss for userR@test.ex
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= 세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbF-0005vi-00@the.local.host.name for userR@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 => userr@test.ex <userR@test.ex> F=<세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbG-0005vi-00"
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: <userQ@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbG-0005vi-00 => :blackhole: <userR@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 U=CALLER F=<CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> rejected RCPT <userS@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> rejected RCPT <userT@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= userU@test.ex U=CALLER P=utf8local-esmtp S=sss for user.γλυκύρριζα@test.ex
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= userU@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbH-0005vi-00@the.local.host.name for user.γλυκύρριζα@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 => user.γλυκύρριζα@test.ex F=<userU@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbI-0005vi-00"
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbI-0005vi-00 => :blackhole: <user.γλυκύρριζα@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbJ-0005vi-00 <= userV.වැල්_මී@test.ex U=CALLER P=utf8local-esmtp S=sss for user.அதிமதுரம்@test.ex
+1999-03-02 09:44:33 10HmbK-0005vi-00 <= userV.වැල්_මී@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbJ-0005vi-00@the.local.host.name for user.அதிமதுரம்@test.ex
+1999-03-02 09:44:33 10HmbJ-0005vi-00 => user.அதிமதுரம்@test.ex F=<userV.වැල්_මී@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbK-0005vi-00"
+1999-03-02 09:44:33 10HmbJ-0005vi-00 Completed
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 10HmbL-0005vi-00 <= userW@test.ex U=CALLER P=utf8local-esmtp S=sss for user.ഇരട്ടിമധുരം@test.ex
+1999-03-02 09:44:33 10HmbM-0005vi-00 <= userW@test.ex H=localhost (the.local.host.name) [127.0.0.1] P=utf8esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbL-0005vi-00@the.local.host.name for user.ഇരട്ടിമധുരം@test.ex
+1999-03-02 09:44:33 10HmbL-0005vi-00 => user.ഇരട്ടിമധുരം@test.ex F=<userW@test.ex> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbM-0005vi-00"
+1999-03-02 09:44:33 10HmbL-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqff
+1999-03-02 09:44:33 10HmbK-0005vi-00 => :blackhole: <user.அதிமதுரம்@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbK-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbM-0005vi-00 => :blackhole: <user.ഇരട്ടിമധുരം@test.ex> R=localuser
+1999-03-02 09:44:33 10HmbM-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqff
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userA@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userA@test.ex> rejected RCPT <user.यष्टिमधु@test.ex>: Sender verify failed
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userB.જેઠીમધ@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userB.જેઠીમધ@test.ex> rejected RCPT <user.ქართული@test.ex>: Sender verify failed
diff --git a/test/mail/4201.यहलोगहिन्दीक्योंनहींबोलसकतेहैं b/test/mail/4201.यहलोगहिन्दीक्योंनहींबोलसकतेहैं
new file mode 100644
index 000000000..2582388aa
--- /dev/null
+++ b/test/mail/4201.यहलोगहिन्दीक्योंनहींबोलसकतेहैं
@@ -0,0 +1,59 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Envelope-to: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+Delivery-date: Tue, 2 Mar 1999 09:44:33 +0000
+Received: from EXIMUSER by the.local.host.name with local (Exim x.yz)
+ id 10HmbI-0005vi-00
+ for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local; Tue, 2 Mar 1999 09:44:33 +0000
+X-Failed-Recipients: userz@test.ex
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@the.local.host.name>
+To: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+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: <E10HmbI-0005vi-00@the.local.host.name>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-body-linecount: 38
+X-message-linecount: 50
+X-received-count: 1
+
+--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:
+
+ userz@test.ex
+ host 127.0.0.1 [127.0.0.1]
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/global-delivery-status
+
+Reporting-MTA: dns; the.local.host.name
+
+Action: failed
+Final-Recipient: rfc822;userz@test.ex
+Status: 5.0.0
+Remote-MTA: dns; 127.0.0.1
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/global
+
+Return-path: <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local>
+Received: from CALLER (helo=client.ffail)
+ by the.local.host.name with utf8local-esmtp (Exim x.yz)
+ (envelope-from <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local>)
+ id 10HmbH-0005vi-00
+ for userz@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: test
+Message-Id: <E10HmbH-0005vi-00@the.local.host.name>
+From: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+body
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM--
+
diff --git a/test/mail/4211.यहलोगहिन्दीक्योंनहींबोलसकतेहैं b/test/mail/4211.यहलोगहिन्दीक्योंनहींबोलसकतेहैं
new file mode 100644
index 000000000..cb2203570
--- /dev/null
+++ b/test/mail/4211.यहलोगहिन्दीक्योंनहींबोलसकतेहैं
@@ -0,0 +1,59 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Envelope-to: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+Delivery-date: Tue, 2 Mar 1999 09:44:33 +0000
+Received: from EXIMUSER by the.local.host.name with local (Exim x.yz)
+ id 10HmbC-0005vi-00
+ for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local; Tue, 2 Mar 1999 09:44:33 +0000
+X-Failed-Recipients: userz@test.ex
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@the.local.host.name>
+To: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+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: <E10HmbC-0005vi-00@the.local.host.name>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-body-linecount: 38
+X-message-linecount: 50
+X-received-count: 1
+
+--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:
+
+ userz@test.ex
+ host 127.0.0.1 [127.0.0.1]
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/global-delivery-status
+
+Reporting-MTA: dns; the.local.host.name
+
+Action: failed
+Final-Recipient: rfc822;userz@test.ex
+Status: 5.0.0
+Remote-MTA: dns; 127.0.0.1
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/global
+
+Return-path: <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local>
+Received: from CALLER (helo=client.ffail)
+ by the.local.host.name with utf8local-esmtp (Exim x.yz)
+ (envelope-from <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local>)
+ id 10HmbB-0005vi-00
+ for userz@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: test
+Message-Id: <E10HmbB-0005vi-00@the.local.host.name>
+From: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+body
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM--
+
diff --git a/test/mail/4221.यहलोगहिन्दीक्योंनहींबोलसकतेहैं b/test/mail/4221.यहलोगहिन्दीक्योंनहींबोलसकतेहैं
new file mode 100644
index 000000000..cb2203570
--- /dev/null
+++ b/test/mail/4221.यहलोगहिन्दीक्योंनहींबोलसकतेहैं
@@ -0,0 +1,59 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Envelope-to: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+Delivery-date: Tue, 2 Mar 1999 09:44:33 +0000
+Received: from EXIMUSER by the.local.host.name with local (Exim x.yz)
+ id 10HmbC-0005vi-00
+ for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local; Tue, 2 Mar 1999 09:44:33 +0000
+X-Failed-Recipients: userz@test.ex
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@the.local.host.name>
+To: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+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: <E10HmbC-0005vi-00@the.local.host.name>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-body-linecount: 38
+X-message-linecount: 50
+X-received-count: 1
+
+--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:
+
+ userz@test.ex
+ host 127.0.0.1 [127.0.0.1]
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/global-delivery-status
+
+Reporting-MTA: dns; the.local.host.name
+
+Action: failed
+Final-Recipient: rfc822;userz@test.ex
+Status: 5.0.0
+Remote-MTA: dns; 127.0.0.1
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM
+Content-type: message/global
+
+Return-path: <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local>
+Received: from CALLER (helo=client.ffail)
+ by the.local.host.name with utf8local-esmtp (Exim x.yz)
+ (envelope-from <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local>)
+ id 10HmbB-0005vi-00
+ for userz@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: test
+Message-Id: <E10HmbB-0005vi-00@the.local.host.name>
+From: यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+body
+
+--NNNNNNNNNN-eximdsn-MMMMMMMMMM--
+
diff --git a/test/rejectlog/4201 b/test/rejectlog/4201
new file mode 100644
index 000000000..a8ced2cc1
--- /dev/null
+++ b/test/rejectlog/4201
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 U=CALLER F=<CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> rejected RCPT <userS@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> rejected RCPT <userT@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userA@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userA@test.ex> rejected RCPT <user.यष्टिमधु@test.ex>: Sender verify failed
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userB.જેઠીમધ@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userB.જેઠીમધ@test.ex> rejected RCPT <user.ქართული@test.ex>: Sender verify failed
diff --git a/test/rejectlog/4211 b/test/rejectlog/4211
new file mode 100644
index 000000000..90d7d73e1
--- /dev/null
+++ b/test/rejectlog/4211
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 U=CALLER F=<CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> rejected RCPT <userS@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> rejected RCPT <userT@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userA@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userA@test.ex> rejected RCPT <user.यष्टिमधु@test.ex>: Sender verify failed
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userB.જેઠીમધ@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userB.જેઠીમધ@test.ex> rejected RCPT <user.ქართული@test.ex>: Sender verify failed
diff --git a/test/rejectlog/4221 b/test/rejectlog/4221
new file mode 100644
index 000000000..067e530de
--- /dev/null
+++ b/test/rejectlog/4221
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 U=CALLER F=<CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> rejected RCPT <userS@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> rejected RCPT <userT@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 H=localhost (the.local.host.name) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> rejected RCPT <the.local.host.name-dddddddd-testing@test.ex>: relay not permitted
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userA@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userA@test.ex> rejected RCPT <user.यष्टिमधु@test.ex>: Sender verify failed
+1999-03-02 09:44:33 U=CALLER sender verify fail for <userB.જેઠીમધ@test.ex>: response to "EHLO the.local.host.name" from 127.0.0.1 [127.0.0.1] did not include SMTPUTF8
+1999-03-02 09:44:33 U=CALLER F=<userB.જેઠીમધ@test.ex> rejected RCPT <user.ქართული@test.ex>: Sender verify failed
diff --git a/test/runtest b/test/runtest
index 2baf2cafd..4a4427839 100755
--- a/test/runtest
+++ b/test/runtest
@@ -413,6 +413,7 @@ RESET_AFTER_EXTRA_LINE_READ:
# Random local part in callout cache testing
s/myhost.test.ex-\d+-testing/myhost.test.ex-dddddddd-testing/;
+ s/the.local.host.name-\d+-testing/the.local.host.name-dddddddd-testing/;
# File descriptor numbers may vary
s/^writing data block fd=\d+/writing data block fd=dddd/;
@@ -844,7 +845,6 @@ RESET_AFTER_EXTRA_LINE_READ:
next if /^SSL info: unknown state/;
next if /^SSL info: SSLv2\/v3 write client hello A/;
next if /^SSL info: SSLv3 read server key exchange A/;
-
}
# ======== stderr ========
@@ -1011,6 +1011,9 @@ RESET_AFTER_EXTRA_LINE_READ:
next if /in\shosts_require_dane\?\sno\s\(option\sunset\)/x;
+ # Experimental_International
+ next if / in smtputf8_advertise_hosts\? no \(option unset\)/;
+
# Skip some lines that Exim puts out at the start of debugging output
# because they will be different in different binaries.
@@ -1027,6 +1030,8 @@ RESET_AFTER_EXTRA_LINE_READ:
/^Fixed never_users:/ ||
/^Size of off_t:/
);
+
+
}
next;
diff --git a/test/scripts/4200-International/4200 b/test/scripts/4200-International/4200
new file mode 100644
index 000000000..48918b702
--- /dev/null
+++ b/test/scripts/4200-International/4200
@@ -0,0 +1,96 @@
+# Internationalised mail: expansions
+#
+# Sample strings taken from RFC3942
+
+exim -be
+
+utf-8 localpart to a-label:
+
+${utf8_localpart_to_alabel:\xD9\x84}
+xn--ghb
+
+${utf8_localpart_to_alabel:\xD9\x84\xD9\x8A\xD9\x87\xD9\x85\xD8\xA7\xD8\xA8\xD8\xAA\xD9\x83\xD9\x84\
+\xD9\x85\xD9\x88\xD8\xB4\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x8A\xD8\x9F}
+xn--egbpdaj6bu4bxfgehfvwxn
+
+a-label localpart to utf-8:
+
+${utf8_localpart_from_alabel:xn--ghb}
+${utf8_localpart_from_alabel:xn--egbpdaj6bu4bxfgehfvwxn}
+
+utf-8 domain to a-label:
+
+${utf8_domain_to_alabel:bogus.\xD9\x84.com}
+bogus.xn--ghb.com
+
+${utf8_domain_to_alabel:arabic.\xD9\x84\xD9\x8A\xD9\x87\xD9\x85\xD8\xA7\xD8\xA8\xD8\xAA\xD9\x83\xD9\x84\
+\xD9\x85\xD9\x88\xD8\xB4\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x8A\xD8\x9F.com}
+arabic.xn--egbpdaj6bu4bxfgehfvwxn.com
+
+${utf8_domain_to_alabel:simpl.chinese.\xE4\xBB\x96\xE4\xBB\xAC\xE4\xB8\xBA\xE4\xBB\x80\
+\xE4\xB9\x88\xE4\xB8\x8D\xE8\xAF\xB4\xE4\xB8\xAD\xE6\x96\x87.com}
+simpl.chinese.xn--ihqwcrb4cv8a8dqg056pqjye.com
+
+${utf8_domain_to_alabel:trad.chinese.\xE4\xBB\x96\xE5\x80\x91\xE7\x88\xB2\xE4\xBB\x80\
+\xE9\xBA\xBD\xE4\xB8\x8D\xE8\xAA\xAA\xE4\xB8\xAD\xE6\x96\x87.com}
+trad.chinese.xn--ihqwctvzc91f659drss3x8bo0yb.com
+
+${utf8_domain_to_alabel:czech.\x50\x72\x6F\xC4\x8D\x70\x72\x6F\x73\x74\xC4\x9B\x6E\x65\
+\x6D\x6C\x75\x76\xC3\xAD\xC4\x8D\x65\x73\x6B\x79.com}
+czech.xn--Proprostnemluvesky-uyb24dma41a.com
+
+${utf8_domain_to_alabel:hebrew.\xD7\x9C\xD7\x9E\xD7\x94\xD7\x94\xD7\x9D\xD7\xA4\xD7\xA9\
+\xD7\x95\xD7\x98\xD7\x9C\xD7\x90\xD7\x9E\xD7\x93\xD7\x91\xD7\xA8\xD7\x99\xD7\x9D\xD7\xA2\
+\xD7\x91\xD7\xA8\xD7\x99\xD7\xAA.com}
+hebrew.xn--4dbcagdahymbxekheh6e0a7fei0b.com
+
+${utf8_domain_to_alabel:hindi.\xE0\xA4\xAF\xE0\xA4\xB9\xE0\xA4\xB2\xE0\xA5\x8B\xE0\xA4\x97\
+\xE0\xA4\xB9\xE0\xA4\xBF\xE0\xA4\xA8\xE0\xA5\x8D\xE0\xA4\xA6\xE0\xA5\x80\xE0\xA4\x95\xE0\xA5\x8D\
+\xE0\xA4\xAF\xE0\xA5\x8B\xE0\xA4\x82\xE0\xA4\xA8\xE0\xA4\xB9\xE0\xA5\x80\xE0\xA4\x82\xE0\xA4\xAC\
+\xE0\xA5\x8B\xE0\xA4\xB2\xE0\xA4\xB8\xE0\xA4\x95\xE0\xA4\xA4\xE0\xA5\x87\xE0\xA4\xB9\xE0\xA5\x88\
+\xE0\xA4\x82.com}
+hindi.xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd.com
+
+${utf8_domain_to_alabel:japanese.\xE3\x81\xAA\xE3\x81\x9C\xE3\x81\xBF\xE3\x82\x93\xE3\x81\xAA\
+\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE3\x82\x92\xE8\xA9\xB1\xE3\x81\x97\xE3\x81\xA6\xE3\x81\x8F\
+\xE3\x82\x8C\xE3\x81\xAA\xE3\x81\x84\xE3\x81\xAE\xE3\x81\x8B.com}
+japanese.xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa.com
+
+# the a-label for the phrase in korean is too long for a domain label (63 byte limit)
+korean: ${utf8_localpart_to_alabel:\xEC\x84\xB8\xEA\xB3\x84\xEC\x9D\x98\xEB\xAA\xA8\xEB\x93\xA0\
+\xEC\x82\xAC\xEB\x9E\x8C\xEB\x93\xA4\xEC\x9D\xB4\xED\x95\x9C\xEA\xB5\xAD\xEC\x96\xB4\xEB\xA5\xBC\
+\xEC\x9D\xB4\xED\x95\xB4\xED\x95\x9C\xEB\x8B\xA4\xEB\xA9\xB4\xEC\x96\xBC\xEB\xA7\x88\xEB\x82\x98\
+\xEC\xA2\x8B\xEC\x9D\x84\xEA\xB9\x8C}
+korean: xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c
+
+${utf8_domain_to_alabel:russian.\xD0\xBF\xD0\xBE\xD1\x87\xD0\xB5\xD0\xBC\xD1\x83\xD0\xB6\
+\xD0\xB5\xD0\xBE\xD0\xBD\xD0\xB8\xD0\xBD\xD0\xB5\xD0\xB3\xD0\xBE\xD0\xB2\xD0\xBE\xD1\x80\
+\xD1\x8F\xD1\x82\xD0\xBF\xD0\xBE\xD1\x80\xD1\x83\xD1\x81\xD1\x81\xD0\xBA\xD0\xB8.com}
+russian.xn--b1abfaaepdrnnbgefbaDotcwatmq2g4l.com
+
+${utf8_domain_to_alabel:spanish.\x50\x6F\x72\x71\x75\xC3\xA9\x6E\x6F\x70\x75\x65\x64\x65\
+\x6E\x73\x69\x6D\x70\x6C\x65\x6D\x65\x6E\x74\x65\x68\x61\x62\x6C\x61\x72\x65\x6E\x45\x73\
+\x70\x61\xC3\xB1\x6F\x6C.com}
+spanish.xn--PorqunopuedensimplementehablarenEspaol-fmd56a.com
+
+${utf8_domain_to_alabel:vietnamese.\x54\xE1\xBA\xA1\x69\x73\x61\x6F\x68\xE1\xBB\x8D\x6B\x68\
+\xC3\xB4\x6E\x67\x74\x68\xE1\xBB\x83\x63\x68\xE1\xBB\x89\x6E\xC3\xB3\x69\x74\x69\xE1\xBA\xBF\
+\x6E\x67\x56\x69\xE1\xBB\x87\x74.com}
+vietnamese.xn--TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g.com
+
+a-label domain to utf-8:
+
+${utf8_domain_from_alabel:arab.xn--ghb.com}
+${utf8_domain_from_alabel:arab.xn--egbpdaj6bu4bxfgehfvwxn.com}
+${utf8_domain_from_alabel:simpl.chinese.xn--ihqwcrb4cv8a8dqg056pqjye.com}
+${utf8_domain_from_alabel:trad.chinese.xn--ihqwctvzc91f659drss3x8bo0yb.com}
+${utf8_domain_from_alabel:czech.xn--Proprostnemluvesky-uyb24dma41a.com}
+${utf8_domain_from_alabel:hebrew.xn--4dbcagdahymbxekheh6e0a7fei0b.com}
+${utf8_domain_from_alabel:hindi.xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd.com}
+${utf8_domain_from_alabel:japanese.xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa.com}
+korean: ${utf8_localpart_from_alabel:xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c}
+${utf8_domain_from_alabel:russian.xn--b1abfaaepdrnnbgefbaDotcwatmq2g4l.com}
+${utf8_domain_from_alabel:spanish.xn--PorqunopuedensimplementehablarenEspaol-fmd56a.com}
+${utf8_domain_from_alabel:vietnamese.xn--TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g.com}
+
+****
diff --git a/test/scripts/4200-International/4201 b/test/scripts/4200-International/4201
new file mode 100644
index 000000000..eb2600682
--- /dev/null
+++ b/test/scripts/4200-International/4201
@@ -0,0 +1,265 @@
+# Internationalised mail: smtp
+# Exim test configuration 4200
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+#
+# Basic smtp input, no delivery
+client 127.0.0.1 PORT_D
+??? 220
+EHLO client
+??? 250-
+??? 250-SIZE
+??? 250-8BITMIME
+??? 250-PIPELINING
+??? 250-SMTPUTF8
+??? 250 HELP
+MAIL FROM: <someone@some.domain> SMTPUTF8
+??? 250
+RCPT TO: <userx@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+# utf-8 from, Basic smtp input, no delivery
+client 127.0.0.1 PORT_D
+??? 220
+EHLO client
+??? 250-
+??? 250-SIZE
+??? 250-8BITMIME
+??? 250-PIPELINING
+??? 250-SMTPUTF8
+??? 250 HELP
+MAIL FROM: <ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com> SMTPUTF8
+??? 250
+RCPT TO: <userx@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+# utf-8 from, -bs input and forwarding
+exim -bs -odi
+EHLO client.bh
+MAIL FROM: <他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com> SMTPUTF8
+RCPT TO: <usery@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+#
+# commandline/stdin input, normal rcpt & sender, forwarded
+exim -odi -f user.dontcare@test1.com userx@test.ex
+Test message 1.
+.
+****
+# commandline/stdin input, utf-8 rcpt, forwarded
+exim -odi -f user.dontcare@test1.com user.他们为什么不说中文@test.ex
+Test message 2.
+.
+****
+# commandline/stdin input, utf-8 sender, forwarded
+exim -odi -f 他们为什么不说中文@test1.com userx@test.ex
+Test message 3.
+.
+****
+#
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+#
+# forwarding fails when target does not support SMTPUTF8
+exim -bs -odi
+EHLO client.ffail
+MAIL FROM: <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> SMTPUTF8
+RCPT TO: <userz@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+#
+#
+killdaemon
+#
+exim -qfl
+****
+#
+#
+#
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# Recipient verify callout, pass
+exim -bs -odi -DCONTROL="verify=recipient/callout"
+EHLO client.bh
+MAIL FROM: <세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> SMTPUTF8
+RCPT TO: <userQ@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+# Recipient+random verify callout, pass
+exim -bs -odi -DCONTROL="verify=recipient/callout=random"
+EHLO client.bh
+MAIL FROM: <세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> SMTPUTF8
+RCPT TO: <userR@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+#
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+#
+# Recipient verify callout, fail
+exim -bs -odi -DCONTROL="verify=recipient/callout"
+EHLO client.ffail
+MAIL FROM: <CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> SMTPUTF8
+RCPT TO: <userS@test.ex>
+QUIT
+****
+#
+# Recipient+random verify callout, fail
+exim -bs -odi -DCONTROL="verify=recipient/callout=random"
+EHLO client.ffail
+MAIL FROM: <CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> SMTPUTF8
+RCPT TO: <userT@test.ex>
+QUIT
+****
+#
+killdaemon
+#
+#
+#
+#
+#
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# utf-8 to, -bs input and forwarding
+exim -bs -odi
+EHLO client.bh
+MAIL FROM: <userU@test.ex> SMTPUTF8
+RCPT TO: <user.γλυκύρριζα@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# sender verify callout, pass
+exim -bs -odi -DCONTROL="verify=sender/callout"
+EHLO client.bh
+MAIL FROM: <userV.වැල්_මී@test.ex> SMTPUTF8
+RCPT TO: <user.அதிமதுரம்@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+# sender+random verify callout, pass
+exim -bs -odi -DCONTROL="verify=sender/callout=random"
+EHLO client.bh
+MAIL FROM: <userW@test.ex> SMTPUTF8
+RCPT TO: <user.ഇരട്ടിമധുരം@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+# sender verify callout, fail
+exim -bs -odi -DCONTROL="verify=sender/callout"
+EHLO client.sfail
+MAIL FROM: <userA@test.ex> SMTPUTF8
+RCPT TO: <user.यष्टिमधु@test.ex>
+QUIT
+****
+# sender+random verify callout, fail
+exim -bs -odi -DCONTROL="verify=sender/callout=random"
+EHLO client.sfail
+MAIL FROM: <userB.જેઠીમધ@test.ex> SMTPUTF8
+RCPT TO: <user.ქართული@test.ex>
+QUIT
+****
+#
+killdaemon
diff --git a/test/scripts/4200-International/REQUIRES b/test/scripts/4200-International/REQUIRES
new file mode 100644
index 000000000..c66f68046
--- /dev/null
+++ b/test/scripts/4200-International/REQUIRES
@@ -0,0 +1 @@
+support Experimental_International
diff --git a/test/scripts/4210-GnuTLS-International/4211 b/test/scripts/4210-GnuTLS-International/4211
new file mode 100644
index 000000000..2e13f3f90
--- /dev/null
+++ b/test/scripts/4210-GnuTLS-International/4211
@@ -0,0 +1,246 @@
+# Internationalised mail: smtp
+# Exim test configuration 4200
+gnutls
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+#
+# Basic smtp input, no delivery
+client 127.0.0.1 PORT_D
+??? 220
+EHLO client
+??? 250-
+??? 250-SIZE
+??? 250-8BITMIME
+??? 250-PIPELINING
+??? 250-STARTTLS
+??? 250-SMTPUTF8
+??? 250 HELP
+MAIL FROM: <someone@some.domain> SMTPUTF8
+??? 250
+RCPT TO: <userx@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+# utf-8 from, Basic smtp input, no delivery
+client 127.0.0.1 PORT_D
+??? 220
+EHLO client
+??? 250-
+??? 250-SIZE
+??? 250-8BITMIME
+??? 250-PIPELINING
+??? 250-STARTTLS
+??? 250-SMTPUTF8
+??? 250 HELP
+MAIL FROM: <ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com> SMTPUTF8
+??? 250
+RCPT TO: <userx@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+# utf-8 from, -bs input and forwarding
+exim -bs -odi
+EHLO client.bh
+MAIL FROM: <他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com> SMTPUTF8
+RCPT TO: <usery@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+#
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+#
+# forwarding fails when target does not support SMTPUTF8
+exim -bs -odi
+EHLO client.ffail
+MAIL FROM: <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> SMTPUTF8
+RCPT TO: <userz@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+#
+#
+killdaemon
+#
+exim -qfl
+****
+#
+#
+#
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# Recipient verify callout, pass
+exim -bs -odi -DCONTROL="verify=recipient/callout"
+EHLO client.bh
+MAIL FROM: <세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> SMTPUTF8
+RCPT TO: <userQ@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+# Recipient+random verify callout, pass
+exim -bs -odi -DCONTROL="verify=recipient/callout=random"
+EHLO client.bh
+MAIL FROM: <세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> SMTPUTF8
+RCPT TO: <userR@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+#
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+#
+# Recipient verify callout, fail
+exim -bs -odi -DCONTROL="verify=recipient/callout"
+EHLO client.ffail
+MAIL FROM: <CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> SMTPUTF8
+RCPT TO: <userS@test.ex>
+QUIT
+****
+#
+# Recipient+random verify callout, fail
+exim -bs -odi -DCONTROL="verify=recipient/callout=random"
+EHLO client.ffail
+MAIL FROM: <CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> SMTPUTF8
+RCPT TO: <userT@test.ex>
+QUIT
+****
+#
+killdaemon
+#
+#
+#
+#
+#
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# utf-8 to, -bs input and forwarding
+exim -bs -odi
+EHLO client.bh
+MAIL FROM: <userU@test.ex> SMTPUTF8
+RCPT TO: <user.γλυκύρριζα@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# sender verify callout, pass
+exim -bs -odi -DCONTROL="verify=sender/callout"
+EHLO client.bh
+MAIL FROM: <userV.වැල්_මී@test.ex> SMTPUTF8
+RCPT TO: <user.அதிமதுரம்@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+# sender+random verify callout, pass
+exim -bs -odi -DCONTROL="verify=sender/callout=random"
+EHLO client.bh
+MAIL FROM: <userW@test.ex> SMTPUTF8
+RCPT TO: <user.ഇരട്ടിമധുരം@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+# sender verify callout, fail
+exim -bs -odi -DCONTROL="verify=sender/callout"
+EHLO client.sfail
+MAIL FROM: <userA@test.ex> SMTPUTF8
+RCPT TO: <user.यष्टिमधु@test.ex>
+QUIT
+****
+# sender+random verify callout, fail
+exim -bs -odi -DCONTROL="verify=sender/callout=random"
+EHLO client.sfail
+MAIL FROM: <userB.જેઠીમધ@test.ex> SMTPUTF8
+RCPT TO: <user.ქართული@test.ex>
+QUIT
+****
+#
+killdaemon
diff --git a/test/scripts/4210-GnuTLS-International/REQUIRES b/test/scripts/4210-GnuTLS-International/REQUIRES
new file mode 100644
index 000000000..d75e95074
--- /dev/null
+++ b/test/scripts/4210-GnuTLS-International/REQUIRES
@@ -0,0 +1,2 @@
+support Experimental_International
+support GnuTLS
diff --git a/test/scripts/4220-OpenSSL-International/4221 b/test/scripts/4220-OpenSSL-International/4221
new file mode 100644
index 000000000..e06ecd339
--- /dev/null
+++ b/test/scripts/4220-OpenSSL-International/4221
@@ -0,0 +1,245 @@
+# Internationalised mail: smtp
+# Exim test configuration 4200
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+#
+# Basic smtp input, no delivery
+client 127.0.0.1 PORT_D
+??? 220
+EHLO client
+??? 250-
+??? 250-SIZE
+??? 250-8BITMIME
+??? 250-PIPELINING
+??? 250-STARTTLS
+??? 250-SMTPUTF8
+??? 250 HELP
+MAIL FROM: <someone@some.domain> SMTPUTF8
+??? 250
+RCPT TO: <userx@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+# utf-8 from, Basic smtp input, no delivery
+client 127.0.0.1 PORT_D
+??? 220
+EHLO client
+??? 250-
+??? 250-SIZE
+??? 250-8BITMIME
+??? 250-PIPELINING
+??? 250-STARTTLS
+??? 250-SMTPUTF8
+??? 250 HELP
+MAIL FROM: <ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com> SMTPUTF8
+??? 250
+RCPT TO: <userx@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+# utf-8 from, -bs input and forwarding
+exim -bs -odi
+EHLO client.bh
+MAIL FROM: <他们为什么不说中文@hebrew.למההםפשוטלאמדבריםעברית.com> SMTPUTF8
+RCPT TO: <usery@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+#
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+#
+# forwarding fails when target does not support SMTPUTF8
+exim -bs -odi
+EHLO client.ffail
+MAIL FROM: <यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> SMTPUTF8
+RCPT TO: <userz@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+#
+#
+killdaemon
+#
+exim -qfl
+****
+#
+#
+#
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# Recipient verify callout, pass
+exim -bs -odi -DCONTROL="verify=recipient/callout"
+EHLO client.bh
+MAIL FROM: <세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> SMTPUTF8
+RCPT TO: <userQ@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+# Recipient+random verify callout, pass
+exim -bs -odi -DCONTROL="verify=recipient/callout=random"
+EHLO client.bh
+MAIL FROM: <세계의모든사람들이한국어를이해한다면얼마나좋을까@russian.почемужеонинеговорятпорусски.com> SMTPUTF8
+RCPT TO: <userR@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+#
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+#
+# Recipient verify callout, fail
+exim -bs -odi -DCONTROL="verify=recipient/callout"
+EHLO client.ffail
+MAIL FROM: <CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> SMTPUTF8
+RCPT TO: <userS@test.ex>
+QUIT
+****
+#
+# Recipient+random verify callout, fail
+exim -bs -odi -DCONTROL="verify=recipient/callout=random"
+EHLO client.ffail
+MAIL FROM: <CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> SMTPUTF8
+RCPT TO: <userT@test.ex>
+QUIT
+****
+#
+killdaemon
+#
+#
+#
+#
+#
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# utf-8 to, -bs input and forwarding
+exim -bs -odi
+EHLO client.bh
+MAIL FROM: <userU@test.ex> SMTPUTF8
+RCPT TO: <user.γλυκύρριζα@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# sender verify callout, pass
+exim -bs -odi -DCONTROL="verify=sender/callout"
+EHLO client.bh
+MAIL FROM: <userV.වැල්_මී@test.ex> SMTPUTF8
+RCPT TO: <user.அதிமதுரம்@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+# sender+random verify callout, pass
+exim -bs -odi -DCONTROL="verify=sender/callout=random"
+EHLO client.bh
+MAIL FROM: <userW@test.ex> SMTPUTF8
+RCPT TO: <user.ഇരട്ടിമധുരം@test.ex>
+DATA
+Subject: test
+
+body
+.
+QUIT
+****
+#
+killdaemon
+exim -DSERVER=server -qqff
+****
+#
+#
+#
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+# sender verify callout, fail
+exim -bs -odi -DCONTROL="verify=sender/callout"
+EHLO client.sfail
+MAIL FROM: <userA@test.ex> SMTPUTF8
+RCPT TO: <user.यष्टिमधु@test.ex>
+QUIT
+****
+# sender+random verify callout, fail
+exim -bs -odi -DCONTROL="verify=sender/callout=random"
+EHLO client.sfail
+MAIL FROM: <userB.જેઠીમધ@test.ex> SMTPUTF8
+RCPT TO: <user.ქართული@test.ex>
+QUIT
+****
+#
+killdaemon
diff --git a/test/scripts/4220-OpenSSL-International/REQUIRES b/test/scripts/4220-OpenSSL-International/REQUIRES
new file mode 100644
index 000000000..74b249f4c
--- /dev/null
+++ b/test/scripts/4220-OpenSSL-International/REQUIRES
@@ -0,0 +1,2 @@
+support Experimental_International
+support OpenSSL
diff --git a/test/stderr/0275 b/test/stderr/0275
index a634ad530..bb642b01b 100644
--- a/test/stderr/0275
+++ b/test/stderr/0275
@@ -341,7 +341,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/0278 b/test/stderr/0278
index 062aaaff6..fd5795b04 100644
--- a/test/stderr/0278
+++ b/test/stderr/0278
@@ -243,7 +243,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: CALLER@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/0361 b/test/stderr/0361
index 5b93c6e9c..43bcdbf84 100644
--- a/test/stderr/0361
+++ b/test/stderr/0361
@@ -240,7 +240,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: kilos@recurse.test.ex.test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r3
DSN: processing successful delivery address: kilos@recurse.test.ex.test.ex
DSN: Sender_address: CALLER@test.ex
@@ -248,7 +248,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: kilos@recurse.test.ex.test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaY-0005vi-00
diff --git a/test/stderr/0386 b/test/stderr/0386
index 086297cf1..3232ada03 100644
--- a/test/stderr/0386
+++ b/test/stderr/0386
@@ -329,7 +329,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: 2@b
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
@@ -505,7 +505,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: 2@b
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaY-0005vi-00
diff --git a/test/stderr/0402 b/test/stderr/0402
index ec373f5fe..c0a03d3ee 100644
--- a/test/stderr/0402
+++ b/test/stderr/0402
@@ -568,7 +568,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userz@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r2
DSN: processing successful delivery address: usery@test.ex
DSN: Sender_address: CALLER@test.ex
@@ -576,7 +576,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: usery@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r1
DSN: processing successful delivery address: CALLER@test.ex
DSN: Sender_address: CALLER@test.ex
@@ -584,7 +584,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: CALLER@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r4
DSN: processing successful delivery address: TESTSUITE/test-mail/junk
DSN: Sender_address: CALLER@test.ex
@@ -592,7 +592,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: TESTSUITE/test-mail/junk
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r5
DSN: processing successful delivery address: TESTSUITE/test-mail/junk
DSN: Sender_address: CALLER@test.ex
@@ -600,7 +600,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: TESTSUITE/test-mail/junk
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r4
DSN: processing successful delivery address: rd+CALLER@test.ex
DSN: Sender_address: CALLER@test.ex
@@ -608,7 +608,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: rd+CALLER@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r5
DSN: processing successful delivery address: rd+usery@test.ex
DSN: Sender_address: CALLER@test.ex
@@ -616,7 +616,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: rd+usery@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/0403 b/test/stderr/0403
index 27b209df2..96e990bfd 100644
--- a/test/stderr/0403
+++ b/test/stderr/0403
@@ -191,7 +191,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: TESTSUITE/test-mail/junk
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r1
DSN: processing successful delivery address: userx@test.ex
DSN: Sender_address: CALLER@test.ex
@@ -199,7 +199,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/0404 b/test/stderr/0404
index 9d04fe58a..1f791c416 100644
--- a/test/stderr/0404
+++ b/test/stderr/0404
@@ -18020,7 +18020,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: sender@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaY-0005vi-00
@@ -18057,7 +18057,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: >sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ...
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r2
DSN: processing successful delivery address: userx@test.ex
DSN: Sender_address: CALLER@test.ex
@@ -18065,7 +18065,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/0408 b/test/stderr/0408
index f578e30c1..67fe44cb5 100644
--- a/test/stderr/0408
+++ b/test/stderr/0408
@@ -181,7 +181,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/0487 b/test/stderr/0487
index e3217abe2..c8d720beb 100644
--- a/test/stderr/0487
+++ b/test/stderr/0487
@@ -184,7 +184,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/2600 b/test/stderr/2600
index 8c0bdb080..cc1864aa2 100644
--- a/test/stderr/2600
+++ b/test/stderr/2600
@@ -457,7 +457,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@myhost.test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/5004 b/test/stderr/5004
index f8d86b750..501488711 100644
--- a/test/stderr/5004
+++ b/test/stderr/5004
@@ -181,7 +181,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: TESTSUITE/test-mail
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
DSN: processing router : r1
DSN: processing successful delivery address: userx@test.ex
DSN: Sender_address: CALLER@test.ex
@@ -189,7 +189,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stderr/5005 b/test/stderr/5005
index 8a9536a34..ae0dbba0b 100644
--- a/test/stderr/5005
+++ b/test/stderr/5005
@@ -173,7 +173,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: nofile@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
@@ -357,7 +357,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaY-0005vi-00
diff --git a/test/stderr/5006 b/test/stderr/5006
index 72b650fbf..9df6ced95 100644
--- a/test/stderr/5006
+++ b/test/stderr/5006
@@ -171,7 +171,7 @@ DSN: orcpt: NULL flags: 0
DSN: envid: NULL ret: 0
DSN: Final recipient: userx@test.ex
DSN: Remote SMTP server supports DSN: 0
-DSN: *** NOT SENDING DSN SUCCESS Message ***
+DSN: not sending DSN success message
LOG: MAIN
Completed
end delivery of 10HmaX-0005vi-00
diff --git a/test/stdout/0405 b/test/stdout/0405
index 6b561f74f..f5b5dce41 100644
--- a/test/stdout/0405
+++ b/test/stdout/0405
@@ -1,4 +1,5 @@
syntax error: domain missing or malformed
-bounce@π.test.ex
+bounce@xn--1xa.test.ex
+ <-- bounce@π.test.ex
router = r1, transport = t1
- host mx.π.test.ex [V4NET.255.255.255] MX=0
+ host mx.xn--1xa.test.ex [V4NET.255.255.255] MX=0
diff --git a/test/stdout/4200 b/test/stdout/4200
new file mode 100644
index 000000000..1cfb7a9db
--- /dev/null
+++ b/test/stdout/4200
@@ -0,0 +1,69 @@
+>
+> utf-8 localpart to a-label:
+>
+> xn--ghb
+> xn--ghb
+>
+> xn--egbpdaj6bu4bxfgehfvwxn
+> xn--egbpdaj6bu4bxfgehfvwxn
+>
+> a-label localpart to utf-8:
+>
+> ل
+> ليهمابتكلموشعربي؟
+>
+> utf-8 domain to a-label:
+>
+> bogus.xn--ghb.com
+> bogus.xn--ghb.com
+>
+> arabic.xn--egbpdaj6bu4bxfgehfvwxn.com
+> arabic.xn--egbpdaj6bu4bxfgehfvwxn.com
+>
+> simpl.chinese.xn--ihqwcrb4cv8a8dqg056pqjye.com
+> simpl.chinese.xn--ihqwcrb4cv8a8dqg056pqjye.com
+>
+> trad.chinese.xn--ihqwctvzc91f659drss3x8bo0yb.com
+> trad.chinese.xn--ihqwctvzc91f659drss3x8bo0yb.com
+>
+> czech.xn--proprostnemluvesky-uyb24dma41a.com
+> czech.xn--Proprostnemluvesky-uyb24dma41a.com
+>
+> hebrew.xn--4dbcagdahymbxekheh6e0a7fei0b.com
+> hebrew.xn--4dbcagdahymbxekheh6e0a7fei0b.com
+>
+> hindi.xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd.com
+> hindi.xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd.com
+>
+> japanese.xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa.com
+> japanese.xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa.com
+>
+> # the a-label for the phrase in korean is too long for a domain label (63 byte limit)
+> korean: xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c
+> korean: xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c
+>
+> russian.xn--b1abfaaepdrnnbgefbadotcwatmq2g4l.com
+> russian.xn--b1abfaaepdrnnbgefbaDotcwatmq2g4l.com
+>
+> spanish.xn--porqunopuedensimplementehablarenespaol-fmd56a.com
+> spanish.xn--PorqunopuedensimplementehablarenEspaol-fmd56a.com
+>
+> vietnamese.xn--tisaohkhngthchnitingvit-kjcr8268qyxafd2f1b9g.com
+> vietnamese.xn--TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g.com
+>
+> a-label domain to utf-8:
+>
+> arab.ل.com
+> arab.ليهمابتكلموشعربي؟.com
+> simpl.chinese.他们为什么不说中文.com
+> trad.chinese.他們爲什麽不說中文.com
+> czech.Pročprostěnemluvíčesky.com
+> hebrew.למההםפשוטלאמדבריםעברית.com
+> hindi.यहलोगहिन्दीक्योंनहींबोलसकतेहैं.com
+> japanese.なぜみんな日本語を話してくれないのか.com
+> korean: 세계의모든사람들이한국어를이해한다면얼마나좋을까
+> russian.почемужеонинеговорятпорусски.com
+> spanish.PorquénopuedensimplementehablarenEspañol.com
+> vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.com
+>
+>
diff --git a/test/stdout/4201 b/test/stdout/4201
new file mode 100644
index 000000000..2baa6661c
--- /dev/null
+++ b/test/stdout/4201
@@ -0,0 +1,208 @@
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO client
+??? 250-
+<<< 250-the.local.host.name Hello client [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-SMTPUTF8
+<<< 250-SMTPUTF8
+??? 250 HELP
+<<< 250 HELP
+>>> MAIL FROM: <someone@some.domain> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>>
+>>> body
+>>> .
+??? 250
+<<< 250 OK id=10HmaX-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO client
+??? 250-
+<<< 250-the.local.host.name Hello client [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-SMTPUTF8
+<<< 250-SMTPUTF8
+??? 250 HELP
+<<< 250 HELP
+>>> MAIL FROM: <ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>>
+>>> body
+>>> .
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaZ-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbH-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbJ-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbL-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+533 mailbox name not allowed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+533 mailbox name not allowed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbN-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbP-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbR-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.sfail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+550-Callback setup failed while verifying <userA@test.ex>
+550-533 mailbox name not allowed
+550-The initial connection, or a HELO or MAIL FROM:<> command was
+550-rejected. Refusing MAIL FROM:<> does not help fight spam, disregards
+550-RFC requirements, and stops you from receiving standard bounce
+550-messages. This host does not accept mail from domains whose servers
+550-refuse bounces.
+550 Sender verify failed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.sfail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-SMTPUTF8
+250 HELP
+250 OK
+550-Callback setup failed while verifying <userB.જેઠીમધ@test.ex>
+550-533 mailbox name not allowed
+550-The initial connection, or a HELO or MAIL FROM:<> command was
+550-rejected. Refusing MAIL FROM:<> does not help fight spam, disregards
+550-RFC requirements, and stops you from receiving standard bounce
+550-messages. This host does not accept mail from domains whose servers
+550-refuse bounces.
+550 Sender verify failed
+221 the.local.host.name closing connection
diff --git a/test/stdout/4211 b/test/stdout/4211
new file mode 100644
index 000000000..18eec3215
--- /dev/null
+++ b/test/stdout/4211
@@ -0,0 +1,223 @@
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO client
+??? 250-
+<<< 250-the.local.host.name Hello client [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-STARTTLS
+<<< 250-STARTTLS
+??? 250-SMTPUTF8
+<<< 250-SMTPUTF8
+??? 250 HELP
+<<< 250 HELP
+>>> MAIL FROM: <someone@some.domain> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>>
+>>> body
+>>> .
+??? 250
+<<< 250 OK id=10HmaX-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO client
+??? 250-
+<<< 250-the.local.host.name Hello client [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-STARTTLS
+<<< 250-STARTTLS
+??? 250-SMTPUTF8
+<<< 250-SMTPUTF8
+??? 250 HELP
+<<< 250 HELP
+>>> MAIL FROM: <ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>>
+>>> body
+>>> .
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaZ-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbB-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbD-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbF-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+533 mailbox name not allowed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+533 mailbox name not allowed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbH-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbJ-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbL-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.sfail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+550-Callback setup failed while verifying <userA@test.ex>
+550-533 mailbox name not allowed
+550-The initial connection, or a HELO or MAIL FROM:<> command was
+550-rejected. Refusing MAIL FROM:<> does not help fight spam, disregards
+550-RFC requirements, and stops you from receiving standard bounce
+550-messages. This host does not accept mail from domains whose servers
+550-refuse bounces.
+550 Sender verify failed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.sfail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+550-Callback setup failed while verifying <userB.જેઠીમધ@test.ex>
+550-533 mailbox name not allowed
+550-The initial connection, or a HELO or MAIL FROM:<> command was
+550-rejected. Refusing MAIL FROM:<> does not help fight spam, disregards
+550-RFC requirements, and stops you from receiving standard bounce
+550-messages. This host does not accept mail from domains whose servers
+550-refuse bounces.
+550 Sender verify failed
+221 the.local.host.name closing connection
diff --git a/test/stdout/4221 b/test/stdout/4221
new file mode 100644
index 000000000..18eec3215
--- /dev/null
+++ b/test/stdout/4221
@@ -0,0 +1,223 @@
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO client
+??? 250-
+<<< 250-the.local.host.name Hello client [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-STARTTLS
+<<< 250-STARTTLS
+??? 250-SMTPUTF8
+<<< 250-SMTPUTF8
+??? 250 HELP
+<<< 250 HELP
+>>> MAIL FROM: <someone@some.domain> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>>
+>>> body
+>>> .
+??? 250
+<<< 250 OK id=10HmaX-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO client
+??? 250-
+<<< 250-the.local.host.name Hello client [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-STARTTLS
+<<< 250-STARTTLS
+??? 250-SMTPUTF8
+<<< 250-SMTPUTF8
+??? 250 HELP
+<<< 250 HELP
+>>> MAIL FROM: <ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>>
+>>> body
+>>> .
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaZ-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbB-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbD-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbF-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+533 mailbox name not allowed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.ffail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+533 mailbox name not allowed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbH-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbJ-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.bh
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbL-0005vi-00
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.sfail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+550-Callback setup failed while verifying <userA@test.ex>
+550-533 mailbox name not allowed
+550-The initial connection, or a HELO or MAIL FROM:<> command was
+550-rejected. Refusing MAIL FROM:<> does not help fight spam, disregards
+550-RFC requirements, and stops you from receiving standard bounce
+550-messages. This host does not accept mail from domains whose servers
+550-refuse bounces.
+550 Sender verify failed
+221 the.local.host.name closing connection
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-the.local.host.name Hello CALLER at client.sfail
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-STARTTLS
+250-SMTPUTF8
+250 HELP
+250 OK
+550-Callback setup failed while verifying <userB.જેઠીમધ@test.ex>
+550-533 mailbox name not allowed
+550-The initial connection, or a HELO or MAIL FROM:<> command was
+550-rejected. Refusing MAIL FROM:<> does not help fight spam, disregards
+550-RFC requirements, and stops you from receiving standard bounce
+550-messages. This host does not accept mail from domains whose servers
+550-refuse bounces.
+550 Sender verify failed
+221 the.local.host.name closing connection