Makale Özeti

TcpClient kullanılarak Pop3 Protokolü üzerine bir uygulama

Makale

TcpClient ile Pop3 Protokolü uygulaması

System.Net.Sockets namespace'i altında yer alan TcpClient sınıfı ile TCP üzerinden veri alış verişi işlemlerini gerçekleştirebilir ve socket programlama yapabilirsiniz. (Socket sınıfı ile de veri alış verişi yapılabilir.)

TcpClient nesnesinin Connect metodu ile bir sunucuya belirlediğiniz ve sizi bekleyen bir portdan bağlandıktan sonra sunucudan gelen verileri okumak için TcpClient.GetStream metodundan dönen NetworkStream sınıfı türündeki nesnenin Read metodu kullanılabilir. TcpClient ile sunucuya veri aktarımı yapmak için ise yine aynı nesnenin (GetStream metodunda dönen NetworkStream türündeki nesne) Write metodunu kullanılabilir. (Diğer yöntemler ise herhangi bir Stream nesnesini kapsülleyen StreamReader sınıfının kullanılması ve BeginXxx şeklindeki asenkronize metodlar olabilir.)

Pop3 Protokolü Uygulaması

Pop3 ve Smtp ikilisini günlük hayatta sıkça kullanıyoruz. Outlook veya benzeri bir program Pop3 protokolü üzerinden çalışan emaillerinizi okurken emailleri sunucudan çekebilmek için bir standart mesajlaşma yöntemi kullanılır. Esasında bu standartlar sadece Pop3 için değildir. SMTP, NNTP, bu makaleye erişebilmek için kullandığınız HTTP vb. protokoller RFC (Request For Comments) adı verilen dokumanlarda tanımlanmış olan mesaj standartları ile çalışırlar. Benim kullandığım web tarayıcısının her web sunucusu ile sağlıklı iletişim kurmasını sağlayan HTTP standardıdır. Aynı şekilde tüm email sunucular ve email okuma programlarını kullandığı ortak protokol ise RFC1939 (http://www.faqs.org/rfcs/rfc1939.html) ile belirlenmiştir.

Pop3 protokolü ile email sunucunuzdaki emailleri aldıktan sonra emaili anlamlı bir biçim ile sunulması için yine RFC'ler ile tanımlanmış bir biçim olan MIME standardı öğrenilmeli ve mesaj parse edilmelidir.

Örneğimizde email sunucuya bağlanıp kimlik bilgisini gönderip gelenkutusunda email olup olmadığına bakacağız.

Örnek bir POP3 mesaj alışverişi

+OK mail.cengizhan.com Mail Server V.2.0 POP3 Sun, 11 Sep 2005 16:39:16 +0300 <20050911163916@mail.cengizhan.com>
USER test@cengizhan.com

+OK test@cengizhan.com
PASS 123
+OK 1 messages 550 octets
STAT
+OK 1 550
RETR 1
+OK 550 octets
Received: from localhost ([81.22.99.98])
by mail.cengizhan.com with SMTP id XFU27787
for <test@cengizhan.com>; Sun, 11 Sep 2005 16:38:52 +0300
Date: Sun, 11 Sep 2005 16:38:51 +0300
From: Test <test@cengizhan.com>
To: test@cengizhan.com
Subject: mesaj konusu
Message-ID: <d40879cbef3c1dd9bde00d1072b8877d@cengizhan.com>
X-Mailer: IceWarp Web Mail 5.2.5
X-Originating-IP: 85.99.111.177
MIME-Version: 1.0
Content-Type: text/plain; charset="iso-8859-9"
Content-Transfer-Encoding: 7bit

mesaj body
.

DELE 1
+OK Message deleted
QUIT
+OK mail.cengizhan.com closing connection
 

Yukarıdaki mesak alış verişini inceleyelim.

Pop3 sunucusuna bağlandığımızda Pop3 sunucu +OK ile başlayan bir hoşgeldin mesajı gönderir. Pop3 sunucu bizim gönderdiğimiz komutlara iki çeşit cevap dönebilir. +OK (işler yolunda gidiyor) ve -ERR (hata var) bu mesaj başlangıçlarının yanında durum ile ilgili bilgi olması genellikler rastlanan bir durum olsada bu kodumuz için anlamlı bir data olmak zorunda değildir.

Sunucu hoşgeldin mesajını gönderdikten sonra USER komutu ile sunucuya kullanıcı adı gönderiliyor. Sonuç +OK ise yolumuza devam ederiz. (Email sunucuları spamcilere karşı bu komuttan sonra her zaman +OK dönerler aksi takdirde bir POP3 sunucuya girip o sunucuda bulunan email adresleri için brute force yapmaktan çekinmeyecek bir çok spamci bayram ederdi.)

PASS komutu ile bildirdiğimiz kullanıcının şifresini aktarıyoruz. +OK geldiğinde yanında mesaj sayımız ve toplam boyutu yazsada bu protokol standardı olan ve parse edilmesi gereken bir veri değildir.

Sunucuda kaç emailimiz olduğunu öğrenmek için STAT komutunu kullanıyoruz. RETR komutu ile aktarılan çok satırlı veri kümesinin sonlandığını anlamak için yeni satır nokta karakteri ve yeni satır (CRLF.CRLF) karakter üçlüsünü görmemiz gereklidir. Bu protokolün bir standardıdır.

DELE komutu ile email sunucudaki bir email silinebilir. Outlook gibi uygulamalar emailleri önce RETR ile indirir ardından DELE komutu ile silerler. Bazı durumlar emaillerinizi outlook ile indirmekte ike herhangi bir sebepten ötürü email sunucu ile bağlantınızı kaybettiğinizde outlook içerisinden o ana kadar indirilmiş olan emailleri okuyabilirsiniz. Ve terar sunucudan emaillerinizi kontrol etmek istediğinizde ise az önce indirdiğiniz emaillerin tekrar indirildiğini görebilirsiniz. Bunun sebebi ilgili email RETR ile indirildikten sonra DELE komutu çalışacak iken bağlantınızı kopmuş olmasıdır. Ayrıca DELE komutu ile sildiğiniz emaillerin sunucu üzerinden silinmesi için bağlantınızı QUIT komutu çağırarak kapatmanız gerekir. Aksi halde emailler silinmez.

Biz örneğimizde USER, PASS, STAT komutlarını gönderip ilgili hesapta email olup olmadığını öğrenen bir sınıf kütüphanesi hazırlayacağız.

Imports System.Net.Sockets

Public Class Pop3

    Public Host As String

    Public Port As Integer

    Public Username As String

    Public Password As String

 

    Public MailCount As Integer

    Public MailSize As Integer

    Private client As TcpClient

    Public Sub New()

    End Sub

    Public Sub New(ByVal host As String, ByVal port As Integer)

        Me.Host = host

        Me.Port = port

    End Sub

    Public Sub CheckMail()

        client = New TcpClient

        client.Connect(Me.Host, Me.Port)

        Dim strCevap As String

        strCevap = Me.GetResponse

        If Not strCevap.StartsWith("+OK") Then

            client.GetStream.Close()

            client.Close()

            Throw New Exception(strCevap)

        End If

        'işler yolunda, +OK geldi.

        Me.SendMessage("USER " & Me.Username)

        strCevap = Me.GetResponse

        If Not strCevap.StartsWith("+OK") Then

            client.GetStream.Close()

            client.Close()

            Throw New Exception(strCevap)

        End If

        'işler yolunda, +OK geldi.

        'PAROLA gönderilecek

        Me.SendMessage("PASS " & Me.Password)

        strCevap = Me.GetResponse

        If Not strCevap.StartsWith("+OK") Then

            client.GetStream.Close()

            client.Close()

            Throw New Exception(strCevap)

        End If

        Me.SendMessage("STAT")

        strCevap = Me.GetResponse

        If Not strCevap.StartsWith("+OK") Then

            client.GetStream.Close()

            client.Close()

            Throw New Exception(strCevap)

        End If

        'STAT'dan dönen sonuç ayrıştırılacak.

        Dim cevaplar() As String

        cevaplar = strCevap.Split(" ")

        '+OK 3 300 geldiyse

        'cevaplar(0) +OK olur

        'cevaplar(1) 3 olur

        'cevaplar(2) 300 olur

        Me.MailCount = cevaplar(1)

        Me.MailSize = cevaplar(2)

        client.GetStream.Close()

        client.Close()

    End Sub

    Private Function GetResponse() As String

        'enter bulunana kadar karakterleri oku, geriye dön.

        Dim strOnceki As String

        Dim strSimdiki As String

        Dim strMesaj As String

        Dim ns As NetworkStream

        ns = client.GetStream

        While True

            Dim buffer(0) As Byte '1 byte 1 byte okuyoruz

            ns.Read(buffer, 0, buffer.Length)

            strSimdiki = System.Text.Encoding.GetEncoding(1254).GetString(buffer)

            strMesaj = strMesaj + strSimdiki

            If strSimdiki = vbLf AndAlso strOnceki = vbCr Then

                'eğer enter yakalandıysa 10 ve 13 arka arkaya

                Exit While

            End If

            strOnceki = strSimdiki

        End While

        Return strMesaj

    End Function

    Private Sub SendMessage(ByVal str As String)

        str = str + vbCrLf 'Controlchars.CrLf '10+13

        Dim buffer() As Byte = System.Text.Encoding.GetEncoding(1254).GetBytes(str)

        Dim ns As NetworkStream = client.GetStream

        ns.Write(buffer, 0, buffer.Length)

    End Sub

End Class

 

Yukarıdaki sınıfı test etmek amacı ile aşağıdaki kod bloğunu yazalım. Tabi email sunucu adresi ve kimlik bilgilerinizi istediğiniz şekilde düzenlemeniz gerekmekte. J

  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Try

            Dim p3 As New Pop3Library.Pop3("mail.cengizhan.com", 110)

            p3.Username = "test@cengizhan.com"

            p3.Password = "123"

            p3.CheckMail()

            MsgBox(p3.MailCount & " : " & p3.MailSize)

        Catch ex As Exception

            MsgBox(ex.Message)

        End Try

    End Sub

Yukarıda gördüğümüz gibi email sunucusunda kaç emailimiz var ve toplam boyutu nedir bilgilerine erişebildik.

Şimdi bu veriyi biraz daha işe yarar biçimde sunmak için kodlarını makalenin ekindeki zip dosyasında bulabileceğiniz bir form oluşturalım. Ve bu uygulama email kutumuzda emailimiz var ise bunu bize mouse işaretçisinin peşinde gezinen minik bir form ile göstersin.



Uygulama Kodları

Cengiz HAN
Microsoft ASP.NET MVP
cengiz@cengizhan.com

Uygulama Kodları