Sending email with C# using SMTP

In this article i'll try to explain how we can send emails using SMTP servers.
First of all, what is SMTP what is MTA,MUA, protocol? Let's start talking about these subjects.

Pencil Sending email with C# using SMTP Protocol�
Protocol is a group of rules which is used by applications that communicate each other from network.�
SMTP
Simple Mail Transfer Protocol.
Is a protocol used to transfer emails.First RFC was published in August1982.We can say that when we compose a message in an outlookapplication and send it, the outlook application sends this email tomail server by using the smtp protocol.
MTA
Mail Transfer Agent.
Is the mail servers which communicates both with other email serversand clients to fetch emails.For example : Qmail,Postfix,Courier…
MUA
Mail User Agent
Is the applications that lets users to read & compose emails.For example: Outlook Express

Here you can find a diagram that explains the network topology.

1000000596 image001 Sending email with C# using SMTP

This diagram shows the communication between the MTA and MUA

1000000596 image002 Sending email with C# using SMTP

What are the rules of SMTP protocol?

SMTP is a protocol (application free) therefore we are able to send anemail without using C# which i prefer to show this using telnet.Nowwe'll send an email to leventyildiz@gmail.com by using telnet.Our mailtransfer agent's address is mail.somemta.com and we'll send this emailby using our existing account lyildiz@somemta.com .

Run the command prompt and enter the following line;
C:\>telnet mail.somemta.com 25

When we enter this command the mta will respond us as follows;
220 mail.somemta.com ESMTP

To finish handshake with the mta enter the following line;
HELO mail.somemta.com

The mta will respond us, telling us that handshaking is ok;
250 mail.somemta.com

At this stage we will inform mta about the email's sender and recipient.
To inform the sender account enter the following line;
mail from:lyildiz@somemta.com

Mta will respond us telling us tht he has received the information.
250 ok

Now we'll send the recipient information by entering the following line;
rcpt to:leventyildiz@gmail.com

Mta should respond us as follows;
250 ok

Hope you don't have any problems J
Now we are ready to write the content of our email.The information we'll enter here will be shown in mua.
We declare mta tht we are ready to enter the email content by entering the followingline;
data

Mta should respond as follows;
354 go ahead

Till now mta was responding us on each of our command by sending us the message "250 ok"
But after we enter the "data" command mta won't respond our comments until we enter the escape command.
The escape command is �<Enter> . <Enter>� (press enter , press . and enter , press enter)�

Let's write the contentFrom:Levent YILDIZ ACME Inc.
To:Levent YILDIZ MINDSTORM Inc.
Subject:our first mail sent by C#�

This mail has been sent by C#

.

After we enter the escape command mta should respond as follows;
250 ok 1118680536 qp 21248

This ok message can vary by the type of the mta.The important section is the "250 ok" part.

Now we can check our email.

If you have experienced any problems till this stage, that problems mayhave been occured by the securty properties of your mta.Most of the mtasystems use "POP-before-SMTP" securty which does not allow users toconnect to SMTP port if the user has not been granted by the POPprotocol.I advise you to get support from your mail administrator.

So let's get to the point.How we will achieve this by C#?Below code is all you need.Take a look at it…

using System;
using System.Net.Sockets;
using System.IO;
namespace SendMailviaSMTP
{
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 ba�lant� 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 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;
}
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"))
{
//al�c� 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("35
4"))
{
//mesajin body k�sm� haz�rlan�yor
//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�l� 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�s�z ise de�er false d�nd�r�l�yor
//returns false if the send process fails
tclSMTP.Close();
return false;
}
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;
}
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;}
}
}
}

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 Name Description
mvarSMTPServerAddress �fully qualified domain name� or the ip address of the MTA (string)
mvarSenderName The sender name that will shown in MUA (string)
mvarSenderEmailAddress The sender email account that we'll inform to MTA. (string)
mvarRecipientName The recipient name that will shown in MUA (string)
mvarRecipientEmailAddress The recipient email account that we'll inform to MTA (string)
mvarEmailSubject Subject of our email (string)
mvarEmailBody The body of our email (string)
mvarSMTPTimeOut Timeout in seconds. (int, default=60)
mvarSMTPRemotePort The port number of the MTA (int, default=25)
SendEmail The 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.");
}
}
}
}


Horaaayy i received the email.
Hope you do so….

Levent YILDIZ
Gulf Agency Company � TURKEY
IT Manager
MCP
msmoracle@hotmail.com

Related Articles :

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

No comments yet... Be the first to leave a reply!