[exim-cvs] smtp input

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] smtp input
Gitweb: http://git.exim.org/exim.git/commitdiff/9d4319dfec653f43b64562c8f31b87f2890365b2
Commit:     9d4319dfec653f43b64562c8f31b87f2890365b2
Parent:     4e08fd50ebe820edb008a96b892a2749bbe8e72b
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Sun Apr 12 19:18:26 2015 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Sun Apr 12 19:18:26 2015 +0100


    smtp input
---
 TODO                                 |   14 +++--
 doc/doc-txt/experimental-spec.txt    |   15 ++++++
 src/src/dns.c                        |   17 ++++++
 src/src/exim.c                       |    4 ++
 src/src/functions.h                  |    1 +
 src/src/globals.c                    |    2 +-
 src/src/parse.c                      |   10 +---
 src/src/smtp_in.c                    |   90 ++++++++++++++++++---------------
 src/src/utf8.c                       |   10 +---
 test/confs/4201                      |   60 ++++++++++++++++++++++
 test/log/4201                        |    9 +++
 test/runtest                         |    6 ++-
 test/scripts/4200-International/4201 |   64 ++++++++++++++++++++++++
 test/stdout/4201                     |   70 ++++++++++++++++++++++++++
 14 files changed, 308 insertions(+), 64 deletions(-)


diff --git a/TODO b/TODO
index d2d31ef..6cce9a6 100644
--- a/TODO
+++ b/TODO
@@ -15,23 +15,25 @@ destination supports the SMTPUTF8 extension
======================

to-Alabel convert of helo name
+- smtp transport

++ An "international" flag on the message?
++ An is-international expansion condition?

 ++ helo-time option handling
-conversion of utf-8 domains on input    rfc5890
-- deconversion on forwarding
-- deconversion for trace headers
+++ conversion of utf-8 domains for DNS    rfc5890
+-- MSA mode: convert on forward?
+
 dsn handling                rfc6533
 logging
 - international msg
 - presentation of local-part in log
 -- a log option?
 encoding of local_part
-encoding transform string-expansions
+
 Recieved-by header tracking info
 - WITH protocol types get UTF8 prefix
+- use for logging also


 forwarding checks            rfc6530 7.1 -3-
 - rcpt-time rejects get 533 mailbox name not allowed
@@ -39,9 +41,11 @@ forwarding checks            rfc6530 7.1 -3-
 - bounces (see dsn handling)



-expansions for to- and from-Alabel ?    bug1567
+++ expansions for to- and from-Alabel ?    bug1567


 enhanced status codes?            rfc5248++


VRFY
EXPN
+
+non-smtp input
diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt
index 738f02c..59dd44e 100644
--- a/doc/doc-txt/experimental-spec.txt
+++ b/doc/doc-txt/experimental-spec.txt
@@ -1278,6 +1278,21 @@ RFCs 6530, 6533, 5890

Compile with EXPERIMENTAL_INTERNATIONAL and libidn.

+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, but all DNS lookups are converted to a-label form.
+
+Log lines and Received-by: header lines will aquire a "utf8"
+prefix on the 'with' element, eg. utf8esmtp.
+
 Expansion operators:
     ${utf8_domain_to_alabel:str}
     ${utf8_domain_from_alabel:str}
diff --git a/src/src/dns.c b/src/src/dns.c
index a2f4309..f1619f4 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", 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 f6d9be6..121c6c2 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -3705,6 +3705,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. */
diff --git a/src/src/functions.h b/src/src/functions.h
index ac93c16..fdd6292 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -422,6 +422,7 @@ 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_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 **);
diff --git a/src/src/globals.c b/src/src/globals.c
index cb93a01..2cbafcd 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -1274,7 +1274,7 @@ int     smtp_rlr_threshold     = INT_MAX;
 BOOL    smtp_use_pipelining    = FALSE;
 BOOL    smtp_use_size          = FALSE;
 #ifdef EXPERIMENTAL_INTERNATIONAL
-uschar *smtputf8_advertise_hosts = US"*";
+uschar *smtputf8_advertise_hosts = US"*";    /* overridden under test-harness */
 #endif


 #ifdef WITH_CONTENT_SCAN
diff --git a/src/src/parse.c b/src/src/parse.c
index ff814e7..a648f75 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;
 }


@@ -744,7 +740,7 @@ if (*s == '<')
   while (bracket_count-- > 0) if (*s++ != '>')
     {
     *errorptr = (s[-1] == 0)? US"'>' missing at end of address" :
-      string_sprintf("malformed address: %.32s may not follow %.*s",
+      string_sprintf("malformed address A: %.32s may not follow %.*s",
         s-1, s - (uschar *)mailbox - 1, mailbox);
     goto PARSE_FAILED;
     }
@@ -797,7 +793,7 @@ if (*s != 0)
     }
   else
     {
-    *errorptr = string_sprintf("malformed address: %.32s may not follow %.*s",
+    *errorptr = string_sprintf("malformed address B: %.32s may not follow %.*s",
       s, s - (uschar *)mailbox, mailbox);
     goto PARSE_FAILED;
     }
@@ -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/smtp_in.c b/src/src/smtp_in.c
index 8086e94..a0e44d8 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -3828,10 +3828,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;


@@ -3859,16 +3857,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;
           }
@@ -3880,35 +3879,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
@@ -3948,34 +3955,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;
@@ -3990,7 +3997,7 @@ while (done <= 0)
 #ifdef EXPERIMENTAL_INTERNATIONAL
         case ENV_MAIL_OPT_UTF8:
       if (smtputf8_advertised)
-        message_smtputf8 = TRUE;
+        message_smtputf8 = allow_utf8_domains = TRUE;
       break;
 #endif
         /* Unknown option. Stick back the terminator characters and break
@@ -4025,9 +4032,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 =
diff --git a/src/src/utf8.c b/src/src/utf8.c
index 9a2b865..32d2eae 100644
--- a/src/src/utf8.c
+++ b/src/src/utf8.c
@@ -78,9 +78,6 @@ size_t p_len = ucs4_len*4;    /* this multiplier is pure guesswork */
 uschar * res = store_get(p_len+5);
 int rc;


-DEBUG(D_expand) debug_printf("l_u2a: ulen %d plen %d\n", ucs4_len, p_len);
-DEBUG(D_expand) for (rc = 0; rc < ucs4_len; rc++) debug_printf("%08x ", p[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)
@@ -90,10 +87,7 @@ if ((rc = punycode_encode(ucs4_len, p, NULL, &p_len, res+4)) != PUNYCODE_SUCCESS
if (err) *err = US punycode_strerror(rc);
return NULL;
}
-DEBUG(D_expand) debug_printf("l_u2a: plen %d\n", p_len);
p_len += 4;
-DEBUG(D_expand) for (rc = 0; rc < p_len; rc++) debug_printf("%02x ", res[rc]);
-DEBUG(D_expand) debug_printf("\n");
free(p);
res[p_len] = '\0';
return res;
@@ -114,9 +108,8 @@ if (alabel[0] != 'x' || alabel[1] != 'n' || alabel[2] != '-' || alabel[3] != '-'
if (err) *err = US"bad alabel prefix";
return NULL;
}
-p_len -= 4;
-DEBUG(D_expand) debug_printf("l_a2u: plen %d\n", p_len);

+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)
@@ -124,7 +117,6 @@ if ((rc = punycode_decode(p_len, CCS alabel+4, &p_len, p, NULL)) != PUNYCODE_SUC
if (err) *err = US punycode_strerror(rc);
return NULL;
}
-DEBUG(D_expand) debug_printf("l_a2u: dlen %d\n", p_len);

 s = stringprep_ucs4_to_utf8(p, p_len, NULL, &p_len);
 res = string_copyn(s, p_len);
diff --git a/test/confs/4201 b/test/confs/4201
new file mode 100644
index 0000000..7d9af4b
--- /dev/null
+++ b/test/confs/4201
@@ -0,0 +1,60 @@
+# Exim test configuration 4201
+
+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
+
+acl_smtp_rcpt = check_recipient
+trusted_users = CALLER
+log_selector = +received_recipients
+
+queue_only
+queue_run_in_order
+
+smtputf8_advertise_hosts = *
+
+
+# ----- ACL -----
+
+begin acl
+
+check_recipient:
+  accept hosts = :
+  accept domains = +local_domains
+  deny   message = relay not permitted
+
+# ----- Routers -----
+
+begin routers
+
+fail_remote_domains:
+  driver = redirect
+  domains = ! +local_domains
+  data = :fail: unrouteable mail domain "$domain"
+
+localuser:
+  driver = redirect
+  data = :blackhole:
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+  driver = appendfile
+  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
+
+# End
diff --git a/test/log/4201 b/test/log/4201
new file mode 100644
index 0000000..29ce53d
--- /dev/null
+++ b/test/log/4201
@@ -0,0 +1,9 @@
+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@??? H=(client) [127.0.0.1] P=esmtp S=sss for userx@???
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= ليهمابتكلموشعربي؟@czech.Pročprostěnemluvíčesky.com H=(client) [127.0.0.1] P=esmtp S=sss for userx@???
+1999-03-02 09:44:33 Start queue run: pid=pppp -qq
+1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userx@???> R=localuser
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userx@???> R=localuser
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qq
diff --git a/test/runtest b/test/runtest
index 2baf2ca..43ae1d4 100755
--- a/test/runtest
+++ b/test/runtest
@@ -844,7 +844,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 +1010,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 +1029,8 @@ RESET_AFTER_EXTRA_LINE_READ:
                 /^Fixed never_users:/ ||
                 /^Size of off_t:/
                 );
+
+
       }


     next;
diff --git a/test/scripts/4200-International/4201 b/test/scripts/4200-International/4201
new file mode 100644
index 0000000..bac040f
--- /dev/null
+++ b/test/scripts/4200-International/4201
@@ -0,0 +1,64 @@
+# 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@???> SMTPUTF8
+??? 250
+RCPT TO: <userx@???>
+??? 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@???>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+killdaemon
+exim -DSERVER=server -qq
+****
+no_msglog_check
+
diff --git a/test/stdout/4201 b/test/stdout/4201
new file mode 100644
index 0000000..b37028d
--- /dev/null
+++ b/test/stdout/4201
@@ -0,0 +1,70 @@
+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@???> SMTPUTF8
+??? 250
+<<< 250 OK
+>>> RCPT TO: <userx@???>
+??? 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@???>
+??? 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