POP3 - клиент на С# (работает на Windows Mobile)

Недавно столкнулся с проблемой получения почты с pop3 — сервера. С отправкой в Framework-е все нормально, а вот с получением… Решил привести пример своего решения данной проблемы на данном молодом сайте.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Net.Sockets;
using System.Collections;
using System.Text.RegularExpressions;
using System.IO;

/// <summary>
/// Сводное описание для POP3EmailMessage
/// </summary>
public class POP3EmailMessage
{
    //номер сообщения на сервере
    public long msgNumber;
    //размер сообщения на сервере
    public long msgSize;
    //флаг, принято ли сообщение с сервера
    public bool msgRecived;
    //текст сообщения
    public string msgContent;
    
    public POP3EmailMessage()
	{
		//
		// TODO: добавьте логику конструктора
		//
	}
}

public class POP3:System.Net.Sockets.TcpClient
{
    public string SaveToFile(string msgContent, string path, string filename)
    {
        string flag = "";
        try
        {
            if (!(Directory.Exists(path)))
            {
                Directory.CreateDirectory(path);
            }
            flag = path + filename + ".eml";
            FileStream file = new FileStream(flag, FileMode.Create);
            StreamWriter sw = new StreamWriter(file);
            sw.WriteLine(msgContent);
            sw.Close();
            file.Close();
        }
        catch (Exception ex)
        {
            flag = "";
        }
        return flag;
    }

    public string From(string msgContent)
    {
        string str = " ";
        char[] sep = {'\r', '\n' };
        string[] tmp = msgContent.Split(sep);
        int count = tmp.Length;
        int j=0;
        while (j != count)
        {
            if (tmp[j].IndexOf("From:") == 0)
            {
                str = Regex.Replace(tmp[j], @"^From:.*[ |<]([a-z|A-Z|0-9|\.|\-|_][email protected][a-z|A-Z|0-9|\.|\-|_]+).*$", "$1");
                break;
            }
            j++;
        }
        return str;
    }

    public string To(string msgContent)
    {
        string str = " ";
        char[] sep = { '\r', '\n' };
        string[] tmp = msgContent.Split(sep);
        int count = tmp.Length;
        int j = 0;
        while (j != count)
        {
            if (tmp[j].IndexOf("To:") == 0)
            {
                str = Regex.Replace(tmp[j], @"^To:.*[ |<]([a-z|A-Z|0-9|\.|\-|_][email protected][a-z|A-Z|0-9|\.|\-|_]+).*$", "$1");
                break;
            }
            j++;
        }
        return str;
    }

    public string Subject(string msgContent)
    {
        string str = " ";
        char[] sep = { '\r', '\n' };
        string[] tmp = msgContent.Split(sep);
        int count = tmp.Length;
        int j = 0;
        while (j != count)
        {
            if (tmp[j].IndexOf("Subject:") == 0)
            {
                str = Regex.Replace(tmp[j], @"^Subject: (.*)$", "$1");
                break;
            }
            j++;
        }
        return str;
    }
    
    public void ConnectPOP(string sServerName, string sUserName, string sUserPassword)
    { 
        //сообщение сервера и результат с сервера
        string sMessage;
        string sResult;

        //соединяемся с POP сервером
        Connect(sServerName, 110);
        //получаем результат
        sResult = Response();

        //проверяеи ответ
        if (sResult.Substring(0, 3) != "+OK") { throw new POPException(sResult); }

        //соеденились, отправляем имя пользователя
        sMessage = "USER " + sUserName + "\r\n";
        //отправляем данные через TCP-соединение
        Write(sMessage);
        sResult = Response();
        if (sResult.Substring(0, 3) != "+OK") { throw new POPException(sResult); }

        //отправляем пароль
        sMessage = "PASS " + sUserPassword + "\r\n";
        Write(sMessage);
        sResult = Response();
        if (sResult.Substring(0, 3) != "+OK") { throw new POPException(sResult); }

    }

    public void DisconnectPOP()
    {
        string sMessage;
        string sResult;

        sMessage = "QUIT\r\n";
        Write(sMessage);
        sResult = Response();
        if (sResult.Substring(0, 3) != "+OK") { throw new POPException(sResult); }
    }

    public ArrayList ListMessages()
    {
        string sMessage;
        string sResult;
        ArrayList returnValue = new ArrayList();
        sMessage = "LIST\r\n";
        Write(sMessage);
        sResult = Response();
        if (sResult.Substring(0, 3) != "+OK") { throw new POPException(sResult); }

        while (true)
        {
            sResult = Response();
            if (sResult == ".\r\n")
            {
                return returnValue;
            }
            else
            {
                POP3EmailMessage oMailMessage = new POP3EmailMessage();
                //разделитель - пробел
                char[] sep = {' '};
                string[] values = sResult.Split(sep);
                oMailMessage.msgNumber = Int32.Parse(values[0]);
                oMailMessage.msgSize = Int32.Parse(values[1]);
                oMailMessage.msgRecived = false;
                returnValue.Add(oMailMessage);
                continue;
            }
        }

    }

    public POP3EmailMessage RetrieveMessage(POP3EmailMessage msgRETR)
    {
        string sMessage;
        string sResult;

        POP3EmailMessage oMailMassage = new POP3EmailMessage();
        oMailMassage.msgSize = msgRETR.msgSize;
        oMailMassage.msgNumber = msgRETR.msgNumber;
        sMessage = "RETR " + msgRETR.msgNumber + "\r\n";
        Write(sMessage);
        sResult = Response();
        if (sResult.Substring(0, 3) != "+OK") { throw new POPException(sResult); }
        oMailMassage.msgRecived = true;
        while (true)
        {
            sResult = Response();
            if (sResult == ".\r\n")
            {
                break;
            }
            else
            {
                oMailMassage.msgContent += sResult;
            }
        }
        return oMailMassage;

    }

    private void Write(string sMessage)
    {
        System.Text.ASCIIEncoding oEncodedData = new System.Text.ASCIIEncoding();
        byte[] WrriteBuffer = new byte[1024];
        WrriteBuffer = oEncodedData.GetBytes(sMessage);
        NetworkStream NetStream = GetStream();
        NetStream.Write(WrriteBuffer, 0, WrriteBuffer.Length);
    }

    private string Response()
    {
        System.Text.ASCIIEncoding oEncodedData = new System.Text.ASCIIEncoding();
        byte[] ServerBuffer = new Byte[1024];
        NetworkStream NetStream = GetStream();
        int count = 0;

        //считываем данные из сетевого потока сервера, что бы потом их декодировать
        while (true)
        {
            byte[] buff = new Byte[2];
            int bytes = NetStream.Read(buff, 0, 1);
            if (bytes == 1)
            {
                ServerBuffer[count] = buff[0];
                count++;
                if (buff[0] == '\n')
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
        //возвращаем декодированный ответ сервера
        string ReturnValue = oEncodedData.GetString(ServerBuffer, 0, count);
        return ReturnValue;
    }

    public void DeleteMessage(POP3EmailMessage msgDELE)
    {
        string sMessage;
        string sResult;

        sMessage = "DELE " + msgDELE.msgNumber + "\r\n";
        Write(sMessage);
        sResult = Response();
        if (sResult.Substring(0, 3) != "+OK") { throw new POPException(sResult); }

    }
}

public class POPException : System.ApplicationException
{
    public POPException(string str): base (str)
    { 
    }
}


Пример кода взят из какой то книги, название не помню. И немного доработан. Конечно он не решит всех проблем, но думаю многим будет полезен.

Комментарии (8)

RSS свернуть / развернуть
+
0
Спасибо за первый пост, повысил Вам рейтинг!
Вот сохранение почтового сообщения в файл я у Вас увидел, а как насчет загрузки сообщения из файла и последующей отправки?
avatar

admin

  • 13 декабря 2010, 13:15
+
0
Функция RetrieveMessage начинает страшно тупить при большом размере получаемого сообщения. Письмо размером в 13МБ принимается 1 час 2 минут!
Все дело в
oMailMassage.msgContent += sResult;
. Я переписал функцию так:
public void RetrieveMessage(POP3EmailMessage msgRETR, string path, string filename)
    {
        string sMessage;
        string sResult;
        string flag = "";

        POP3EmailMessage oMailMassage = new POP3EmailMessage();
        oMailMassage.msgSize = msgRETR.msgSize;
        oMailMassage.msgNumber = msgRETR.msgNumber;
        sMessage = "RETR " + msgRETR.msgNumber + "\r\n";
        Write(sMessage);
        sResult = Response();
        if (sResult.Substring(0, 3) != "+OK") { throw new POPException(sResult); }
        oMailMassage.msgRecived = true;
        if (!(Directory.Exists(path)))
        {
            Directory.CreateDirectory(path);
        }
        flag = path + filename + ".eml";
        FileStream file = new FileStream(flag, FileMode.Create);
        StreamWriter sw = new StreamWriter(file);
        try
        {
            while (true)
            {
                sResult = Response();
                if (sResult == ".\r\n")
                {
                    break;
                }
                else
                {
                    sw.Write(sResult);
                }
            }
        }
        catch
        {
        }
        sw.Close();
        file.Close();
    }


Т.е. я сохраняю письмо в файл сразу в процессе приема, поэтому передаю в функцию путь к файлу и имя файла. Но теперь функция не возвращает тело сообщения! Я загружаю сохраненный файл и могу его парсить:

msgg = (POP3EmailMessage)MessageList[j];
                                    pop3.RetrieveMessage(msgg, tmp_path, filename);
                                    //узнаем от кого сообщение
                                    CDO.Message msg = new CDO.MessageClass();
                                    ADODB.Stream stream = new ADODB.StreamClass();
                                    stream.Open(Type.Missing, ADODB.ConnectModeEnum.adModeUnknown, ADODB.StreamOpenOptionsEnum.adOpenStreamUnspecified, String.Empty, String.Empty);
                                    stream.LoadFromFile(fullpath);
                                    stream.Flush();
                                    msg.DataSource.OpenObject(stream, "_Stream");
                                    msg.DataSource.Save();
                                    string from = msg.From;
                                    string subject = msg.Subject;
                                    string to = msg.To;
                                    stream.Close();
avatar

admin

  • 28 декабря 2010, 16:21
+
0
Здравствуйте, мне нужно создать что-то вроде такого проекта, может кто подскажет какую литературу или статьи почитать, чтобы было немного понятнее с этим примером?
спасибо
avatar

ilia

  • 25 августа 2012, 15:59
+
0
И еще…
А как мне открыть этот пример в Visual Studio, чтобы он заработал:(
avatar

ilia

  • 25 августа 2012, 16:27
+
-1
Посмотрите эту веточку. Там все обсуждалось. Этот код надо сделать классом, подключить его к своему проекту в студии и использовать.
avatar

admin

  • 28 августа 2012, 13:47
+
0
admin, вы знаете а эта веточка выдает 404 ошибку:(
avatar

ilia

  • 01 сентября 2012, 17:50
+
0
Интересный у вас дизайн, у меня бы так сделать еще: Полезный блог о строительстве и ремонте окна строительные компании москвы.
avatar

temothisni1977

  • 01 сентября 2012, 06:23
+
0
admin, вы знаете а эта веточка выдает 404 ошибку:(
avatar

ilia

  • 01 сентября 2012, 17:49

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.