Sunday, January 23, 2011

Sending e-mail using C#

Protocols:-its a group of rules that communicates with each other  from network
SMTP-Simple Mail Transfer  Protocol. Its a protocol used to send e-mails .
MTA-Mail Transfer Agent. its a mail server that communicates with other server and clients to fetch mails.
MUA-Mail User Agent. Its an application that lets he user to create and read mails.
1000000596 image001 Sending email with C# using SMTP

1000000596 image002 Sending email with C# using SMTP

Namespaces we used;
System
System.Net.Sockets
System.IO

We used sockets ns to connect to MTA by tcpclient class, IO ns to receive and send the information arrived to netstream object.
You can find the members of our class below
<center>
Member NameDescription
mvarSMTPServerAddress�fully qualified domain name� or the ip address of the MTA (string)
mvarSenderNameThe sender name that will shown in MUA (string)
mvarSenderEmailAddressThe sender email account that we'll inform to MTA. (string)
mvarRecipientNameThe recipient name that will shown in MUA (string)
mvarRecipientEmailAddressThe recipient email account that we'll inform to MTA (string)
mvarEmailSubjectSubject of our email (string)
mvarEmailBodyThe body of our email (string)
mvarSMTPTimeOutTimeout in seconds. (int, default=60)
mvarSMTPRemotePortThe port number of the MTA (int, default=25)
SendEmailThe method that sends the email. (bool)
</center>
We've set the default values of our two properties in our default constructor method.
public SMTPMailSender()
{
mvarSMTPTimeOut = 60;
mvarSMTPRemotePort = 25;
}
Let'shave a look at the heart of our class, the SendEmail() method.
1- We connect to MTA
The method will return a false value at any line if any error occurs.This willhelp us to know that the mail is sent successfully or not.


tclSMTP=new TcpClient();
try
{
tclSMTP.Connect(mvarSMTPServerAddress,mvarSMTPRemotePort);
}
catch
{
return false;
}
If you look at the code above the method willreturn false value if the connection to the mta fails.
2- After our connection is ready, we create an instance of the networkstream tohandle the incoming/outgoing tcpip traffic.To send and receive stringinformation via the networkstream object, we create the streamwriter and thestreamreader classes.
nstSMTP=tclSMTP.GetStream();
stwSMTP=new StreamWriter(nstSMTP);
strSMTP=new StreamReader(nstSMTP);

3- All of our tools for communicating with mta is ready so we can make astart.As i have mentioned in the beginning of this article we'll use the SMTPprotocol.
I'll explain the WaitForResponse method later so it is ok for you to know thatthis method waits for the mta response.  

//mta'dan kar��lama mesaj� bekleniyor
//waiting for greeting message from MTA
if (WaitForResponse("220"))
{
//mta'ya kar��lama mesaj� g�nderiliyor
//sending greeting message to MTA
stwSMTP.WriteLine("HELO " + mvarSMTPServerAddress);
stwSMTP.Flush();
}
else
{
tclSMTP.Close();
return false;

}
Asyou can see above if we get the 220 response from the mta "HELOmail.somemta.com" message is being sent.If any problem occurs in theWaitForResponse method the connection will be closed and the SendEmail() methodwill return false.
The rest of the protocol messages will be send and the responses will bereceived just the same as the above code.The only difference will be the messagethat we send and the response we received.
Nowwe'll have a look at our WaitForResponsemethod;
bool WaitForResponse(string strResponseCode)
{
//zamana��m� kontrol� i�in mevcut tarih saat bilgisi al�n�yor
//gathering current date time data for timeout check
dteTimeOutCheck=DateTime.Now;
//zamana��m� de�eri bulunuyor
//calculating timeout value
TimeSpan tsp=DateTime.Now-dteTimeOutCheck;
//zamana��m� de�eri kullan�c�n�n belirledi�i de�eri a��ncaya kadar d�ng� �al��t�r�l�yor
//looping code until the timeout exceeds the user defined value
while(tsp.Seconds<mvarSMTPTimeOut)
{
//MTA bize herhangi bir mesaj g�ndermi� mi kontrol ediliyor.
//checking if MTA has sent a message to us
if (nstSMTP.DataAvailable)
{
//e�er g�ndermi��se mesaj okunuyor

//if so, get the message
string strIncomingData=strSMTP.ReadLine();
//gelen bilginin protokol numaras� istenen koda uyuyormu kontrol ediliyor
//checking if the requested protocol number matches the server response
if (strIncomingData.Substring(0,strResponseCode.Length)==strResponseCode)
return true;
}
//zamana��m� de�eri yeniden hesaplan�yor
//recalculating the timeout value
tsp=DateTime.Now-dteTimeOutCheck;
}
return false;
}

As you can see this method takes a string parameter, strResponseCode.
This parameter represents the first 3 char of the response we wait from the MTA.
Remember that when we connect with the telnet application we were sendingcommands and waiting for the mta's "250 ok" responses.By sending thefirst 3 char to this method we understand tht the mta has successfully receivedour message and sent us the ok command.If this method returns false weunderstand tht some problem occured and we cut off the connection.
At this stage the only thing we should consider is the timeout property and howwe'll understand the timeout is exceeded or not.
Mta can end the connection by any reason or we can have a network problem.If sohow we'll solve this problem.If we do not create a timeout mechanizm and we havea network connectivity problem the WaitForResponse method will wait until we endour program.This will not be a good solution.
We should store the current datetime value to a variable and check if thedifference exceeds the timeout value.

//zamana��m� kontrol� i�in mevcut tarih saat bilgisi al�n�yor
//gathering current date time data for timeout check
dteTimeOutCheck=DateTime.Now;
//zamana��m� de�eri bulunuyor
//calculating timeout value
TimeSpan tsp=DateTime.Now-dteTimeOutCheck;
//zamana��m� de�eri kullan�c�n�n belirledi�i de�eri a��ncaya kadar d�ng� �al��t�r�l�yor
//looping code until the timeout exceeds the user defined value
while(tsp.Seconds<mvarSMTPTimeOut)
{


//zamana��m� de�eri yeniden hesaplan�yor
//recalculating the timeout value
tsp=DateTime.Now-dteTimeOutCheck;
}

We store the current datetime value to the dteTimeOutCheck variable.
Using the TimeSpan class we can find out the difference between ourdteTimeOutCheck value and the current datetime and if the difference exceeds thetimeout value we return a false value telling the outer block thatWaitForResponse method failed.
Have a look at the following code;

tyle="border:1pt solid windowtext;padding:0in 5.4pt;width:6.45in;" valign="top" width="619">//MTA bize herhangi bir mesaj g�ndermi� mi kontrol ediliyor.
//checking if MTA has sent a message to us
if (nstSMTP.DataAvailable)
{
//e�er g�ndermi��se mesaj okunuyor
//if so, get the message
string strIncomingData=strSMTP.ReadLine();
//gelen bilginin protokol numaras� istenen koda uyuyormu kontrol ediliyor
//checking if the requested protocol number matches the server response
if (strIncomingData.Substring(0,strResponseCode.Length)==strResponseCode)
return true;
}
//zamana��m� de�eri yeniden hesaplan�yor
//recalculating the timeout value
tsp=DateTime.Now-dteTimeOutCheck;

We check that if there is any data waiting to be received in the first line.
At first look this line seems unneccessary.Even we can think that we can write asmaller code with just using �strSMTP.ReadLine()�.Correct but not all thetime.
If we have any problem with the mta or any problem occurs in the protocol flowyou'll see how important this line is.
Assume that we are waiting the 250 response from the mta and somehow the mtaresponded us as "502 unimplemented".
If we do not use the nstSMTP.DataAvailable check we'll receive the 502 commandand because of the 502 is not the message we are waiting for we'll continue towait.If this scenario happens you'll continue waiting the 250 command in thesecond loop.You will wait because the strSMTP.ReadLine() command waits until hehas received any message.Finally you won't reach to the checkpoint of thetimeout mechanizm until the mta sends us the message we wait.
Beleive me it's good to write more code, thinking all the possibilities thanwriting a small but unsafe code.
Yahooo, the last stage , testing the code.
Copy the following code and do not forget to change the mta recipient senderproperties.

using System;
namespace SendMailviaSMTP
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
SMTPMailSender sm=new SMTPMailSender();
sm.SMTPTimeOut=10;
sm.SenderEmailAddress="lyildiz@somemta.com";
sm.RecipientEmailAddress="leventyildiz@gmail.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 has been sent successfully.");
}
else
{
Console.WriteLine("Problem occured.");
}
}
}
}

No comments:

Post a Comment