In the .NET framework there is a class TcpClient to retrieve emails from an email server. The TcpClient class has 4 constructors to connect with the server which take at most two parameters. It works fine with those servers which does not use SSL. But gmail or many other email providers use SSL for IMAP.
I can connect with gmail server but can not authenticate with email_id and password.
My code for authenticate user is
public void AuthenticateUser(string username, string password)
{
_imapSw.WriteLine("$ LOGIN " + username + " " + password);
//_imapSw is a object of StreamWriter class
_imapSw.Flush();
Response();
}
But this code can not login.
So how can I use the TcpClient class to retrieve emails when I have to use SSL?
You have to use the SslStream along with the TcpClient then use the SslStream to read the data rather than the TcpClient.
Something along the lines of:
TcpClient mail = new TcpClient();
SslStream sslStream;
mail.Connect("pop.gmail.com", 995);
sslStream = new SslStream(mail.GetStream());
sslStream.AuthenticateAsClient("pop.gmail.com");
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
if (messageData.ToString().IndexOf("<EOF>") != -1)
{
break;
}
} while (bytes != 0);
Console.Write(messageData.ToString());
Console.ReadKey();
EDIT
The above code will simply connect via SSL to Gmail and output the contents of a test message. To log in to a gmail account and issue commands you will need to do something along the lines of:
TcpClient mail = new TcpClient();
SslStream sslStream;
int bytes = -1;
mail.Connect("pop.gmail.com", 995);
sslStream = new SslStream(mail.GetStream());
sslStream.AuthenticateAsClient("pop.gmail.com");
byte[] buffer = new byte[2048];
// Read the stream to make sure we are connected
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
//Send the users login details
sslStream.Write(Encoding.ASCII.GetBytes("USER USER_EMAIL\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
//Send the password
sslStream.Write(Encoding.ASCII.GetBytes("PASS USER_PASSWORD\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
// Get the first email
sslStream.Write(Encoding.ASCII.GetBytes("RETR 1\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
Obviously, without all the duplication of code :)
To tailor the best response above specifically to the question of IMAP and IMAP authentication, you will need to modify the code slightly to use IMAP commands as follows. For debugging, you can set breakpoints just after strOut is assigned to view the server responses.
pmOffice pmO = new pmOffice();
pmO.GetpmOffice(3, false);
TcpClient mail = new TcpClient();
SslStream sslStream;
int bytes = -1;
mail.Connect("outlook.office365.com", 993);
sslStream = new SslStream(mail.GetStream());
sslStream.AuthenticateAsClient("outlook.office365.com");
byte[] buffer = new byte[2048];
// Read the stream to make sure we are connected
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
//Send the users login details (insert your username & password in the following line
sslStream.Write(Encoding.ASCII.GetBytes("$ LOGIN " + pmO.mailUsername + " " + pmO.mailPassword + "\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
string strOut = Encoding.ASCII.GetString(buffer, 0, bytes);
// Get the status of the inbox (# of messages)
sslStream.Write(Encoding.ASCII.GetBytes("$ STATUS INBOX (messages)\r\n"));
bytes = sslStream.Read(buffer, 0, buffer.Length);
strOut = Encoding.ASCII.GetString(buffer, 0, bytes);
You can wrap the NetworkStream provided by TcpClient with an SslStream. This will provide the necessary handling of SSL and certificates.
You may have to insert some handler code to perform a certificate validation callback, e.g. through ServicePointManager.ServerCertificateValidationCallback.
Related
i have an issue where im not receiving any bytes from the connected TcpClient!
Server: (i attempt to add the received message into a listbox, but nothing comes out.
//tl is a TcpListener
//I set this up in a 500 milisecond loop. No worries about that.
if (tl.Pending())
{
TcpClient tcp = tl.AcceptTcpClient();
var s = tcp.GetStream();
int bytesRead = s.Read(new byte[tcp.ReceiveBufferSize], 0,
tcp.ReceiveBufferSize);
string dataReceived = Encoding.ASCII.GetString(new
byte[tcp.ReceiveBufferSize], 0, bytesRead);
listBox1.Items.Add(dataReceived);
tcp.Close();
oac++; //Overall connection count
label3.Text = "Overall Connections: " + oac; //logging connections
}
Client:
void Send(){
TcpClient c = new TcpClient(Im not including my ip., 4444);
System.IO.StreamWriter w = new System.IO.StreamWriter(c.GetStream());
byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes($"Username: \"
{textBox1.Text}\" | Password: \"{textBox2.Text}\"");
NetworkStream nwStream = c.GetStream();
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
nwStream.Flush();
}
I The connection works, but theres some issues receiving data. it just comes out blank
On serverside, your problem is that you renew toy byte array new byte[tcp.ReceiveBufferSize]. You could also do something like this:
using( var inputStream = new MemoryStream() )
{
tcp.GetStream().CopyTo(inputStream);
Encoding.ASCII.GetString(inputStream.ToArray());
listBox1.Items.Add(dataReceived);
...
}
Remember using on all IDisposable's, else you will run out of resources.
Hello in my C# application i have to send and get data from teamSpeak via Telnet.
So I implemented the following function which allows me to send a command and receave the answer via Telnet.
Initialize Telnet connection with TeamSpeak Server
// Init Steam
client = new TcpClient(adress, port);
stream = client.GetStream();
// send Password
Byte[] data = System.Text.Encoding.ASCII.GetBytes("login " + username + " " + password + "\n");
stream.Write(data, 0, data.Length);
data = new Byte[256];
Thread.Sleep(999);
Int32 bytes = stream.Read(data, 0, data.Length);
String responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine(responseData);
// send use
Byte[] data2 = System.Text.Encoding.ASCII.GetBytes("use 1\n");
stream.Write(data2, 0, data2.Length);
data2 = new Byte[9899];
Thread.Sleep(200);
Int32 bytes2 = stream.Read(data2, 0, data2.Length);
String responseData2 = System.Text.Encoding.ASCII.GetString(data2, 0, bytes2);
Console.WriteLine(responseData2);
Send command
Byte[] data2 = System.Text.Encoding.ASCII.GetBytes(command + "\n");
stream.Write(data2, 0, data2.Length);
data2 = new Byte[9899];
Thread.Sleep(200);
Int32 bytes2 = stream.Read(data2, 0, data2.Length);
String responseData2 = System.Text.Encoding.ASCII.GetString(data2, 0, bytes2);
Console.WriteLine(responseData2);
This implementation works but i had to implement a Thread.Sleep(200); (which slows down my application), because elsewhise the data2 Byte[] is empty.
Can anyone tell me what i'm doing wrong?
I try to get a connection between an UWP-programm and a "normal" C# application.
UWP:
StreamSocket s = new StreamSocket();
await socket.ConnectAsync(new HostName("localhost"), "8003");
BinaryWriter bw = new BinaryWriter(socket.OutputStream.AsStreamForWrite());
String toSend = "Hello World!";
byte[] text = Encoding.UTF8.GetBytes(toSend);
byte[] number = BitConverter.getBytes(text.Length);
if(BitConverter.isLittleEndian) Array.Reverse(number);
bw.Write(number, 0, number.Length);
bw.Write(text, 0, text.Length);
"normal" C#, after the TcpListener etablished a new ClientThread:
//client was accepted by the server and is an instance of TcpClient
BinaryReader br = new BinaryReader(client.GetStream());
byte[] number = new byte[4];
br.Read(number, 0, number.Length);
if(BitConverter.isLittleEndian) Array.Reverse(number);
int size = BitConverter.ToInt32(number);
byte[] buffer = new byte[size];
br.Read(buffer, 0, buffer.Length);
String recieved = Encoding.UTF8.GetString(buffer);
Debug.WriteLine(recieved);
But the server doesn´t recieves anything. And the int size is 0. But if i run the UWP-code on a "normal" C# application, by replacing the s.OutputStream.AsStreamForWrite() with client.GetStream() and using a TcpClient instead of an StreamSocket the server recieves the text. What am I doing wrong?
Greets Marcel
here is my code to send TCP request coded in SSL and get the answer from server, but it doesn't work. Debugging and trying to catch exceptions didn't work.
public void SendRequest(string request)
{
byte[] buffer = new byte[2048];
int bytes = -1;
sslStream.Write(Encoding.ASCII.GetBytes(request));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
}
I took that from stackoverflow answer so I'm suprised it doesn't work. Here is my code that receives greeting from server (it works properly):
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = 0;
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
Console.Write(messageData.ToString());
If the sslStream.Read(buffer, 0, buffer.Length); is hanging, it's because the server hasn't sent a response.
Taking a look at your code on github (linked from your other question), it looks like you are using Console.ReadLine() to read commands and then write them to your network stream.
What is happening is that ReadLine() strips off the "\r\n" in the string that it returns, so what you'll need to do when sending it to the server is to add back the "\r\n" so that the server knows that the command is finished (it waits until it gets an EOL sequence before it will respond).
What you could do is in SendRequest(), you could do:
sslStream.Write(Encoding.ASCII.GetBytes(request + "\r\n"));
Server program C#
private TcpListener serverSocket;
..
init:
serverSocket = new TcpListener(ipAddress, port_number);
when new connection request found:
TcpClient clientSock = default(TcpClient);
clientSock = serverSocket.AcceptTcpClient();
NetworkStream networkStream = clientSocket.GetStream();
String FileName = requested binary data file name from client
Byte[] sendBytes = null;
if (File.Exists(pkgName))
{
//load file contents
sendBytes = File.ReadAllBytes(pkgName);
}
if (sendBytes != null)
{
networkStream.Write(sendBytes, 0, sendBytes.Length); //sendBytes.Length = 1001883;
networkStream.Flush();
}
...
Java Android code: client
InetAddress serverAddr = InetAddress.getByName(serverIp);
Log.d("SideloadManager", "C: Connecting...");
Socket socket = new Socket(serverAddr, serverPort);
InputStream inFromServer = socket.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
FileOutputStream outStream = new FileOutputStream("...\recieved.bmp");
int size = 1001883; //same size from server
byte[] buf = new byte[size];
in.read(buf);
outStream.write(buf, 0, buf.length);
outStream.flush();
outStream.close();
received.bmp is of same size as on server 1001883 bytes. But its contents gets corrupted. After debugging i have seen that:
on C# program byte array is [ 149, 145, 10, .....]
on Java program byte array is: [ -105, -101, 10, .....] this is due to signed byte in java
What am i missing to receive correct bitmap?
SOLVED as below:
Replace:
int size = 1001883; //same size from server
byte[] buf = new byte[size];
in.read(buf);
outStream.write(buf, 0, buf.length);
with this:
int len=-1;
byte[] buf = new byte[1024];
while ((len = in.read(buf, 0, buf.length)) > 0) {
outStream.write(buf, 0, len);
}
solved the issue :)
The data is transferred correctly because 149 and -105 have the same binary representation as bytes. The more likely problem is that you're not reading all of the data that was sent in the java side.
The read method returns the number of bytes that have been read, and -1 when the end of the stream has been reached. You need a loop to read the entire file:
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
outStream.write(buf, 0, bytesRead);
}