diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c
index 14d4429882945316edc9a6b729835900ee1b393f..4213fc55093e434914dfe404d5b581c8c857fdd4 100644
--- a/src/sbbs3/mailsrvr.c
+++ b/src/sbbs3/mailsrvr.c
@@ -61,6 +61,7 @@
 #include "mailsrvr.h"
 #include "mime.h"
 #include "crc32.h"
+#include "base64.h"
 
 /* Constants */
 #define FORWARD			"forward:"
@@ -72,6 +73,7 @@ int dns_getmx(char* name, char* mx, char* mx2
 static char* ok_rsp		=	"250 OK";
 static char* sys_error	=	"421 System error";
 static char* badseq_rsp	=	"503 Bad sequence of commands";
+static char* badauth_rsp=	"535 Authentication failure";
 static char* badrsp_err	=	"%s replied with:\r\n\"%s\"\r\n"
 							"instead of the expected reply:\r\n\"%s ...\"";
 
@@ -414,7 +416,7 @@ static int sockreadline(SOCKET socket, char* buf, int len)
 		buf[rd++]=ch;
 	}
 	if(rd>0 && buf[rd-1]=='\r')
-		buf[rd-1]=0;
+		buf[--rd]=0;
 	else
 		buf[rd]=0;
 	
@@ -1408,6 +1410,8 @@ static void smtp_thread(void* arg)
 	char		sender[128];
 	char		sender_addr[128];
 	char		hello_name[128];
+	char		user_name[LEN_ALIAS+1];
+	char		user_pass[LEN_PASS+1];
 	char		relay_list[MAX_PATH+1];
 	char		domain_list[MAX_PATH+1];
 	char		host_name[128];
@@ -1499,6 +1503,7 @@ static void smtp_thread(void* arg)
 	memset(&smb,0,sizeof(smb));
 	memset(&msg,0,sizeof(msg));
 	memset(&user,0,sizeof(user));
+	memset(&relay_user,0,sizeof(relay_user));
 
 	SAFECOPY(host_ip,inet_ntoa(smtp.client_addr.sin_addr));
 
@@ -2184,7 +2189,8 @@ static void smtp_thread(void* arg)
 			p=buf+4;
 			while(*p && *p<=' ') p++;
 			SAFECOPY(hello_name,p);
-			sockprintf(socket,"250 %s",startup->host_name);
+			sockprintf(socket,"250-%s",startup->host_name);
+			sockprintf(socket,"250 AUTH LOGIN");
 			esmtp=TRUE;
 			state=SMTP_STATE_HELO;
 			cmd=SMTP_CMD_NONE;
@@ -2192,6 +2198,59 @@ static void smtp_thread(void* arg)
 			subnum=INVALID_SUB;
 			continue;
 		}
+		/* This is a stupid protocol, but it's the only one Outlook Express supports */
+		if(!stricmp(buf,"AUTH LOGIN")) {	
+			sockprintf(socket,"334 VXNlcm5hbWU6");	/* Base64-encoded "Username:" */
+			rd = sockreadline(socket, buf, sizeof(buf));
+			if(rd<1) {
+				sockprintf(socket,badauth_rsp);
+				continue;
+			}
+			b64_decode(user_name,sizeof(user_name),buf,rd);
+			sockprintf(socket,"334 UGFzc3dvcmQ6");	/* Base64-encoded "Password:" */
+			rd = sockreadline(socket, buf, sizeof(buf));
+			if(rd<1) {
+				sockprintf(socket,badauth_rsp);
+				continue;
+			}
+			b64_decode(user_pass,sizeof(user_pass),buf,rd);
+			if((relay_user.number=matchuser(&scfg,user_name,FALSE))==0) {
+				if(scfg.sys_misc&SM_ECHO_PW)
+					lprintf("%04d !SMTP UNKNOWN USER: %s (password: %s)"
+						,socket, user_name, user_pass);
+				else
+					lprintf("%04d !SMTP UNKNOWN USER: %s"
+						,socket, user_name);
+				sockprintf(socket,badauth_rsp);
+				continue;
+			}
+			if((i=getuserdat(&scfg, &relay_user))!=0) {
+				lprintf("%04d !SMTP ERROR %d getting data on user (%s)"
+					,socket, i, user_name);
+				sockprintf(socket,badauth_rsp);
+				continue;
+			}
+			if(relay_user.misc&(DELETED|INACTIVE)) {
+				lprintf("%04d !SMTP DELETED or INACTIVE user #%u (%s)"
+					,socket, relay_user.number, user_name);
+				sockprintf(socket,badauth_rsp);
+				break;
+			}
+			if(stricmp(user_pass,relay_user.pass)) {
+				if(scfg.sys_misc&SM_ECHO_PW)
+					lprintf("%04d !SMTP FAILED Password attempt for user %s: '%s' expected '%s'"
+						,socket, user_name, user_pass, relay_user.pass);
+				else
+					lprintf("%04d !SMTP FAILED Password attempt for user %s"
+						,socket, user_name);
+				sockprintf(socket,badauth_rsp);
+				break;
+			}
+			lprintf("%04d SMTP %s authenticated using LOGIN protocol"
+				,socket,relay_user.alias);
+			sockprintf(socket,"235 User Authenticated");
+			continue;
+		}
 		if(!stricmp(buf,"QUIT")) {
 			sockprintf(socket,"221 %s Service closing transmission channel",startup->host_name);
 			break;
@@ -2389,7 +2448,8 @@ static void smtp_thread(void* arg)
 					|| dest_port!=server_addr.sin_port) {
 
 					sprintf(relay_list,"%srelay.cfg",scfg.ctrl_dir);
-					relay_user.number=userdatdupe(&scfg, 0, U_NOTE, LEN_NOTE, host_ip, FALSE);
+					if(relay_user.number==0)
+						relay_user.number=userdatdupe(&scfg, 0, U_NOTE, LEN_NOTE, host_ip, FALSE);
 					if(relay_user.number!=0)
 						getuserdat(&scfg,&relay_user);
 					if(p!=alias_buf /* forced relay by alias */ &&