Skip to content

Commit

Permalink
hMailServer should be able to deliver to servers not supporting EHLO. h…
Browse files Browse the repository at this point in the history
  • Loading branch information
martinknafve committed Sep 22, 2014
1 parent 48ef3d1 commit f76a9d6
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 22 deletions.
42 changes: 39 additions & 3 deletions hmailserver/source/Server/SMTP/SMTPClientConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,10 @@ namespace HM
ProtocolStateHELOEHLO_(Request);
return true;
case HELOSENT:
ProtocolHELOEHLOSent_(Request);
ProtocolHELOSent_(Request);
return true;
case EHLOSENT:
ProtocolEHLOSent_(iCode, Request);
return true;
case STARTTLSSENT:
ProtocolSTARTTLSSent_(iCode);
Expand Down Expand Up @@ -237,11 +240,16 @@ namespace HM
String computer_name = Utilities::ComputerName();

if (use_esmtp)
{
EnqueueWrite_("EHLO " + computer_name);
SetState_(EHLOSENT);
}
else
{
EnqueueWrite_("HELO " + computer_name);
SetState_(HELOSENT);
}

SetState_(HELOSENT);
}

void
Expand Down Expand Up @@ -307,8 +315,36 @@ namespace HM
}

void
SMTPClientConnection::ProtocolHELOEHLOSent_(const AnsiString &request)
SMTPClientConnection::ProtocolHELOSent_(const AnsiString &request)
{
ProtocolSendMailFrom_();
}

void
SMTPClientConnection::ProtocolEHLOSent_(int code, const AnsiString &request)
{
if (!IsPositiveCompletion(code))
{
bool ehlo_required = GetConnectionSecurity() == CSSTARTTLSRequired ||
use_smtpauth_;

if (ehlo_required)
{
// hMailServer is configured to require EHLO, but the remote server does not support it.
UpdateAllRecipientsWithError_(500, "Server does not support EHLO command.", false);
SendQUIT_();
}
else
{
// Server does not support EHLO, but we do not require it. Switch to HELO.
String computer_name = Utilities::ComputerName();
EnqueueWrite_("HELO " + computer_name);
SetState_(HELOSENT);
}

return;
}

if (GetConnectionSecurity() == CSSTARTTLSRequired ||
GetConnectionSecurity() == CSSTARTTLSOptional)
{
Expand Down
4 changes: 3 additions & 1 deletion hmailserver/source/Server/SMTP/SMTPClientConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ namespace HM

void ProtocolStateHELOEHLO_(const AnsiString &request);
void ProtocolSendMailFrom_();
void ProtocolHELOEHLOSent_(const AnsiString &request);
void ProtocolHELOSent_(const AnsiString &request);
void ProtocolEHLOSent_(int code, const AnsiString &request);
void ProtocolSTARTTLSSent_(int code);
void ProtocolMailFromSent_();
void ProtocolRcptToSent_(int code, const AnsiString &request);
Expand Down Expand Up @@ -80,6 +81,7 @@ namespace HM
{
HELO = 1,
HELOSENT = 9,
EHLOSENT = 10,
AUTHLOGINSENT = 11,
USERNAMESENT = 12,
PASSWORDSENT = 13,
Expand Down
82 changes: 82 additions & 0 deletions hmailserver/test/RegressionTests/SMTP/SMTPClientStartTLSTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ namespace RegressionTests.SMTP
[TestFixture]
public class SMTPClientStartTLSTests : TestFixtureBase
{
private Status _status;
private Account _account;

[SetUp]
public new void SetUp()
{
_status = _application.Status;

_account = SingletonProvider<TestSetup>.Instance.AddAccount(_domain, "[email protected]", "test");
}

[Test]
public void UseStartTlsIfEnabledAndAvailable()
{
Expand Down Expand Up @@ -131,5 +142,76 @@ public void DoNotUseStartTlsIfNotEnabledAndNotAvailable()
CustomAssert.IsFalse(TestSetup.DefaultLogContains("220 Ready to start TLS"));
}
}



[Test]
public void TestDelivertoServerNotSupportingEHLOOptionalConnectionSecurity()
{
CustomAssert.AreEqual(0, _status.UndeliveredMessages.Length);

var deliveryResults = new Dictionary<string, int>()
{
{"[email protected]", 250}
};

int smtpServerPort = TestSetup.GetNextFreePort();
using (var server = new SMTPServerSimulator(1, smtpServerPort))
{
server.ServerSupportsEhlo = false;
server.AddRecipientResult(deliveryResults);
server.StartListen();

// Add a route so we can conenct to localhost.
SMTPClientTests.AddRoutePointingAtLocalhost(1, smtpServerPort, false, eConnectionSecurity.eCSSTARTTLSOptional);

// Send message to this route.

if (!SMTPClientSimulator.StaticSend("[email protected]", "[email protected]", "Test", "Test message"))
CustomAssert.Fail("Delivery failed");

// Wait for the client to disconnect.
server.WaitForCompletion();

TestSetup.AssertRecipientsInDeliveryQueue(0, false);

CustomAssert.IsTrue(server.MessageData.Contains("Test message"));
}
}

[Test]
public void TestDeliverToServerNotSupportingEHLORequiredConnectionSecurity()
{
CustomAssert.AreEqual(0, _status.UndeliveredMessages.Length);

var deliveryResults = new Dictionary<string, int>()
{
{"[email protected]", 250}
};

int smtpServerPort = TestSetup.GetNextFreePort();
using (var server = new SMTPServerSimulator(1, smtpServerPort))
{
server.ServerSupportsEhlo = false;
server.AddRecipientResult(deliveryResults);
server.StartListen();

// Add a route so we can conenct to localhost.
SMTPClientTests.AddRoutePointingAtLocalhost(1, smtpServerPort, false, eConnectionSecurity.eCSSTARTTLSRequired);

// Send message to this route.

if (!SMTPClientSimulator.StaticSend("[email protected]", "[email protected]", "Test", "Test message"))
CustomAssert.Fail("Delivery failed");

// Wait for the client to disconnect.
server.WaitForCompletion();

TestSetup.AssertRecipientsInDeliveryQueue(0, true);

var msg = POP3ClientSimulator.AssertGetFirstMessageText("[email protected]", "test");
CustomAssert.IsTrue(msg.Contains("Server does not support EHLO command."));
}
}
}
}
70 changes: 69 additions & 1 deletion hmailserver/test/RegressionTests/SMTP/SMTPClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ public void TestDeliverySuccess50Recipients()
}
}



[Test]
[Description(
Expand Down Expand Up @@ -1025,5 +1024,74 @@ public void TestTemporaryFailure()
CustomAssert.IsTrue(message.Contains("452 [email protected]"));
CustomAssert.IsTrue(message.Contains("Tried 2 time(s)"));
}

[Test]
public void TestDeliverToServerNotSupportingEHLO()
{
CustomAssert.AreEqual(0, _status.UndeliveredMessages.Length);

var deliveryResults = new Dictionary<string, int>()
{
{"[email protected]", 250}
};

int smtpServerPort = TestSetup.GetNextFreePort();
using (var server = new SMTPServerSimulator(1, smtpServerPort))
{
server.ServerSupportsEhlo = false;
server.AddRecipientResult(deliveryResults);
server.StartListen();

// Add a route so we can conenct to localhost.
SMTPClientTests.AddRoutePointingAtLocalhost(1, smtpServerPort, false, eConnectionSecurity.eCSNone);

// Send message to this route.

if (!SMTPClientSimulator.StaticSend("[email protected]", "[email protected]", "Test", "Test message"))
CustomAssert.Fail("Delivery failed");

// Wait for the client to disconnect.
server.WaitForCompletion();

TestSetup.AssertRecipientsInDeliveryQueue(0, false);

CustomAssert.IsTrue(server.MessageData.Contains("Test message"));
}
}

[Test]
public void TestDeliverToServerNotSupportingHELO()
{
CustomAssert.AreEqual(0, _status.UndeliveredMessages.Length);

var deliveryResults = new Dictionary<string, int>()
{
{"[email protected]", 250}
};

int smtpServerPort = TestSetup.GetNextFreePort();
using (var server = new SMTPServerSimulator(1, smtpServerPort))
{
server.ServerSupportsHelo = false;
server.AddRecipientResult(deliveryResults);
server.StartListen();

// Add a route so we can conenct to localhost.
SMTPClientTests.AddRoutePointingAtLocalhost(1, smtpServerPort, false, eConnectionSecurity.eCSNone);

// Send message to this route.

if (!SMTPClientSimulator.StaticSend("[email protected]", "[email protected]", "Test", "Test message"))
CustomAssert.Fail("Delivery failed");

// Wait for the client to disconnect.
server.WaitForCompletion();

TestSetup.AssertRecipientsInDeliveryQueue(0, true);

var msg = POP3ClientSimulator.AssertGetFirstMessageText("[email protected]", "test");
CustomAssert.IsTrue(msg.Contains("Remote server replied: 550 Command HELO not recognized."));
}
}
}
}
45 changes: 28 additions & 17 deletions hmailserver/test/RegressionTests/Shared/SMTPServerSimulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,16 @@ internal class SMTPServerSimulator : TcpServer
private SimulatedErrorType _simulatedError;
private bool _transmittingData;

public bool ServerSupportsEhlo { get; set; }
public bool ServerSupportsHelo { get; set; }


public SMTPServerSimulator(int maxNumberOfConnections, int port, eConnectionSecurity connectionSecurity) :
base(maxNumberOfConnections, port, connectionSecurity)
{
_recipientResults = new List<Dictionary<string, int>>();
ServerSupportsEhlo = true;
ServerSupportsHelo = true;
}

public SMTPServerSimulator(int maxNumberOfConnections, int port) :
Expand Down Expand Up @@ -116,13 +121,13 @@ public void Run()

private bool ProcessCommand(string command)
{
if (command.ToUpper().StartsWith("HELO"))
if (ServerSupportsHelo && command.ToUpper().StartsWith("HELO"))
{
Send("250 Test Server - Helo\r\n");
return false;
}

if (command.ToUpper().StartsWith("EHLO"))
if (ServerSupportsEhlo && command.ToUpper().StartsWith("EHLO"))
{
var response = new StringBuilder();

Expand Down Expand Up @@ -229,28 +234,29 @@ private bool ProcessCommand(string command)
Disconnect();
return true;
}



_messageData += command;
}

if (_messageData.IndexOf("\r\n.\r\n") > 0)
{
// remove the ending...
_messageData = _messageData.Replace("\r\n.\r\n", "\r\n");
if (_messageData.IndexOf("\r\n.\r\n") > 0)
{
// remove the ending...
_messageData = _messageData.Replace("\r\n.\r\n", "\r\n");

Send("250 Test Server - Queued for delivery\r\n");
Send("250 Test Server - Queued for delivery\r\n");

if (_simulatedError == SimulatedErrorType.DisconnectAfterMessageAccept)
{
Disconnect();
return true;
if (_simulatedError == SimulatedErrorType.DisconnectAfterMessageAccept)
{
Disconnect();
return true;
}

_transmittingData = false;
return false;
}

_transmittingData = false;
return false;
}

if (_expectingUsername)
{
_expectingUsername = false;
Expand All @@ -271,6 +277,11 @@ private bool ProcessCommand(string command)
return false;
}


var commandName = command.Substring(0, 4);

Send(string.Format("550 Command {0} not recognized.\r\n", commandName));

return false;
}
}
Expand Down

0 comments on commit f76a9d6

Please sign in to comment.