Jump to content

C# Ile Smtp Sunuculari Kullanarak Mail Göndermek


wmismail

Recommended Posts

C# ile SMTP sunuculari kullanarak mail göndermek

Tüm yazilimci arkadaşlara selamlar,

Bu makalemde size SMTP protokolünün isleyisinden ve c# ile SMTP mail sunucularini kullanarak nasıl mail gönderebilecegimizden bahsedecegim.

Ilk önce SMTP nedir? MTA MTU nedir? protokol nedir? biraz bu kavramlardan bahsedelim.

Protokol – Network üzerinden çalisan yazilimlarin birbirleri arasinda haberlesmeleri için kullandiklari kurallar topluluguna denir.

SMTP Simple Mail Transfer Protocol yani Basit Mesaj Transfer Protokolüdür.Ilgili RFC kaydi Agustos 1982'de yazilmistir.Outlook uygulamasinda bir mail yazdigimiz zaman outlook bu maili SMTP

protokolü kurallarina uyarak mail sunucusuna iletir.

MTA Mail Transfer Agent - Bugün hepimizin kullanmakta oldugu mail sunucularidir.

Ornegin Microsoft Exchange Server.

MTU Mail User Agent - Mail yazmak ve okumak için kullandigimiz yazilimlardir.

En basit örnegi outlook express veya Outlook uygulamalari olacaktir.

Asagida MTA ve MUA iletisimi ve SMTP protokolü akis diyagramlarini bulabilirsiniz.

1000000596_image001.jpg

1000000596_image002.jpg

Peki SMTP protokolünün kurallari nelerdir?

Ilk önce yapmak istedigimizi c# kullanmadan yapmamiz ve bu protokolün nasıl isledigini görmemiz gerekir.Çünkü yapmaya çalistigimiz sey tamamen görsellikten uzak, network haberlesmesidir.

MUA kullanmadan ilk mailimizi msdos komut satirini kullanarak gönderecegiz.

Diyelimki Forumda msn, mail, adres, gerçek isim vs. bilgilerinizi paylaşmayınız[/b].com]leventyildizForumda msn, mail, adres, gerçek isim vs. bilgilerinizi paylaşmayınız.comadresine test konulu bir mesaj gondermek istiyoruz.

Yapmamiz gereken command prompt’u çalistirip, telnet ile MTA’ya baglanmaktir.

C:\>telnet mail.somemta.com 25

Bu komutu yazdigimizda MTA bize asagidaki gibi bir mesaj gönderecektir.

220 mail.somemta.com ESMTP

Karsi komut olarak asagidaki komutu yazin ve enter tusuna basin

HELO mail.somemta.com

MTA bizden komut bekledigini belirten

250 mail.somemta.com

mesajini gösterecektir.

Bu asamadan sonra yapmamiz gereken mailin kim tarafindan, kime ve ne içerikle gönderileceginin bilgisini vermek olacaktir.

Mailin kim tarafindan gönderildigini belirtmek için asagidaki komutu yazip enter tusuna basin.

mail from:[email protected]

sunucu bize komutun alindigina dair asagidaki mesaji verecektir.

250 ok

Simdi mesaji kime gönderecegimizin bilgisini içeren asagidaki komutu yazip enter tusuna basin.

rcpt to:leventyildizForumda msn, mail, adres, gerçek isim vs. bilgilerinizi paylaşmayınız.com

yine sunucu bize komutun alindigina dair asagidaki mesaji verecektir.

250 ok

Buraya kadar sanirim problem yok J

Simdi mesajimizin içerigini yazabiliriz.Bu bölümde yazacagimiz bilgiler MUA’da görünecek bilgilerdir.Mesajin kimden geldigi kime gittigi mesaj konusu ve içerigi.

Bu detaylari girmemiz için asagidaki komutu yazip enter tusuna basin.

data

sunucu bize komutun alindigina dair asagidaki mesaji verecektir.

354 go ahead

Bu bölüme kadar yazdigimiz komutlar sonucunda enter tusuna bastigimizda sunucu bizden komutu aldigina dair 250 ok mesajlari göndermekteydi.Biz data komutunu yazdiktan sonra bu degisecektir.Artik enter tusuna bastigimizda sunucudan herhangi bir onay almayacagiz.

Bu moddan çikmak için “<Enter> . <Enter>” (enter tusuna basilacak , nokta tusuna basilacak, enter tusuna basilacak) tuslamamiz gerekecektir.

Simdi mesajin içerigini yazalim.

From:Levent YILDIZ ACME Inc.

To:Levent YILDIZ MINDSTORM Inc.

Subject:ilk command prompt emailimiz

Bu telnet kullanarak gönderdigimiz ilk mail

.

data kismini yazdiktan sonra sunucu bize maili aldigina dair asagidaki gibi bir mesaj gönderecektir.

250 ok 1118680536 qp 21248

Bu mesaj sunucunun tipine göre degisebilir.Önemli olan 250 ok kismidir.

Evet artik mailimizi kontrol edebiliriz.

Eger bu asamada herhangi bir sorun ile karsilasirsaniz bu baglandiginiz MTA’nin güvenlik ayarlari ile ilgili olabilir.Çogu sistemler bugün “POP-before-SMTP” yöntemini kullanarak SMTP güvenligini saglamaktadir.Yani mail göndermeden önce sunucuya POP protokolü ile baglanip uname ve password göndermeniz ve sunucunun bunu dogrulamasi gerekir.Bu dogrulama sonucu sunucu size 1 saatligine SMTP baglantisi izni verir.

Gelelim asil konuya.Bunu c# kullanarak nasıl gerçeklestirecegiz?

Gerekli bütün kod asagidadir.Koda bir göz atin…

usingSystem;

usingSystem.Net.Sockets;

usingSystem.IO;

namespaceSendMailviaSMTP

{

public class SMTPMailSender

{

string mvarSMTPServerAddress;

string mvarSenderName;

string mvarSenderEmailAddress;

string mvarRecipientName;

string mvarRecipientEmailAddress;

string mvarEmailSubject;

string mvarEmailBody;

int mvarSMTPTimeOut;

int mvarSMTPRemotePort;

TcpClient tclSMTP;

NetworkStream nstSMTP;

StreamReader strSMTP;

StreamWriter stwSMTP;

DateTime dteTimeOutCheck;

public SMTPMailSender()

{

mvarSMTPTimeOut = 60;

mvarSMTPRemotePort = 25;

}

public bool SendEmail()

{

//SMTP sunucusu ile baglanti kuruluyor //Connecting to SMTP Server tclSMTP=new TcpClient();

try {

tclSMTP.Connect(mvarSMTPServerAddress,mvarSMTPRemotePort);

}

catch {

return false;

}

nstSMTP=tclSMTP.GetStream();

stwSMTP=new StreamWriter(nstSMTP);

strSMTP=new StreamReader(nstSMTP);

//mta'dan karsilama mesaji bekleniyor //waiting for greeting message from MTA if (WaitForResponse("220"))

{

//mta'ya karsilama mesaji gönderiliyor //sending greeting message to MTA stwSMTP.WriteLine("HELO " + mvarSMTPServerAddress);

stwSMTP.Flush();

}

else {

tclSMTP.Close();

return false;

}

if (WaitForResponse("250"))

{

//gönderici email adresi gönderiliyor //sending sender email address to MTA stwSMTP.WriteLine("mail from:" + mvarSenderEmailAddress);

stwSMTP.Flush();

}

else {

tclSMTP.Close();

return false;

}

if (WaitForResponse("250"))

{

//alici email adresi gönderiliyor //sending recipient email address to MTA stwSMTP.WriteLine("rcpt to:" + mvarRecipientEmailAddress);

stwSMTP.Flush();

}

else {

tclSMTP.Close();

return false;

}

if (WaitForResponse("250"))

{

//mail'i yazmak için data moduna geçiliyor //switching to data mode for entering body of the mail stwSMTP.WriteLine("data");

stwSMTP.Flush();

}

else {

tclSMTP.Close();

return false;

}

if (WaitForResponse("354"))

{

//mesajin body kismi hazirlaniyor //preparing the body section of the email string strSMTPData="";

strSMTPData="From:" + mvarSenderName + Environment.NewLine;

strSMTPData+="To:" + mvarRecipientName + Environment.NewLine;

strSMTPData+="Subject:" + mvarEmailSubject + Environment.NewLine + Environment.NewLine;

strSMTPData+=mvarEmailBody + Environment.NewLine + "." + Environment.NewLine;

//mesaj gönderiliyor //sending message stwSMTP.Write(strSMTPData);

stwSMTP.Flush();

}

else {

tclSMTP.Close();

return false;

}

if (WaitForResponse("250"))

{

//gönderim başarıli ise değer true döndürülüyor //returns true if the send process succeeds tclSMTP.Close();

return true;

}

else {

tclSMTP.Close();

return false;

}

//gönderim başarısiz ise değer false döndürülüyor //returns false if the send process fails tclSMTP.Close();

return false;

}

bool WaitForResponse(string strResponseCode)

{

//zamanasimi kontrolü için mevcut tarih saat bilgisi aliniyor //gathering current date time data for timeout check dteTimeOutCheck=DateTime.Now;

//zamanasimi değeri bulunuyor //calculating timeout value TimeSpan tsp=DateTime.Now-dteTimeOutCheck;

//zamanasimi değeri kullanıcının belirledigi değeri asincaya kadar döngü çalistiriliyor //looping code until the timeout exceeds the user defined value while(tsp.Seconds<mvarSMTPTimeOut)

{

//MTA bize herhangi bir mesaj göndermis mi kontrol ediliyor. //checking if MTA has sent a message to us if (nstSMTP.DataAvailable)

{

//eger göndermissse mesaj okunuyor //if so, get the message string strIncomingData=strSMTP.ReadLine();

//gelen bilginin protokol numarasi istenen koda uyuyormu kontrol ediliyor //checking if the requested protocol number matches the server response if (strIncomingData.Substring(0,strResponseCode.Length)==strResponseCode)

return true;

}

//zamanasimi değeri yeniden hesaplaniyor //recalculating the timeout value tsp=DateTime.Now-dteTimeOutCheck;

}

return false;

}

public string SMTPServerAddress

{

get{return mvarSMTPServerAddress;}

set{mvarSMTPServerAddress=value;}

}

public string SenderName

{

get{return SenderName;}

set{mvarSenderName=value;}

}

public string SenderEmailAddress

{

get{return SenderEmailAddress;}

set{mvarSenderEmailAddress=value;}

}

public string RecipientName

{

get{return RecipientName;}

set{mvarRecipientName=value;}

}

public string RecipientEmailAddress

{

get{return RecipientEmailAddress;}

set{mvarRecipientEmailAddress=value;}

}

public string EmailSubject

{

get{return EmailSubject;}

set{mvarEmailSubject=value;}

}

public string EmailBody

{

get{return EmailBody;}

set{mvarEmailBody=value;}

}

public int SMTPTimeOut

{

get{return SMTPTimeOut;}

set{mvarSMTPTimeOut=value;}

}

public int SMTPRemotePort

{

get{return SMTPRemotePort;}

set{mvarSMTPRemotePort=value;}

}

}

}

Link to comment
Share on other sites

Kullandigimiz namespace’ler

System

System.Net.Sockets

System.IO

Sockets ns ini MTA’ya tcpclient ile baglanmak için, IO ns ini ise networkstream’e gelen bilgileri okumak için kullandik.

Sinifimizin üyelerini incelememiz gerekirse;

Üye ismi

Açiklama

mvarSMTPServerAddress

MTA’nin ip adresi veya “fully qualified domain name”’I (string)

mvarSenderName

Mail client uygulamasinda gözükecek Gönderici Ismi (string)

mvarSenderEmailAddress

MTA’ya bildirilecek gönderici email adresi.Bu değer eger yanlis gönderilirse MTA’nin tipine göre degisen güvenlik ayarlarinca sunucu ile baglantiniz sonlandirilabilir. (string)

mvarRecipientName

Mail client uygulamasinda gözükecek Alici ismi (string)

mvarRecipientEmailAddress

MTA’ya bildirilecek alici email adresi. (string)

mvarEmailSubject

Gönderecegimiz email’in konusu (string)

mvarEmailBody

Gönderecegimiz email’in mesaj kismi (string)

mvarSMTPTimeOut

Saniye cinsinden zamanasimi süresi (int varsayilan=60)

mvarSMTPRemotePort

MTA’ya baglanilirken kullanilacak port numarasi (int varsayilan=25)

Yapici metodumuzda iki üyenin varsayilan özellikleri atanmistir.

public SMTPMailSender()

{

mvarSMTPTimeOut = 60;

mvarSMTPRemotePort = 25;

}

Sinifimizin kalbi, veritipi bool olan SendEmail() metodunu inceleyelim.

1- MTA’ya baglanti gerçeklestiriliyor

Metodun herhangi bir asamasinda herhangi bir hata olustugu taktirde metod false değerini döndürecek ve biz de bu sayede emailin ulasip ulasmadigini anlayabilecegiz.

tclSMTP=new TcpClient();

try

{

tclSMTP.Connect(mvarSMTPServerAddress,mvarSMTPRemotePort);

}

catch

{

return false;

}

Eger baglantida herhangi bir hata olusursa metodumuz false döndürecektir.

2- Baglanti olustuktan sonra soketten veri alisverisi için gerekli olan networkstream sinifimizi yaratiyoruz.Ayni sekilde bu siniftan da string okuyup yazmak için streamwriter ve streamreader siniflarimizi olusturuyoruz.

nstSMTP=tclSMTP.GetStream();

stwSMTP=new StreamWriter(nstSMTP);

strSMTP=new StreamReader(nstSMTP);

3- Bütün araçlarimizi olusturdugumuza göre artik veri alip gönderebiliriz.Makalenin basinda deginmis oldugum SMTP protokol kurallarina uyarak MTA’ya gerekli mesajlari gönderip MTA’nin cevaplarina göre hareket edecegiz.

Bu satirlarda WaitForResponse metodunu gözardi edin.Ilerleyen satirlarda bu metod’u açiklayacagim.

Bu medodun simdilik sadece MTA’dan ilgili cevabi almak için oldugunu bilmeniz yeterli olacaktir.

//mta'dan karsilama mesaji bekleniyor

//waiting for greeting message from MTA

if (WaitForResponse("220"))

{

//mta'ya karsilama mesaji gönderiliyor//sending greeting message to MTAstwSMTP.WriteLine("HELO " + mvarSMTPServerAddress);

stwSMTP.Flush();

}

else

{

tclSMTP.Close();

return false;

}

Gördügünüz gibi MTA’dan 220 cevabi başarıli bir sekilde alinirsa MTA’ya “HELO mail.somemta.com” mesaji gönderilmektedir.Eger mesaj alisverisinde herhangi bir sorun yasanirsa WaitForResponse metodu false değerini döndürecektir ve sonuç olarak tclSMTP tcpclient baglantisi kapatilip SendEmail metodu false olarak dönecektir.

Diger bütün asamalar mesaj alip gönderme , yani yukaridaki blogun aynisidir.

Sadece gönderilen mesajlar ve alinan cevaplar degisecektir.

Tabi SMTP protokolünün izin verdigi sirada J

Gelelim WaitForResponse metodumuza;

bool WaitForResponse(string strResponseCode)

{

//zamanasimi kontrolü için mevcut tarih saat bilgisi aliniyor//gathering current date time data for timeout checkdteTimeOutCheck=DateTime.Now;

//zamanasimi değeri bulunuyor//calculating timeout valueTimeSpan tsp=DateTime.Now-dteTimeOutCheck;

//zamanasimi değeri kullanıcının belirledigi değeri asincaya kadar döngü çalistiriliyor//looping code until the timeout exceeds the user defined valuewhile(tsp.Seconds<mvarSMTPTimeOut)

{

//MTA bize herhangi bir mesaj göndermis mi kontrol ediliyor.//checking if MTA has sent a message to usif (nstSMTP.DataAvailable)

{

//eger göndermissse mesaj okunuyor//if so, get the messagestring strIncomingData=strSMTP.ReadLine();

//gelen bilginin protokol numarasi istenen koda uyuyormu kontrol ediliyor//checking if the requested protocol number matches the server responseif (strIncomingData.Substring(0,strResponseCode.Length)==strResponseCode)

return true;

}

//zamanasimi değeri yeniden hesaplaniyor//recalculating the timeout valuetsp=DateTime.Now-dteTimeOutCheck;

}

return false;

}

Bu metodumuz gördügünüz gibi string tipinde strResponseCode parametresini almaktadir.

Bu parametre MTA’dan bekledigimiz mesajin kodunu temsil etmektedir.

Hatirlarsaniz bizim MTA’ya gönderdigimiz veriler sonucunda MTA bize “250 ok” “354 go ahead” gibi mesajlar geri göndermekteydi.işte biz bu mesajlarin ilk 3 harfini bu metoda göndererek MTA’nin bize istedigimiz gibi cevap verip vermedigini anlayacagiz.Eger MTA istedigimiz cevabi verirse metod true vermezse false değerini döndürecektir.

Burda kontrol etmemiz gereken bir durum mevcut.Zamanasimi.

Protokolün herhangi bir asamasinda sunucu kasitli veya kasitsiz bir sekilde baglantiya son verebilir.

Bu tür bir durum gerçeklestiginde eger zamanasimi mekanizmamiz olmazsa sürekli sunucunun cevabini bekleriz, programimiz saglikli çalismaz.

Yapmamiz gereken mevcut tarih saat bilgisini bir degiskene atayip döngü içersinde zamanasimi değerini asip asmadigimizi kontrol etmektir.

//zamanasimi kontrolü için mevcut tarih saat bilgisi aliniyor

//gathering current date time data for timeout check

dteTimeOutCheck=DateTime.Now;

//zamanasimi değeri bulunuyor

//calculating timeout value

TimeSpan tsp=DateTime.Now-dteTimeOutCheck;

//zamanasimi değeri kullanıcının belirledigi değeri asincaya kadar döngü çalistiriliyor

//looping code until the timeout exceeds the user defined value

while(tsp.Seconds<mvarSMTPTimeOut)

{

…..

…..

//zamanasimi değeri yeniden hesaplaniyor

//recalculating the timeout value

tsp=DateTime.Now-dteTimeOutCheck;

}

dteTimeOutCheck degiskenine sistemin o anki tarih saat değerini atiyoruz.

TimeSpan nesnesi sayesinde dteTimeOutCheck değeri ile mevcut tarih saat değeri arasindaki farki buluyoruz.While döngüsü kosul bölümünde ise farkin sinif üyesi olan mvarSMTPTimeOut değerini asip asmadigini kontrol ediyoruz.Böylece bir timeout mekanizmasi kurmus oluyoruz.

Simdi isterseniz while döngüsünün içindeki kodu inceleyelim.

//MTA bize herhangi bir mesaj göndermis mi kontrol ediliyor.

//checking if MTA has sent a message to us

if (nstSMTP.DataAvailable)

{

//eger göndermissse mesaj okunuyor//if so, get the messagestring strIncomingData=strSMTP.ReadLine();

//gelen bilginin protokol numarasi istenen koda uyuyormu kontrol ediliyor//checking if the requested protocol number matches the server responseif (strIncomingData.Substring(0,strResponseCode.Length)==strResponseCode)

return true;

}

//zamanasimi değeri yeniden hesaplaniyor

//recalculating the timeout value

tsp=DateTime.Now-dteTimeOutCheck;

Burdaki ilk satirimiz " if (nstSMTP.DataAvailable)” sayesinde networkstream belleginde herhangi bir verinin mevcut olup olmadigini kontrol ediyoruz.

Ilk bakista bu kontrol gereksiz olarak gözükebilir.Hatta isi “strSMTP.ReadLine()” komutu ile çözebilecegimizi düsünebilirsiniz.Hatta pratikte bunu uyguladiginizda herhangi bir hata vermeyecek gayet saglikli çalisacaktir.Fakat diger taraftan protokol akisinda bir problem oldugunu düsünürsek bu kontrolün ne kadar önemli oldugu görülecektir.

Varsayalimki biz MTA’dan 250 cevabini beklerken sunucu bize “502 unimplemented” yani geçersiz bir komut gönderdiniz mesajini gönderdi.Readline ile 502’yi okuyacagiz fakat bekledigimiz mesaj 502 olmadigindan dolayi döngü sonlanmayacak devam edecektir ve tekrar readline() komutu çalisacaktir.

Eger networkstream belleginde herhangi bir mesaj mevcut degil ise Readline metodu imleci birsonraki mesaj gelene kadar tutacaktir.Bu da bizim zamanasimi mekanizmamizin devredisi kalmasina sebep olacaktir ki bu hiç istemedigimiz bir durumdur.

Sira geldi son asamaya , kodun testi.

Asagidaki kodu örnek alip kendi kullanacaginiz MTA adresi, alici gönderici adresi değerlerini degistirmeyi unutmayin.

using System;

namespace SendMailviaSMTP

{

class Class1

{

[sTAThread]

static void Main(string[] args)

{

SMTPMailSender sm=new SMTPMailSender();

sm.SMTPTimeOut=10;

sm.SenderEmailAddress="[email protected]";

sm.RecipientEmailAddress="leventyildizForumda msn, mail, adres, gerçek isim vs. bilgilerinizi paylaşmayınız.com";

sm.SMTPServerAddress="mail.somemta.com";

sm.SenderName="Levent YILDIZ ACME Inc";

sm.RecipientName="Levent YILDIZ MINDSTORM Inc";

sm.EmailSubject="Test subject";

sm.EmailBody="Test Body";

if (sm.SendEmail())

{

Console.WriteLine("Email başarıyla gönderildi.");

}

else{

Console.WriteLine("Email gönderiminde hata olustu.");

}

}

}

}

Bu makalemde c# ile SMTP sunuculari kullanarak nasıl mail gönderecegimizi, hangi siniflara ihtiyacimiz oldugunu anlattim.Umarim yeterince açiklayici olabilmisimdir.Bir sonraki makalemde görüşmek üzere.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...