Reputation: 2911
I have an application that scans an email account for returned mail. It uses POP3, and works successfully on several clients' systems. However, with one client, when we try to connect, we are getting a SocketException - No such host is known.
My first thought was that either the address or port were not accessible, but they came back saying that it is an SSL port, and I figured that my code may not be able to handle SSL. However, the error is happening when I call tcpClient = new TcpClient(Host, Port);
, so I am back to my previous hypothesis. Is there a special way TcpClient needs to connect to an SSL port?
My second question is whether there is an easy way to convert code to use SSL without basically creating a regular POP3 connection class and an SSL POP3 connection class? I believe I need to use SslStream
instead of StreamReader
, which means I would have to modify any code that accesses the POP3 server, since SslStream
does not have a ReadLine()
method.
I've added my initial connection code below (or the important bits).
try
{
tcpClient = new TcpClient(Host, Port);
}
catch (SocketException e)
{
logger.Log(...);
throw (e);
}
String response = "";
try
{
streamReader = new StreamReader(tcpClient.GetStream());
// Log in to the account
response = streamReader.ReadLine();
if (response.StartsWith("+OK"))
{
response = SendReceive("USER ", UserName.Trim() + "@" + Domain.Trim());
if (response.StartsWith("+OK"))
{
response = SendReceive("PASS ", Password);
}
}
if (response.StartsWith("+OK"))
result = true;
}
catch (Exception e)
{
result = false;
}
The SendReceive
method is pretty simple:
private String SendReceive(String command, String parameter)
{
String result = null;
try
{
String myCommand = command.ToUpper().Trim() + " " + parameter.Trim() + Environment.NewLine;
byte[] data = System.Text.Encoding.ASCII.GetBytes(myCommand.ToCharArray());
tcpClient.GetStream().Write(data, 0, data.Length);
result = streamReader.ReadLine();
}
catch { } // Not logged in...
return result;
}
It seems to be mainly the ReadLine()
method that does not work, but reading up on that suggests that it is difficult to read a line with a stream since you don't know whether it is finished sending or not. Is this the case, or do I just need to write a quick method to read until I hit a \r
or \n
?
Upvotes: 0
Views: 1600
Reputation: 38528
To answer your first question, there is no different way to connect to an SSL port, it works exactly the same way.
As far as your second question, a StreamReader
wraps a System.IO.Stream
and an SslStream
is just an implementation of System.IO.Stream
, so you can create a StreamReader
around it just fine.
What you will need to do is something like this:
var stream = tcpClient.GetStream ();
if (useSsl) {
var ssl = new SslStream (stream);
ssl.AuthenticateAsClient (Host, null, SslProtocols.Tls12, true);
stream = ssl;
}
streamReader = new StreamReader (stream);
Of course, you'll need to fix your SendReceive()
method to not use tcpClient.GetStream()
again, because you'll need to use the SslStream
and not the NetworkStream
that tcpClient.GetStream()
will return.
The easiest way to do that is probably to just pass the stream
variable to SendReceive()
, or, I suppose, add a Stream
member to your class like you presumably did for streamReader
and tcpClient
.
Of course, a better solution would be to use a library for this such as my MailKit library which handles all of this for you in a much more robust way than this code does :)
Upvotes: 2