![]() |
General Programming »
Internet / Network »
Email
Intermediate
Socket Console for SMTP in C#By vmlinuxxThis is a byproduct while writing a fully functional mail sender. A good example for learning socket communication. |
C#.NET 1.1, Win2003, Visual Studio, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

This console is used for learning SMTP communication.
TcpClient.
TextBox look and act like a console box.
SocketHelper used to process SMTP commands and receive response from server. public class SocketHelper
{
private TcpClient client=null;
private NetworkStream stream=null;
private StreamReader reader=null;
private StreamWriter writer=null;
private string resp="";
private int state=-1;
public SocketHelper(string name,int port)
{
//
// TODO: Add constructor logic here
//
client=new TcpClient(name,port);
stream=client.GetStream();
reader=new StreamReader(stream);
writer=new StreamWriter(stream);
}
public SocketHelper(TcpClient tc)
{
client=tc;
stream=client.GetStream();
reader=new StreamReader(stream);
writer=new StreamWriter(stream);
}
public void SendData(byte[] bts)
{
if(GetResponseState()!=221)
{
stream.Write(bts,0,bts.Length);
stream.Flush();
}
}
public void SendCommand(string cmd)
{
if(GetResponseState()!=221)
{
writer.WriteLine(cmd);
writer.Flush();
}
}
public string RecvResponse()
{
if(GetResponseState()!=221)
resp=reader.ReadLine();
else
resp="221 closed!";
return resp;
}
public int GetResponseState()
{
if(resp.Length>=3 && IsNumber(resp[0])
&& IsNumber(resp[1]) && IsNumber(resp[2]))
state=Convert.ToInt32(resp.Substring(0,3));
return state;
}
private bool IsNumber(char c)
{
return c>='0' && c<='9';
}
public string GetFullResponse()
{
System.Text.StringBuilder sb=new System.Text.StringBuilder();
sb.Append(RecvResponse());
sb.Append("\r\n");
while(HaveNextResponse())
{
sb.Append(RecvResponse());
sb.Append("\r\n");
}
return sb.ToString();
}
public bool HaveNextResponse()
{
if(GetResponseState()>-1)
{
if(resp.Length>=4 && resp[3]!=' ')
return true;
else
return false;
}
else
return false;
}
}
It is a simple package for TcpClient. My biggest problem while programming was that NetworkStream has no Length. My solution is to parse server response and then decide whether to get more response (some advise please).
TextBox like a console, as follows: private void tbConsole_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if(tbConsole.SelectionStart <
tbConsole.TextLength-tbConsole.Lines[tbConsole.Lines.Length-1].Length)
tbConsole.SelectionStart=tbConsole.TextLength;
if(e.KeyValue==13) //enter
{
int pos=tbConsole.Text.LastIndexOf("\n");
string cmd="";
string res="\r\n";
bool getresp=true;
bool datamode=false;
byte[] bts=null;
if(pos>-1)
cmd=tbConsole.Text.Substring(pos+1,tbConsole.TextLength-pos-1);
else
cmd=tbConsole.Text;
if(cmd==string.Empty)
return;
if(cmd[0]=='$')
{
cmd=Convert.ToBase64String(
System.Text.Encoding.ASCII.GetBytes(cmd.Substring(1)));
tbConsole.Text+="["+cmd+"]";
}
else if(cmd[0]=='.' && cmd.Length>1)
{
cmd=cmd.Substring(1);
getresp=false;
}
else if(cmd[0]=='@')
{
cmd=cmd.Substring(1);
if(System.IO.File.Exists(cmd))
{
FileStream file=System.IO.File.OpenRead(cmd);
bts=new byte[file.Length];
file.Read(bts,0,bts.Length);
file.Close();
datamode=true;
getresp=false;
}
}
if(datamode)
this.Helper.SendData(bts);
else
this.Helper.SendCommand(cmd);
if(getresp)
res+=this.Helper.GetFullResponse();
tbConsole.Text+=res;
tbConsole.SelectionStart=tbConsole.TextLength;
e.Handled=true;
}
else if(e.KeyValue==38 || e.KeyValue==40) //move up or down
e.Handled=true;
else if(e.KeyValue==39) //move right
{
if(tbConsole.SelectionStart < tbConsole.TextLength)
{
char c=tbConsole.Text[tbConsole.SelectionStart];
if(c=='\r' || c=='\n')
e.Handled=true;
}
}
else if(e.KeyValue==37 || e.KeyValue==8) //move left
{
if(tbConsole.SelectionStart>0)
{
char c=tbConsole.Text[tbConsole.SelectionStart-1];
if(c=='\r' || c=='\n')
e.Handled=true;
}
}
}
tbConsole.SelectionStart tells us where the current cursor is. In order to limit the actions of the TextBox, I changed the manner of arrow keys, enter key, and backspace. There are several special commands: the style "$string" means convert "string" to base64 string, then send "@filename" means load "filename" from disk, and send to server ".string" means send "string" to server but don't try to get response. That's the main difference from command line tool Telnet.
HELO dear server
AUTH LOGIN
(enter base64 string as username)
(enter base64 string as password)
MAIL From:sa@mail.local
RCPT To:target@mail.local
DATA
(send mail data to server)
.(send over)
QUIT
HELO is some level equivalent to EHLO (without detailed command prompt). So in my console, just enter the following commands to send a mail:
HELO dear server
AUTH Login
$myname
$mypass
MAIL From:sa@mail.local
RCPT To:test@mail.local
DATA
@c:\mail.txt
.
QUIT
Here is a sample mail:
From: from@mail.local
To: to@mail.local
Subject: hello boy
nice to meet you
Make some changes, you can turn this console into any kind of TCP client. So that's all.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 25 May 2004 Editor: Smitha Vijayan |
Copyright 2004 by vmlinuxx Everything else Copyright © CodeProject, 1999-2009 Web21 | Advertise on the Code Project |