<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">diff --git Makefile Makefile
index 1c31ebb..2db9cfb 100644
--- Makefile
+++ Makefile
@@ -1447,7 +1447,7 @@ substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
 	tls.o ssl_timeoutio.o -L/usr/local/ssl/lib -lssl -lcrypto \
 	ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
 	lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
-	str.a fs.a auto_qmail.o  `cat dns.lib` `cat socket.lib`
+	str.a fs.a auto_qmail.o  `cat dns.lib` `cat socket.lib` -lidn2
 
 qmail-remote.0: \
 qmail-remote.8
diff --git qmail-remote.c qmail-remote.c
index c8746bf..f58111c 100644
--- qmail-remote.c
+++ qmail-remote.c
@@ -2,6 +2,7 @@
 #include &lt;sys/socket.h&gt;
 #include &lt;netinet/in.h&gt;
 #include &lt;arpa/inet.h&gt;
+#include &lt;idn2.h&gt;
 #include "sig.h"
 #include "stralloc.h"
 #include "substdio.h"
@@ -42,7 +43,9 @@ stralloc helohost = {0};
 stralloc routes = {0};
 struct constmap maproutes;
 stralloc host = {0};
+stralloc asciihost = {0};
 stralloc sender = {0};
+int smtputf8 = 0;
 
 saa reciplist = {0};
 
@@ -156,6 +159,7 @@ char smtpfrombuf[128];
 substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf);
 
 stralloc smtptext = {0};
+stralloc firstpart = {0};
 
 void get(ch)
 char *ch;
@@ -308,6 +312,8 @@ void blast()
   int r;
   char ch;
 
+  substdio_put(&amp;smtpto,firstpart.s,firstpart.len);
+
   for (;;) {
     r = substdio_get(&amp;ssin,&amp;ch,1);
     if (r == 0) break;
@@ -530,6 +536,102 @@ int tls_init()
 
 stralloc recip = {0};
 
+int containsutf8(p, l) unsigned char * p; int l;
+{
+  int i = 0;
+  while (i&lt;l)
+    if(p[i++] &gt; 127) return 1;
+  return 0;
+}
+
+int utf8message;
+
+void checkutf8message()
+{
+  int pos;
+  int i;
+  int r;
+  char ch;
+  int state;
+
+  if (containsutf8(sender.s, sender.len)) { utf8message = 1; return; }
+  for (i = 0;i &lt; reciplist.len;++i)
+    if (containsutf8(reciplist.sa[i].s, reciplist.sa[i].len)) {
+      utf8message = 1;
+      return;
+    }
+
+  state = 0;
+  pos = 0;
+  for (;;) {
+    r = substdio_get(&amp;ssin,&amp;ch,1);
+    if (r == 0) break;
+    if (r == -1) temp_read();
+
+    if (ch == '\n' &amp;&amp; !stralloc_cats(&amp;firstpart,"\r")) temp_nomem();
+    if (!stralloc_append(&amp;firstpart,&amp;ch)) temp_nomem();
+
+    if (ch == '\r')
+      continue;
+    if (ch == '\t')
+      ch = ' ';
+
+    switch (state) {
+    case 6: /* in Received, at LF but before WITH clause */
+      if (ch == ' ') { state = 3; pos = 1; continue; }
+      state = 0;
+      /* FALL THROUGH */
+
+    case 0: /* start of header field */
+      if (ch == '\n') return;
+      state = 1;
+      pos = 0;
+      /* FALL THROUGH */
+
+    case 1: /* partway through "Received:" */
+      if (ch != "RECEIVED:"[pos] &amp;&amp; ch != "received:"[pos]) { state = 2; continue; }
+      if (++pos == 9) { state = 3; pos = 0; }
+      continue;
+
+    case 2: /* other header field */
+      if (ch == '\n') state = 0;
+      continue;
+
+    case 3: /* in Received, before WITH clause or partway though " with " */
+      if (ch == '\n') { state = 6; continue; }
+      if (ch != " WITH "[pos] &amp;&amp; ch != " with "[pos]) { pos = 0; continue; }
+      if (++pos == 6) { state = 4; pos = 0; }
+      continue;
+
+    case 4: /* in Received, having seen with, before the argument */
+      if (pos == 0 &amp;&amp; (ch == ' ' || ch == '\t')) continue;
+      if (ch != "UTF8"[pos] &amp;&amp; ch != "utf8"[pos]) { state = 5; continue; }
+      if(++pos == 4) { utf8message = 1; state = 5; continue; }
+      continue;
+
+    case 5: /* after the RECEIVED WITH argument */
+      /* blast() assumes that it copies whole lines */
+      if (ch == '\n') return;
+      state = 1;
+      pos = 0;
+      continue;
+    }
+  }
+}
+
+void checkutf8server()
+{
+  stralloc *sa;
+  unsigned int len;
+
+  sa = ehlokw.sa;
+  len = ehlokw.len;
+
+  for (; len &amp;&amp; case_diffs(sa-&gt;s, "SMTPUTF8"); ++sa, --len);
+
+  if (len) smtputf8 = 1;
+}
+
 void smtp()
 {
   unsigned long code;
@@ -583,9 +685,15 @@ void smtp()
   }
 #endif
  
+  checkutf8message();
+  checkutf8server();
+  if (utf8message &amp;&amp; !smtputf8) quit("DConnected to "," but server does not support unicode in email addresses");
+
   substdio_puts(&amp;smtpto,"MAIL FROM:&lt;");
   substdio_put(&amp;smtpto,sender.s,sender.len);
-  substdio_puts(&amp;smtpto,"&gt;\r\n");
+  substdio_puts(&amp;smtpto,"&gt;");
+  if (utf8message) substdio_puts(&amp;smtpto," SMTPUTF8");
+  substdio_puts(&amp;smtpto,"\r\n");
   substdio_flush(&amp;smtpto);
   code = smtpcode();
   if (code &gt;= 500) quit("DConnected to "," but sender was rejected");
@@ -714,6 +822,15 @@ char **argv;
       relayhost[i] = 0;
     }
     if (!stralloc_copys(&amp;host,relayhost)) temp_nomem();
+  } else {
+    char * ascii = 0;
+    host.s[host.len] = '\0';
+    switch (idn2_lookup_u8(host.s, (uint8_t**)&amp;ascii, IDN2_NFC_INPUT)) {
+      case IDN2_OK: break;
+      case IDN2_MALLOC: temp_nomem();
+      default: perm_dns();
+    }
+    if (!stralloc_copys(&amp;asciihost, ascii)) temp_nomem();
   }
 
 
@@ -735,7 +852,7 @@ char **argv;
 
  
   random = now() + (getpid() &lt;&lt; 16);
-  switch (relayhost ? dns_ip(&amp;ip,&amp;host) : dns_mxip(&amp;ip,&amp;host,random)) {
+  switch (relayhost ? dns_ip(&amp;ip,&amp;host) : dns_mxip(&amp;ip,&amp;asciihost,random)) {
     case DNS_MEM: temp_nomem();
     case DNS_SOFT: temp_dns();
     case DNS_HARD: perm_dns();
diff --git qmail-smtpd.c qmail-smtpd.c
index 23f7e3d..edc62cd 100644
--- qmail-smtpd.c
+++ qmail-smtpd.c
@@ -226,6 +226,28 @@ int flagbarf; /* defined if seenmail */
 int allowed;
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
+stralloc mfparms = {0};
+int smtputf8 = 0;
+
+void mailfrom_parms(arg) char *arg;
+{
+  int i;
+  int len;
+
+  len = str_len(arg);
+  if (!stralloc_copys(&amp;mfparms,"")) die_nomem();
+  i = byte_chr(arg,len,'&gt;');
+  if (i &gt; 4 &amp;&amp; i &lt; len) {
+    while (len) {
+      arg++; len--;
+      if (*arg == ' ' || *arg == '\0' ) {
+         if (case_starts(mfparms.s,"SMTPUTF8")) smtputf8 = 1;
+      }
+      else
+        if (!stralloc_catb(&amp;mfparms,arg,1)) die_nomem();
+    }
+  }
+}
 
 void smtp_helo(arg) char *arg;
 {
@@ -236,7 +258,7 @@ void smtp_helo(arg) char *arg;
 void smtp_ehlo(arg) char *arg;
 {
   if(!spp_helo(arg)) return;
-  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250-SMTPUTF8\r\n250 8BITMIME\r\n");
   seenmail = 0; dohelo(arg);
 }
 void smtp_rset(arg) char *arg;
@@ -251,6 +273,7 @@ void smtp_mail(arg) char *arg;
   if (!(spp_val = spp_mail())) return;
   if (spp_val == 1)
   flagbarf = bmfcheck();
+  mailfrom_parms(arg);
   seenmail = 1;
   if (!stralloc_copys(&amp;rcptto,"")) die_nomem();
   if (!stralloc_copys(&amp;mailfrom,addr.s)) die_nomem();
@@ -394,7 +417,7 @@ void smtp_data(arg) char *arg; {
   qp = qmail_qp(&amp;qqt);
   out("354 go ahead\r\n");
  
-  received(&amp;qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
+  received(&amp;qqt,smtputf8 ? "UTF8SMTP" : "SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
   qmail_put(&amp;qqt,sppheaders.s,sppheaders.len); /* set in qmail-spp.c */
   spp_rset();
   blast(&amp;hops);
</pre></body></html>