As you may see I work a little SMTP server written in C#. I included whole code (one class is not included), but I hope you get good view of detail. I am struggeling at the DATA post from the client, the problem is in my point of view the not working "Auto Flush". The client sends to my server "DATA" to tell me to get ready to receive data for my email. I need to answer "354 start mail input", which I do, my problem is: After sending "354 start mail input" I need to receive the message from client in this funtion.
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace FakeSMTP
{
public class SMTPServer //: IDisposable
{
TcpClient client;
NetworkStream stream;
System.IO.StreamReader reader;
System.IO.StreamWriter writer;
//public void Dispose()
//{
// writer.Dispose();
// reader.Dispose();
// stream.Dispose();
//}
public SMTPServer(TcpClient client)
{
this.client = client;
stream = client.GetStream();
reader = new System.IO.StreamReader(stream);
writer = new System.IO.StreamWriter(stream);
writer.NewLine = "\r\n";
writer.AutoFlush = true;
}
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Loopback, 25);
listener.Start();
//using (SMTPServer handler = new SMTPServer(listener.AcceptTcpClient()))
while (true)
{
SMTPServer handler = new SMTPServer(listener.AcceptTcpClient());
Thread thread = new System.Threading.Thread(new ThreadStart(handler.Run));
thread.Start();
}
}
public void Run()
{
string sadress;
string radress;
string rserver;
bool auth = false;
writer.WriteLine("220 smtp.localsmtp.de ESMTP server ready");
for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
Console.Error.WriteLine("Read line {0}", line);
if (line.StartsWith("EHLO"))
{
writer.WriteLine("250-smtp.localsmtp.de");
//Auth ankuendigen
writer.WriteLine("250 AUTH PLAIN");
}
if (line.StartsWith("QUIT"))
{
writer.WriteLine("221 Bye Sweetie see ya");
client.Close();
}
#region auth
if (line.StartsWith("AUTH PLAIN"))
{
Console.WriteLine("client sendet Auth: " + line);
string [] pw = line.Split(new string[] { "PLAIN " }, StringSplitOptions.None);
byte[] bytes = Convert.FromBase64String(pw[1]);
string result = Encoding.BigEndianUnicode.GetString(bytes);
if (result == "12")
{
writer.WriteLine("235 2.7.0 Authentication successful");
auth = true;
}
else
{
Console.WriteLine("Falsche AUTH Daten");
writer.WriteLine("535 – Incorrect authentication data");
}
}
#endregion
#region sender
if (line.StartsWith("MAIL FROM") && auth == true)
{
string[] sadressa = line.Split(new string[] { "FROM:" }, StringSplitOptions.None);
sadress = sadressa[1];
//Absender
sadress = sadress.Replace("<","").Replace(">","");
//Debug
Console.WriteLine("Absender: " + sadress);
writer.WriteLine("250 OK");
}
#endregion
#region receiver
if (line.StartsWith("RCPT TO:") && auth == true)
{
string[] radressa = line.Split(new string[] { "RCPT TO:" }, StringSplitOptions.None);
radress = radressa[1];
//Empfänger
radress = radress.Replace("<", "").Replace(">", "");
if (samplesmtp.getMX.GetMXRecord(radress) != "invalid")
{
rserver = samplesmtp.getMX.GetMXRecord(radress);
Console.WriteLine("MX Record: " + rserver);
}
else
Console.WriteLine("ALARM");
//Debug
Console.WriteLine("Empfänger: " + radress);
writer.WriteLine("250 OK");
}
#endregion
#region data
if (line.StartsWith("DATA") && auth == true)
{
writer.WriteLine("354 start mail input");
var emailLine = reader.ReadLine();
while (!emailLine.Equals("."))
{
// add emailLine to the email body
string[] emailbody = new string[] {emailLine};
Console.WriteLine("Emailbody: " + emailbody[0]);
}
reader.Close();
writer.Close();
stream.Dispose();
writer.WriteLine("250 OK");
}
#endregion
}
}
}
}
Trying to call .Flush() manually in code doesn't change the problem at all. No effect.
In answer to your actual question you want to read all the lines until you receive a . on a line on it's own (see https://www.ietf.org/rfc/rfc2821.txt), something like this: -
var emailLine = reader.ReadLine();
while (!emailLine.Equals("."))
{
// add emailLine to the email body
emailLine = reader.readLine();
}
writer.WriteLine("250 OK");
reader.Close();
writer.Close();
stream.Dispose();