Tuesday, September 14, 2010

Receive Emails

Attention: This post describes the basic of receiving emails. At the time of this post this was possible without the use of SSL, nowadays this is required by most providers Therefore I explain the receiving of emails with an SSL connection in this new post. There also the usage of an IMAP server is described - in this post only a POP3 server is considered.

In a previous post I showed, how to send emails with C#.
Today is about receiving emails using C#.
Sending was relatively easy, since .Net provided methods to connect to an SMTP server, over whcih emails can be send.
Receiving is a bit harder, we have to logon to the incoming mail server and send the right commands to check and geet emails.
Clients can get emails from the mail server usign the POP3 or IMAP protocoll. IMAP provides more functionality, the most free mail providers like WEB or GMX though use POP3.
The code shown here also works with the POP3 protocoll.
A POP3 server waits for requests on a specific port (mostly 110). A client then can input username and password there and then send commands, which all have to be separated by a linebreak.
The server sends to every command and answer and waits for input, if necessary.
We impement the POP3 server in C# with a TcpClient and send the commands via a NetworkStream.
Before I go into more details of the code, first I want to explain the basic process of communication with the incoming mail server:
After setting up the connection this first expects a username, which we set with the command "USER username". Then the password follows with "PASS password".
To list all mails available on the server the command "LIST" is needed. In response to that, the server sends all messages as an answer - for each ID and size of the message, per line one message, the end of a line is characterized by ".".
One specific email can be retrieved via "RETR id". The server then answers with the complete content.
To terminate the connection to the server, there is the command "QUIT".

Now to the implementation:

To represent the POP3 server an instance of the class TcpClient. To send the commands described above, we use the class NetworkStream, which connects to the stream of the server.
Since computers work with binary number, but we humans understand words over our alphabet better, we have to convert the commands to bytecode, which can be done with the class ASCIIEncoding.
An instance of the class StreamReader eventually is used to read the answers sent by the server.
The following program demonstrates a communication with the incoming mail server, the programming style (using global variables etc.) is not the best, but I think, the basic principles should become clear quickly in this way.
The program consists of 4 functions, which are all called from Form1_Load():

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net.Sockets;
using System.IO;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        TcpClient POP3Server = new TcpClient(); // TcpClient for the connection to the server
        NetworkStream POP3Stream; // network stream for the connection with the server
        StreamReader StreamListener; // StreamReader to convert byte data to readable text
        byte[] CommandBuffer = new byte[1024]; // byte Array for sending commands to the server
        ASCIIEncoding AscEncoding = new ASCIIEncoding(); // ASCII encoding to encode ASCII commands to byte data

        private void Form1_Load(object sender, EventArgs e)
        {
            if (Connect("hosturl", port, "benutzername""password"))
            {
                /* remove the following comment to get all mails from the server */
                // ListMails();
                /* remove the following comment to read the context of message with ID id */
                // richTextBox1.Text = ReadMailContent(id);
                Quit();
            }
        }

        /// <summary>
       /// tries to connect to the given POP3 server
        /// </summary>
        /// <param name="server">URL of the server</param>
        /// <param name="port">port of the server</param>
        /// <param name="user">username</param>
        /// <param name="password">password</param>
        /// <returns>true if connection successful, otherwise false</returns>
        private bool Connect(string server, int port, string user, string password)
        {
            POP3Server.Connect(server, port); // connect
            POP3Stream = POP3Server.GetStream(); // create network stream
            StreamListener = new StreamReader(POP3Stream); // create StreamReader from network stream

            if (POP3Server.Connected) // connection succesful
            {
                MessageBox.Show(StreamListener.ReadLine());

                // send username
                CommandBuffer = AscEncoding.GetBytes("USER " + user + "\r\n");
                POP3Stream.Write(CommandBuffer, 0, CommandBuffer.Length);
                MessageBox.Show(StreamListener.ReadLine());

                // send password
                CommandBuffer = AscEncoding.GetBytes("PASS " + password + "\r\n");
                POP3Stream.Write(CommandBuffer, 0, CommandBuffer.Length);
                MessageBox.Show(StreamListener.ReadLine());

                return true;
            }

            return false;
        }

        /// <summary>
       /// terminate connection to the POP3 server
        /// </summary>
        private void Quit()
        {
            // send quit command
            CommandBuffer = AscEncoding.GetBytes("QUIT\r\n");
            POP3Stream.Write(CommandBuffer, 0, CommandBuffer.Length);
            MessageBox.Show(StreamListener.ReadLine());
        }

        /// <summary>
       /// reads the content of the given mail
        /// <summary>
        /// <param name="mailNr">ID of the mail which should be read</param>
        /// <returns>content of the mail</returns>
        private string ReadMailContent(int mailNr)
        {
            // send command to retrieve the correspondign mail
            CommandBuffer = AscEncoding.GetBytes("RETR " + mailNr + "\r\n");
            POP3Stream.Write(CommandBuffer, 0, CommandBuffer.Length);

            // StringBuilder for a quicker loading of the mail content
            StringBuilder FullEmailContent = new StringBuilder();

            /* as long as not "." is read, the email is not at its end,
            write read lines in the StringBuilder */
            string TempLine = StreamListener.ReadLine();
            while (TempLine != ".")
            {
                FullEmailContent.Append(TempLine + "\r\n");
                TempLine = StreamListener.ReadLine();
            }

            return FullEmailContent.ToString();
        }

        /// <summary>
       /// Lists all mails available on the server
        /// </summary>
        private void ListMails()
        {
            // send command to list all mails
            CommandBuffer = AscEncoding.GetBytes("LIST\r\n");
            POP3Stream.Write(CommandBuffer, 0, CommandBuffer.Length);

            /* as long as not "." is read, there are more emails available on the server, iterate through them and output ID + size */
            string CurrentMessage = StreamListener.ReadLine();
            while (CurrentMessage != ".")
            {
                MessageBox.Show(CurrentMessage);
                CurrentMessage = StreamListener.ReadLine();
            }
        }

    }
}


The function ReadMailContent() writes the content of the read mail in a RichTextBox (which has to be available on the form), since this control supports basic formattings (like links and split lines), like they occur in emails.
When using the function Connect(), the parameters have to be replacecd by own ones.
For the free mail providers WEB and GMX the following parameters are needed:

WEB:
hosturl: pop3.web.de
port: 110
username: Email address without the ending @web.de
passwort: you should know that

GMX:
hosturl: mail.gmx.net
port: 110
benutzername: complete email address
password: you should know that

No comments:

Post a Comment