diff --git a/exec/bench/nettype.js b/exec/bench/nettype.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b1c05138ddc00184adb95368be53dc518aaefe7
--- /dev/null
+++ b/exec/bench/nettype.js
@@ -0,0 +1,60 @@
+load('sbbsdefs.js');
+
+function nettype(t)
+{
+	switch(Number(t)) {
+		case NET_NONE: return "none";
+		case NET_UNKNOWN: return "unknown";
+		case NET_INTERNET: return "Internet";
+		case NET_QWK: return "QWKnet";
+		case NET_FIDO: return "FidoNet";
+	}
+	return format("???(%s)", t);
+}
+
+var test = [];
+test[NET_NONE] = [
+	null,
+	undefined,
+	"",
+	" ",
+	"-",
+	" user@addr",
+	"user @host.name",
+	"user name@host.name",
+];
+
+test[NET_UNKNOWN] = [
+	"@user",
+	"user@addr ",
+];
+
+test[NET_INTERNET] = [
+	"user@192.168.1.2",
+	"user.name@1.2.3.4",
+	"user@host.name",
+	"user.name@host.name.tld",
+];
+
+test[NET_FIDO] = [
+	"user@1",
+	"user@1/2",
+	"user@1:2/3",
+	"user@1:2/3.4",
+	"user name @ 1:2/3",
+];
+
+test[NET_QWK] = [
+	"1@VERT",
+	"digital man@VERT",
+	"digital man @ VERT",
+];
+
+
+for(var t in test) {
+	for(var i in test[t]) {
+		var type = netaddr_type(test[t][i]);
+		if(type != t)
+			alert(format("'%s'", test[t][i]) + ' = ' + nettype(type) + ' != ' + nettype(t));
+	}
+}
diff --git a/exec/newuser.js b/exec/newuser.js
index a9e053ce655b90ea693fd4717d32f41eefe9d3d3..bfb633c24fa3b19540b68a61716d69bcbb62f509 100644
--- a/exec/newuser.js
+++ b/exec/newuser.js
@@ -142,7 +142,7 @@ function send_newuser_welcome_msg(fname)
 		subject: "Welcome to " + system.name + "!" 
 	};
 
-	msgtxt = msgtxt.replace(/@(\w+)@/, function (code) { return bbs.atcode(code); });
+	msgtxt = msgtxt.replace(/@(\w+)@/g, function (code) { return bbs.atcode(code.slice(1, -1)); });
 	var result = msgbase.save_msg(hdr, msgtxt);
 	if(!result)
 		log(LOG_ERR, "!ERROR " + msgbase.error + " saving mail message");
diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c
index 39c317fe885d2e1c92ba9db33d3e74fa34c52335..038b7b6bee9403cae02438bf17c96a8ac2e24210 100644
--- a/src/sbbs3/js_global.c
+++ b/src/sbbs3/js_global.c
@@ -1400,7 +1400,7 @@ js_netaddr_type(JSContext *cx, uintN argc, jsval *arglist)
 	jsval *argv=JS_ARGV(cx, arglist);
 	char*	str = NULL;
 
-	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
+	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(NET_NONE));
 
 	if(argc==0 || JSVAL_NULL_OR_VOID(argv[0]))
 		return(JS_TRUE);
diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c
index 89520f4a29fe860f32e90c1384f8d595f25e6f28..bac9ec9f45ee52b8fe02da1d7ae60f78047a4a17 100644
--- a/src/sbbs3/mailsrvr.c
+++ b/src/sbbs3/mailsrvr.c
@@ -3643,7 +3643,7 @@ static void smtp_thread(void* arg)
 					continue;
 				}
 				if(relay_user.number == 0
-					&& strchr(sender, '@') != NULL
+					&& smb_netaddr_type(sender) == NET_INTERNET
 					&& compare_addrs(sender, sender_addr) != 0) {
 					lprintf(LOG_WARNING,"%04d %s %s !FORGED mail header 'FROM' field ('%s' vs '%s', %lu total)"
 						,socket, client.protocol, client_id, sender, sender_addr, ++stats.msgs_refused);
@@ -4073,8 +4073,8 @@ static void smtp_thread(void* arg)
 				p=buf;
 				if(*p=='.') p++;	/* Transparency (RFC821 4.5.2) */
 				if(strlen(p) > RFC822_MAX_LINE_LEN) {
-					lprintf(LOG_WARNING, "%04d %s %s sent an ILLEGALLY-LONG body line (%d chars > %d): '%s'"
-						,socket, client.protocol, client_id, (int)strlen(p), RFC822_MAX_LINE_LEN, p);
+					lprintf(LOG_WARNING, "%04d %s %s !%s sent an ILLEGALLY-LONG body line (%d chars > %d): '%s'"
+						,socket, client.protocol, client_id, reverse_path, (int)strlen(p), RFC822_MAX_LINE_LEN, p);
 					sockprintf(socket, client.protocol, session, "500 Line too long (body)");
 					break;
 				}
@@ -4090,8 +4090,8 @@ static void smtp_thread(void* arg)
 			}
 			/* RFC822 Header parsing */
 			if(strlen(buf) > RFC822_MAX_LINE_LEN) {
-				lprintf(LOG_WARNING, "%04d %s %s sent an ILLEGALLY-LONG header line (%d chars > %d): '%s'"
-					,socket, client.protocol, client_id, (int)strlen(buf), RFC822_MAX_LINE_LEN, buf);
+				lprintf(LOG_WARNING, "%04d %s %s !%s sent an ILLEGALLY-LONG header line (%d chars > %d): '%s'"
+					,socket, client.protocol, client_id, reverse_path, (int)strlen(buf), RFC822_MAX_LINE_LEN, buf);
 				sockprintf(socket, client.protocol, session, "500 Line too long (header)");
 				break;
 			}
diff --git a/src/sbbs3/mqtt.c b/src/sbbs3/mqtt.c
index 9270fcb5698d1fd4f1a7a032fb75f05672c423e1..3fbb3f3a3787290ee8e30daa5bf99091b948c5aa 100644
--- a/src/sbbs3/mqtt.c
+++ b/src/sbbs3/mqtt.c
@@ -531,6 +531,7 @@ int mqtt_startup(struct mqtt* mqtt, scfg_t* cfg, struct startup* startup, const
 	mqtt_pub_strval(mqtt, TOPIC_HOST_LEVEL, NULL, startup->host_name);
 	mqtt_pub_strval(mqtt, TOPIC_SERVER, "version", version);
 	mqtt_pub_uintval(mqtt, TOPIC_SERVER, "served", mqtt->served);
+	mqtt_pub_uintval(mqtt, TOPIC_SERVER, "error_count", mqtt->error_count);
 
 #ifdef USE_MOSQUITTO
 	if(mqtt->handle != NULL)
diff --git a/src/smblib/smbstr.c b/src/smblib/smbstr.c
index 6d4a2ef5e40ee32306482d4e080dbeed5f55f71c..c545de7a8357ecbd1ac9abf174394df440cfec98 100644
--- a/src/smblib/smbstr.c
+++ b/src/smblib/smbstr.c
@@ -331,8 +331,11 @@ char* smb_netaddrstr(const net_t* net, char* fidoaddr_buf)
 /****************************************************************************/
 enum smb_net_type smb_netaddr_type(const char* str)
 {
+	enum smb_net_type type;
 	const char*	p;
 
+	if(str == NULL || IS_WHITESPACE(*str))
+		return NET_NONE;
 	if((p=strchr(str,'@')) == NULL) {
 		p = str;
 		SKIP_WHITESPACE(p);
@@ -342,13 +345,17 @@ enum smb_net_type smb_netaddr_type(const char* str)
 			return NET_FIDO;
 		return NET_NONE;
 	}
-	else
-		p++;
+	if(p == str)
+		return NET_UNKNOWN;
+	p++;
 	SKIP_WHITESPACE(p);
 	if(*p==0)
 		return(NET_UNKNOWN);
 
-	return smb_get_net_type_by_addr(p);
+	type = smb_get_net_type_by_addr(p);
+	if(type == NET_INTERNET && strchr(str, ' ') != NULL)
+		return NET_NONE;
+	return type;
 }
 
 /****************************************************************************/
@@ -357,6 +364,7 @@ enum smb_net_type smb_netaddr_type(const char* str)
 /* Examples:																*/
 /*  ""					= NET_NONE											*/
 /*	"@"					= NET_NONE											*/
+/*	"@something"		= NET_UNKNOWN										*/
 /*	"VERT"				= NET_QWK											*/
 /*	"VERT/NIX"			= NET_QWK											*/
 /*	"1:103/705"			= NET_FIDO											*/
@@ -374,6 +382,8 @@ enum smb_net_type smb_get_net_type_by_addr(const char* addr)
 	const char*	tp;
 
 	char* at = strchr(p,'@');
+	if(at == p)
+		return NET_UNKNOWN;
 	if(at != NULL)
 		p = at + 1;
 
@@ -383,8 +393,9 @@ enum smb_net_type smb_get_net_type_by_addr(const char* addr)
 	char* dot = strchr(p,'.');
 	char* colon = strchr(p,':');
 	char* slash = strchr(p,'/');
+	char* space = strchr(p,' ');
 
-	if(at == NULL && IS_ALPHA(*p) && dot == NULL && colon == NULL)
+	if(at == NULL && IS_ALPHA(*p) && dot == NULL && colon == NULL && space == NULL)
 		return NET_QWK;
 
 	char last = 0;
@@ -417,7 +428,7 @@ enum smb_net_type smb_get_net_type_by_addr(const char* addr)
 	}
 	if(at == NULL && IS_DIGIT(*p) && *tp == '\0' && IS_DIGIT(last))
 		return NET_FIDO;
-	if(slash == NULL && (IS_ALPHANUMERIC(*p) || p == colon))
+	if(slash == NULL && space == NULL && dot != NULL && (IS_ALPHANUMERIC(*p) || p == colon))
 		return NET_INTERNET;
 
 	return NET_UNKNOWN;
@@ -455,6 +466,7 @@ char* smb_msgattrstr(int16_t attr, char* outstr, size_t maxlen)
 	MSG_ATTR_CHECK(attr, DOWNVOTE);
 	MSG_ATTR_CHECK(attr, POLL);
 	MSG_ATTR_CHECK(attr, SPAM);
+	MSG_ATTR_CHECK(attr, FILE);
 	strncpy(outstr, str, maxlen);
 	return outstr;
 }