Click here to Skip to main content
6,596,602 members and growing! (23,351 online)
Email Password   helpLost your password?
General Programming » Internet / Network » Email     Intermediate

Socket Console for SMTP in C#

By vmlinuxx

This 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
Posted:25 May 2004
Views:36,098
Bookmarked:18 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
5 votes for this article.
Popularity: 1.63 Rating: 2.33 out of 5

1
3 votes, 60.0%
2
1 vote, 20.0%
3

4
1 vote, 20.0%
5

Sample image

Introduction

This console is used for learning SMTP communication.

  1. How to use packaged socket client class TcpClient.
  2. How to make a simple TextBox look and act like a console box.
  3. How to communicate with SMTP servers.

Classes

  1. There is a class called 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).

  2. The code makes a 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.

  3. The common command sequence to communicate with a SMTP server should be as follows:
    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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

vmlinuxx


Member

Occupation: Web Developer
Location: China China

Other popular Internet / Network articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
  (Refresh) 
-- There are no messages in this forum --

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin 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