Hello All,

I need to develope an application to receive POP3 emails automatically at regular intervals.
I am totally a newbie to this one and need your kind help.
The application should fetch emails using some service that would run in the background.
So basically I need 2 things (I suppose) :-

  1. A windows service that would run in the background to fetch POP3 emails at regular interval.
  2. An application that would show the new emails (along with the old ones of course) that may come through the windows service.

Any suggestion on this please so that I may kick start it ?
Thanks a lot in advance.

Create a TcpClient and connect to the POP3 server, open a NetworkStream that uses the client and download all the data available. You can then parse this using the POP3 specification.
You can parse this data into a class for storage (file or database)

In your client application you need to be able to connect to your service (I suggest WCF as it allows some pretty cool features) and you grab your mails from this service.

If you're using WCF then you can issue a callback to any connected client saying that mail is ready for it to collect, or, simply send the mail down the callback (although I avoid this scenario, simply telling the client that mail is ready for collection is enough and avoids locking the service while it sends data down the callback channel).

Create a TcpClient and connect to the POP3 server, open a NetworkStream that uses the client and download all the data available. You can then parse this using the POP3 specification.

That's a gross oversimplification. ;) Doing it right is a non-trivial task, so I'd recommend utilizing a library like OpenPOP that already has all of the grunt work done.

Thanks to both of you for you replies.

Hi Ketsuekiame, could you please ellaborate by giving some live example ?

Hi deceptikon, is the OpenPOP meant to download the emails and has the services that run in the background also ?

I suggest you use OpenPOP (as deceptikon mentioned) if you're not interested in learning the mechanics behind POP Mail. You will need to build the services around it for your application.

I would first start with building a one-way WCF service (You call it and it gives you a response). Once you have built that up, it will be easier to teach you how to implement callback contracts for two-way service communication.

Visual Studio has a nice template for a basic WCF service. I suggest you take a look at that and run through some WCF tutorials.

A quick google and This looks like a decent WCF Tutorial to get you started.

Edited 3 Years Ago by Ketsuekiame

Hi,

Thanks for your response and I have implemented OpenPOP methodology however it is developed in windows forms and I thought of some windows service to achieve this.
Not too sure how to convert this class library to windows service and also, I am completely a newbie to WCF and windows services and as of now not able to understand why do I need WCF when I can do the same thing using windows services.
Could you please help me with this as I am stuck as if I'm in some deadlock mode.
Any help is much appreciated. Thanks a lot for your time and replies.

I have implemented OpenPOP methodology however it is developed in windows forms and I thought of some windows service to achieve this.

OpenPOP doesn't depend on Windows Forms, last I recall. There may be a Windows Forms test or utility, or something, but you should be able to ignroe it. You can use it in a class library or a Windows Service with no issues at all. Of this I'm sure, because I've done it before.

I used OpenPOP in a service before I moved to my own POP3 management library. And the only reason I moved to my own was to facilitate easier support of IMAP, OWA, and MAPI.

Hi thanks for the response but I'm not sure how to use this code in a new Windows Service as I have very less or no idea about creating windows services.
So, I request if you could please guide and help me at adding this existing code in a windows service and start it in the background like windows processes and lastly I need to show the results generated by this service in my WPF application.
Please help me with the same.
Thanks a lot.

It sounds more like the issue is with creating a Windows Service. It's pretty straightforward as far as setting things up, though there are a huge number of variations depending on what you want to do and how you want to do it.

The MSDN tutorial is a good start.

The problem here is that you're asking for things that involve too much code to comfortably put in a post.

Hi, thanks a lot for this and here's my code now :-

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using OpenPop.Mime;
using OpenPop.Mime.Header;
using OpenPop.Pop3;
using OpenPop.Pop3.Exceptions;
using OpenPop.Common.Logging;
using Message = OpenPop.Mime.Message;
using System.IO;
using System.Windows.Forms;

namespace EmailReceivingService
{
    public partial class KMEmailService : ServiceBase
    {
        private readonly Dictionary<int, Message> messages = new Dictionary<int, Message>();
        private readonly Pop3Client pop3Client;
        private string popServerText;
        private string portText;
        private string loginText;
        private string passwordText;
        private TreeView listMessages;
        private TreeView listAttachments;

        public KMEmailService()
        {
            InitializeComponent();
            System.Diagnostics.Debugger.Break();
            this.listMessages = new System.Windows.Forms.TreeView();
            this.listAttachments = new System.Windows.Forms.TreeView();

            // This is how you would override the default logger type
            // Here we want to log to a file
            DefaultLogger.SetLog(new FileLogger());

            // Enable file logging and include verbose information
            FileLogger.Enabled = true;
            FileLogger.Verbose = true;

            pop3Client = new Pop3Client();

            // This is only for faster debugging purposes
            // We will try to load in default values for the hostname, port, ssl, username and password from a file
            string myDocs = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            string file = Path.Combine(myDocs, "OpenPopLogin.txt");
            if (File.Exists(file))
            {
                using (StreamReader reader = new StreamReader(File.OpenRead(file)))
                {
                    // This describes how the OpenPOPLogin.txt file should look like
                    popServerText = reader.ReadLine(); // Hostname
                    portText = reader.ReadLine(); // Port
                    loginText = reader.ReadLine(); // Username
                    passwordText = reader.ReadLine(); // Password
                }
            }
            ReceiveEmails();
        }

        protected override void OnStart(string[] args)
        {

        }

        private void ReceiveEmails()
        {
            try
            {
                if (pop3Client.Connected)
                    pop3Client.Disconnect();
                pop3Client.Connect(popServerText, int.Parse(portText), false);
                pop3Client.Authenticate(loginText, passwordText);
                int count = pop3Client.GetMessageCount();
                messages.Clear();
                listMessages.Nodes.Clear();
                listAttachments.Nodes.Clear();

                int success = 0;
                int fail = 0;
                for (int i = count; i >= 1; i -= 1)
                {
                    try
                    {
                        Message message = pop3Client.GetMessage(i);

                        // Add the message to the dictionary from the messageNumber to the Message
                        messages.Add(i, message);

                        // Create a TreeNode tree that mimics the Message hierarchy
                        TreeNode node = new OpenPop.TestApplication.TreeNodeBuilder().VisitMessage(message);

                        // Set the Tag property to the messageNumber
                        // We can use this to find the Message again later
                        node.Tag = i;

                        // Show the built node in our list of messages
                        listMessages.Nodes.Add(node);

                        success++;
                    }
                    catch (Exception e)
                    {
                        DefaultLogger.Log.LogError(
                            "TestForm: Message fetching failed: " + e.Message + "\r\n" +
                            "Stack trace:\r\n" +
                            e.StackTrace);
                        fail++;
                    }
                }

                MessageBox.Show("Mail received!\nSuccesses: " + success + "\nFailed: " + fail, "Message fetching done");

                if (fail > 0)
                {
                    MessageBox.Show("Since some of the emails were not parsed correctly (exceptions were thrown)\r\n" +
                                    "please consider sending your log file to the developer for fixing.\r\n" +
                                    "If you are able to include any extra information, please do so.",
                                    "Help improve OpenPop!");
                }
            }
            catch (InvalidLoginException)
            {
                MessageBox.Show("The server did not accept the user credentials!", "POP3 Server Authentication");
            }
            catch (PopServerNotFoundException)
            {
                MessageBox.Show("The server could not be found", "POP3 Retrieval");
            }
            catch (PopServerLockedException)
            {
                MessageBox.Show("The mailbox is locked. It might be in use or under maintenance. Are you connected elsewhere?", "POP3 Account Locked");
            }
            catch (LoginDelayException)
            {
                MessageBox.Show("Login not allowed. Server enforces delay between logins. Have you connected recently?", "POP3 Account Login Delay");
            }
            catch (Exception e)
            {
                MessageBox.Show("Error occurred retrieving mail. " + e.Message, "POP3 Retrieval");
            }
            finally
            {

            }
        }

        protected override void OnStop()
        {
        }
    }
}

I have successfully built it also but now, I want to develope another application/project that would display the new emails fetching from this service (running in the background and fetching new results at regular intervals say every 15 minutes) into any control like datagrid etc in WPF.
So basically I thought of maintaining a database that would store the new emails (but would that be a right approach as with increasing emails my database would also get increased) :-

  1. Design a database in which the table would contain the new emails from the service (for which I need to change the service code to return emails; as of now its just showing a message box with no. of emails fetched).
  2. Fetch these values at regular intervals into my WPF application in any control like datagrid or textboxes etc.

How can I proceed further on this or do I need to update the approach I am following now ?

First, I need to warn you about services and users/desktop sessions.

Your message boxes will never be shown (On Vista and up). The services don't run on any desktop session, so they don't have anywhere to be shown and you should never attempt to show UI from a service. Additionally, services will not typically run under your user account so the concept of special folder locations will not apply as you think it might.

As for your design question, the database would be the perfect tool for the job, but I think you're missing out on the services aspect of it. In my opinion, the client should be a thin client, only dealing with the layout of your UI and putting the data on to it.

Retrieving the data from the database and shipping it to something understandable should be the job of your service. Your client would then call the service and ask it for a list of emails. This is why I mentioned WCF as it gives you a nice way of hosting a service that you can call and debug easily. You can do it with standard windows services, but I find NET Remoting a bit clunky compared to WCF.

Thanks for your response to this.

  1. However, firstly, I am asked to use the windows services only instead of WCF as per the requirement so unfortunately even if I intend to go with your sugesstions, I cannot go with them.
  2. Secondly, even if I remove the message box showing number of emails, my question is how can I return those numbers to another WPF application showing number of emails say in a textblock or something.
  3. I want this service running on the user's machine who will install my software i.e., my WPF application so I don't think using special folders would create a problem (if so, please correct me).
  4. As the number of emails would increase the Database (DB) size would also increase so, I don't think that maintaining such a huge DB and extending it as per the increasing number of emails is a good idea (well, for that only I was searching alternatives).
  5. I am not attempting to show UI from service but I want to get the data from the service/DB to the UI and show it to the user.

I appreciate your replies however request you to kindly understand that I am not very much familier with these services concepts and also will appreciate that if possible, please update my code so that it would be understandable to me.

Edited 3 Years Ago by KM499

I'll answer in order;

  1. WCF is a framework that can run inside Windows Services. Think of Windows Services as a bucket, doesn't matter what you put inside, so long as it fits.
  2. This is where service communication comes in. If you really can't use WCF, then you should look at .NET Remoting. You will need to review the MSDN and some tutorials. It's too big to talk about here in detail.
  3. It's the service side that I'm talking about :) Your Windows Service will likely run under the account "LOCAL SYSTEM" or "NETWORK SERVICE". Neither of these accounts are attached to the user who logs in to the desktop. So to the service, it has no concept of where that special folder is for the specific client you've logged in as. Where your WPF is concerned, special folders can be used as normal because you're logged in to a desktop session on a standard user account.
  4. Database is the best tool for the job. It will not get that large over the lifetime of the account unless you send huge attachments to it. You could also maintain a maximum age policy whereby everything after say, one month, is automatically deleted from your local store. A good idea here would be to download the headers only (not sure if the OpenPOP client will let you do that) OR download everything and only store the required information for display (such as the subject/datetime/summary) and then download the entire mail later. Depends how your library works (only really talking design with you atm)
  5. I understand the misconception, unfortunately MessageBoxs count as UI. As a rue of thumb, anything that requires you to include System.Windows.Forms or show anything to a user is out of bounds.
    Maybe an easier concept for this is, services start running before anyone logs on. If your service displays a message box before anyone logs on, who does it show it to? Additionally, if you have Remote Terminal Services enabled, you could have 3-4 users logged on at once. Which one do you show it to then?
    It's also a big security risk, which is why it no longer works after XP (I think they removed it in SP2 though I can't verify that).

At the moment, there is nothing that I can give you in code that would help, beyond what the tutorials I link will show you. Also, postng enough code to help you out will clutter up the thread remarkably. (Plus all the time I have to spend designing and debugging it)
I think you'll manage to get there on your own with only minor points in future. Compared to WPF (which you managed to figure out on your own for the most part) Windows Services are easy :)

Thanks a lot Ketsuekiame.
I really appreciate your response and the time you have given to this article.
I will surely try to follow the approaches you have suggested and will let you know if I face any issues in between.
Thanks again :)

Hi, I wrote the logic in my service to get the status (succedeed or failed) of new emails in a string variable as emailStatus and now I added this service project into my solution containing a wpf project.
I built the whole solution, installed this service using installutil.exe myservicename.exe and it was there in services.msc and I started that service.
But now my question is that since this service is now running in the background, how can I have that variable's (emailStatus) value at run time in my WPF application ?

This is why I mentioned that you need a service you can call using IPC (inter process communication)

By far the easiest method is WCF, you can call it just like a webservice. (I'll keep going on about WCF because I like it and use it all the time ;))

If you seriously can't do that, you will need to implement something like Named Pipes communication.

Have a look Here, this will help you get set up with NP-IPC.

Edited 3 Years Ago by Ketsuekiame

Hi,

I have managed to get the entries written to the database and then I will fetch that data in my WPF application.
Its working perfectly fine however I just wanted to know how can I achieve the functionality of writing to the database in my service at a regular interval say every 5 minutes ? (may be a timer functionality)

Thanks a lot for your help.

Edited 3 Years Ago by KM499

Hi,

I am facing some problems.

I am writing the output and exceptions to a log file as OpenPOP in text format. My service is running fine however after 1 or 1.6 hours, it displayed an exception in the log file as

"11/7/2013 2:48:55 PM Connect(): No such host is known
11/7/2013 2:48:55 PM The server could not be found. POP3 Retrieval"

and I guess that may be due to the connection timeout as I am using MySql as the backend to store the new emails data and I think the connection got expired, so my question is that how can I set its timeout for infinite time or till the time the system is ON as I want this service all time running in the background and interact with the Database.

Would using the following be a solution :-

if (mySqlCon.ConnectionTimeout == -1)
{
   mySqlCon.Open();
}
mySqlCon.Open();
MySqlCommand mySqlCommand = mySqlCon.CreateCommand();
mySqlCommand.CommandTimeout = 0;

Also, what about System.Timers.Timer as I have managed to do the same by using the following :-

protected override void OnStart(string[] args)
        {
            myTimer = new System.Timers.Timer(300000);
            myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);
            myTimer.Enabled = true;
            myTimer.AutoReset = true;
            myTimer.Start();
        }

Would I be facing any issues when using this instead of System.Threading.Timer and also what is the difference between the two ?

Edited 3 Years Ago by KM499

Use of that timer is perfectly fine. The main difference is that Threading.Timer is more light-weight.

It's better practice to open/close SQL Connections as you use them. MySQL connections are stored in a connection pool anyway (by default in .NET) so just close the connection after you've made the call.

Your error is actually on Connect though from looking at your log and the error message is more indicative that the server you're trying to connect to can't be found (possibly a DNS error or the server went offline). This might be more related to the POP server you're trying to connect to rather than the database (As indicated by the 'POP3 Retrieval' comment in your log). I would put a bit extra logging in there so you know for sure where the log is being generated from.

I tried the first solution by using the following :-

if (mySqlCon.State == ConnectionState.Closed)
{
   mySqlCon.Open();
}

I think that would work. Please correct if wrong :)

Edited 3 Years Ago by KM499

I would do the following...

public void DoSomethingWithSql()
{
    using(SqlConnection conn = new SqlConnection(connectionString))
    {
        conn.Open();
        using(SqlCommand command = new SqlCommand(/* args in here */))
        {
            command.ExecuteNonQuery(); // Or whatever you need
        }
    }
}

This ensures that your connection is closed (or in MySQL's case returned to the connection pool) and that your objects are disposed properly. It also means that you don't have to manage your SQL Connection. The connector does a lot of work for you in this respect.

Edited 3 Years Ago by Ketsuekiame: Typos

I understand that this is a fine code however I wanted to keep the connection open always so that no time out exists.
I did this way :-

if (mySqlCon.State == ConnectionState.Closed)
{
   mySqlCon.Open();
}

MySqlCommand mySqlCommand = mySqlCon.CreateCommand();
mySqlCommand.CommandTimeout = 0;

And this is also working fine but thanks a lot for your suggestions too, they may be useful for future :)

Keeping the connection open is what's causing the timeout and is bad design.

You should not be controlling this yourself manually, let the framework do the work for you.
All the connections are maintained in a connection pool. This will leave connections open and you won't have to worry about timeout problems. It's what it was designed to do.

When you call close, it returns the connection to the pool, but leaves it open. When you next call open, the pool will return you the next available open connection or open a new one for you.

If you don't want to do this you will need to implement IDisposable on your Database interface layer in which you can dispose of the connection you are keeping open.

Also, please ensure you're disposing your command objects. Not doing so will cause a memory leak.

Hi,

I did wrote mySql.close(); in the finally block and also removed the if condition. But somehow, it also doesn't work.
Could you please give some code to do this that can possibly help me out of this situation ?

Edited 3 Years Ago by KM499

Well I'm not entirely sure what you're doing wrong, but the pattern should be silimar to:

string _connectionString = "CONN_STR_HERE";

...

public void SaveAge(int userId, int age)
{
    using(SqlConnection con = new SqlConnection(_connectionString))
    {
        using(SqlCommand command = new SqlCommand("SaveAge", conn))
        {
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.Add(new SqlParameter("@UserId", userId));
            command.Parameters.Add(new SqlParameter("@Age", age));

            conn.Open();
            command.ExecuteNonQuery();
        }
    }
}

If this doesn't work, something is wrong somewhere else.

Edited 3 Years Ago by Ketsuekiame

Thanks a lot, I will surely try this one out and let you know :)

This question has already been answered. Start a new discussion instead.