You are on page 1of 22

Creating an SMTP Server (Page 1 of 5 )

A downloadable file for this article (for purposes of testing) is available here. A downloadable zip of the source code is also available here.

Introduction An SMTP Server stores mail messages in an ordered way. The server gets the messages from an SMTP Client. For example, if you create and send a new message from a mail client such as Eudora or Outlook Express, an SMTP Client will carry this message to an SMTP Server associated with the domain in a mail address. A typical email address consists of a name and domain name i.e., john@whatever.com, so the sending client will transport the message to the receiving server. The server will then store the message, so that a pop3 server can retrieve it later. To summarize, the purpose of an SMTP Server is to store messages received from SMTP Clients. If you want to learn more about pop3 servers, check out my article here; it's a companion piece to this one. Aims of the Application Like any communications protocol, the SMTP Server communicates through commands and replies. So in this tutorial we will implement all the commands that are needed to create a fully functional SMTP Server. The following commands are needed: USERNAME PASSWORD MAIL FROM RCPT TO DATA

What you need If you have Delphi 6 and above, then you can skip this section; otherwise go to http://www.indyproject.org/ and download the version appropriate to your Delphi version. I am using Delphi 7 and Indy 10.1.15. There are proper guides available on the indy site that explain how to install Indy on your computer. Let's get started Start Delphi, and create a new application. Drop the following components on the form: Components TidSMTPserver TidMessage TidServerInterceplogfile(optional) TAdoConncetion TADOtable TADOQuery From Tab Indy Server Indy Misc Indy Intercept ADO ADO ADO Rename to: pops mess logfile AdoConnection1 Ado1 q2

Creating an SMTP Server - Setting the database connections (Page 2 of 5 ) Click on adoconnection1 and go to the object inspector's properties tab. Then click on the ellipses button next to ConnectionString property. A dialog box should pop up (see below).

Make sure that "Use Connection String" is selected and click on build. Another dialog box should pop up (see below).

Select the "Microsoft.Jet.OLEDB.4.0" option and click next. A dialog box like the one below should appear:

The only thing you change on this dialog box is question number 1. Click on the ellipses button and go to where you've downloaded the database that I've included in this tutorial. DO NOT CHANGE ANYTHING ELSE IN THIS DIALOG BOX! Click OK and OK again. On adoconnection1's properties tab, go to the "loginPrompt" and select "False." That's it! Next, click on ado1's "connection" property in the object inspector and select "ADOConnection1." Do the same for q2 and we are done with the database set up!

Creating an SMTP Server - Optional (Page 3 of 5 )

1. Create a text file. Give it any name you like.

2. Click on logfile, then go to the object inspector's "FileName" property and point to the location of a text file that you've created. The reason for doing this is to see the communication between the pop3 client and your pop3 server. Also it makes it easy for you to debug. GUI We do not actually require a GUI for the server, but for debugging purposes it is useful, so I'm putting this in the optional section. Add eight labels, a memo and two buttons, and arrange them to your liking. You should have something like this:

Creating an SMTP Server - The Code (Page 4 of 5 ) Take a look at the communication between an SMTP Server and a client. This is an intercept: 127.0.0.1:3976 Stat Connected. 127.0.0.1:3976 Sent 18/02/2006 18:03:57: 220 Welcome to SMTP Server<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:03:57: EHLO LEIDAGO<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:57: 250-Hello LEIDAGO <EOL>250-AUTH LOGIN<EOL>250-ENHANCEDSTATUSCODES<EOL>250 PIPELINING<EOL>

127.0.0.1:3976 Recv 18/02/2006 18:03:57: AUTH LOGIN<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:57: 334 VXNlcm5hbWU6<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:03:57: amFjcXVlcw==<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:57: 334 UGFzc3dvcmQ6<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:03:57: bm9haA==<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:57: 235 2.7.0 welcome Leidago<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:03:57: RSET<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:57: 250 Ok<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:03:57: MAIL FROM: <admin@localhost><EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:57: 250 2.1.0 admin@localhost Address Okay<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:03:57: RCPT TO:<admin@localhost.com><EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:57: 250 2.1.5 admin@localhost.com Address Okay<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:03:58: RSET<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:58: 250 Ok<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:03:58: RSET<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:03:58: 250 Ok<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:04:01: MAIL FROM: <admin@localhost><EOL> 127.0.0.1:3976 Sent 18/02/2006 18:04:01: 250 2.1.0 admin@localhost Address Okay<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:04:01: RCPT TO:<admin@localhost.com><EOL>

127.0.0.1:3976 Sent 18/02/2006 18:04:01: 250 2.1.5 admin@localhost.com Address Okay<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:04:01: DATA<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:04:01: 354 Start mail input; end with <CRLF>.<CRLF><EOL> 127.0.0.1:3976 Recv 18/02/2006 18:04:01: From: admin@localhost <admin@localhost><EOL>Subject: hello<EOL>To: admin@localhost.com<EOL>Date: Sat, 18 Feb 2006 18:03:57 +0000<EOL><EOL><EOL> 127.0.0.1:3976 Recv 18/02/2006 18:04:01: <EOL>.<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:04:01: 250 Ok<EOL> 127.0.0.1:3976 Recv 18/02/2006 18:04:01: QUIT<EOL> 127.0.0.1:3976 Sent 18/02/2006 18:04:01: 221 Signing Off<EOL> 127.0.0.1:3976 Stat Disconnected. 0.0.0.0:0 Stat Disconnected. ************************** End intercept************************ I will heavily comment the code where it is not easy to work out what is happening. This procedure is triggered when the server receives a message: procedure TForm1.IdSMTPServer1MsgReceive(ASender: TIdSMTPServerContext; AMsg: TStream; var LAction: TIdDataReply); var lmsg : TIdMessage; LStream : TFileStream; toad,from,sub,body:string; abuff:tstrings; six:int64; begin CoInitialize(nil); //get message size.. six:=amsg.Size; LStream := TFileStream.Create(ExtractFilePath (Application.exename) + 'test.eml', fmCreate); Try

//put message contents in LStream... LStream.CopyFrom(AMsg, 0); Finally FreeAndNil(LStream); End; mess.NoDecode:=true; //Load the message into idMessage component mess.LoadFromFile('test.eml',false); label4.Caption:=datetostr(mess.Date); label1.Caption:=mess.Recipients.EMailAddresses; label2.Caption:=mess.From.Address; label3.Caption:=mess.Subject; memo1.Lines.Text:=mess.Body.Text; //if mess.From.Address <> '' then begin ado1.TableName:='email'; ado1.Active:=true; ado1.Insert; ado1.FieldByName('to').Text:=mess.Recipients.EMailAddresses; ado1.FieldByName('from').Text:= mess.From.Address; ado1.FieldByName('subject').Text:=mess.Subject; ado1.FieldByName('mbody').AsString:=mess.Body.Text; //Date: Wed, 1 Feb 2006 17:34:43 +0000 ado1.FieldByName('mdate').AsDateTime:=mess.Date; ado1.FieldByName('msize').value:=six; ado1.FieldByName('ismarked').value:=0; ado1.Post; CoUnInitialize; //end; end; The message is received in a stream and is therefore stored physically on disk by the TFilestream method. It is loaded again to be stored in the database. Next is the rcptTo command, here you just validate the entered emailAddress. The Address is stored in the "AAddress: String;" bit of the procedure header. All that I did here is to check that the entered email address contains a '@' character, since all email addresses have to contain one. If the email address contains a '@' character then Vaction is set to AddressOK, otherwise it's set to InValid or any of the responses outlined in the code below:
procedure TForm1.IdSMTPServer1RcptTo(ASender: TIdSMTPServerContext; const AAddress: String; var VAction: TIdRCPToReply; var VForward: String); begin // The following actions can be returned to the server: { rAddressOk, //address is okay rRelayDenied, //we do not relay for third-parties

rInvalid, //invalid address rWillForward, //not local - we will forward rNoForward, //not local - will not forward - please use rTooManyAddresses, //too many addresses rDisabledPerm, //disabled permanently - not accepting E-Mail rDisabledTemp //disabled temporarily - not accepting E-Mail } if Pos('@', AAddress) > 0 then VAction := rAddressOk; end else begin VAction :=rInvalid; end; end; procedure TForm1.IdSMTPServer1Received(ASender: TIdSMTPServerContext; var AReceived: String); begin // This is a new event in the rewrite of IdSMTPServer for Indy 10. // It lets you control the Received: header that is added to the e-mail. // If you do not want a Received here to be added, set AReceived := ''; // Formatting 'keys' are available in the received header -please check // the IdSMTPServer source for more detail. AReceived := ''; end; procedure TForm1.IdSMTPServer1UserLogin(ASender: TIdSMTPServerContext; const AUsername, APassword: String; var VAuthenticated: Boolean); begin // This event is fired if a user attempts to login to the server // Normally used to grant relay access to specific users etc. //Search for the username and password in "users" table.. q2.SQL.Text := 'SELECT * from users WHERE uname=:user AND upass=:pwd'; q2.Parameters.ParamByName('user').Value :=AUsername; q2.Parameters.ParamByName('pwd').Value := APassword; q2.open; //if the user is not found, set authentication to false if q2.RecordCount = 0 then begin VAuthenticated := False; end else begin VAuthenticated := True; end; end; Same as RcptTo, check if the email address contains a '@' character and reply accordingly... begin

procedure TForm1.IdSMTPServer1MailFrom(ASender: TIdSMTPServerContext; const AAddress: String; var VAction: TIdMailFromReply); begin // Here we are testing the MAIL FROM line sent to the server. // MAIL FROM address comes in via AAddress. VAction sets the return action to the //server. // The following actions can be returned to the server: { mAccept, mReject } if Pos('@', AAddress) > 0 then VAction:= mAccept; end else begin VAction := mReject; end; end; procedure TForm1.FormCreate(Sender: TObject); begin idsmtpserver1.Greeting.SetReply(220,'Welcome to SMTP Server'); end; procedure TForm1.IdSMTPServer1Execute(AContext: TIdContext); begin logfile.DoLogWriteString(acontext.Connection.IOHandler.ReadLn); end; procedure TForm1.IdSMTPServer1Exception(AContext: TIdContext; AException: Exception); begin acontext.Connection.IOHandler.Write(aexception.Message); end; begin

Creating an SMTP Server - Conclusion (Page 5 of 5 ) To test the server in Outlook Express enter "localhost" for both POP3/SMTP servers and use the username and passwords from the database's users table. Note that Outlook Express requires both an SMTP and POP3 server to be running prior to sending messages, so use the code from my previous POP3 Server tutorial to build a POP3 Server and run them both on your machine. Then start sending email messages! You can of course use these programs in a LAN environment or in a company as long as there's a network. I've included an empty MS Access database (available for download at the beginning of this article) for testing purposes. The Entire Code
unit usmtps; interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, IdIntercept, IdServerInterceptLogBase, IdServerInterceptLogFile, DB, ADODB, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, IdCmdTCPServer, IdExplicitTLSClientServerBase, IdSMTPServer, IdMessage,idcontext,idsync,ActiveX; type // just some testrecord TTestRec = record IntField : integer; CharField : char; ByteField : byte; StrField : string[20]; end; PTTestRec = ^TTestRec; TShowMessageSync = class(TIdSync) protected FMsg: TIdMessage; public procedure DoSynchronize; override; constructor Create(tMsg: TIdMessage); reintroduce; class procedure Show(tMsg: TIdMessage); end; TForm1 = class(TForm) btnserveron: TButton; btnserveroff: TButton; IdSMTPServer1: TIdSMTPServer; ado1: TADOTable; q: TADOQuery; ADOConnection1: TADOConnection; LogFile: TIdServerInterceptLogFile; mess: TIdMessage; Label1: TLabel; StaticText1: TStaticText; StaticText2: TStaticText; Label2: TLabel; Label3: TLabel; StaticText3: TStaticText; Memo1: TMemo; Label4: TLabel; StaticText4: TStaticText; procedure btnserveronClick(Sender: TObject); procedure btnserveroffClick(Sender: TObject); procedure IdSMTPServer1MsgReceive(ASender: TIdSMTPServerContext; AMsg: TStream; var LAction: TIdDataReply); procedure IdSMTPServer1Connect(AContext: TIdContext); procedure IdSMTPServer1RcptTo(ASender: TIdSMTPServerContext; const AAddress: String; var VAction: TIdRCPToReply; var VForward: String); procedure IdSMTPServer1Received(ASender:

TIdSMTPServerContext; var AReceived: String); procedure IdSMTPServer1UserLogin(ASender: TIdSMTPServerContext; const AUsername, APassword: String; var VAuthenticated: Boolean); procedure IdSMTPServer1MailFrom(ASender: TIdSMTPServerContext; const AAddress: String; var VAction: TIdMailFromReply); procedure FormCreate(Sender: TObject); procedure IdSMTPServer1Execute(AContext: TIdContext); procedure IdSMTPServer1Exception(AContext: TIdContext; AException: Exception); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} constructor TShowMessageSync.Create(tMsg: TIdMessage); begin inherited Create; FMsg := tMsg; end; procedure TShowMessageSync.DoSynchronize; begin Form1.Label2.Caption := FMsg.From.Address; Form1.Label1.Caption := FMsg.Recipients.EMailAddresses; Form1.Label3.Caption := FMsg.Subject; Form1.Memo1.Lines.AddStrings(FMsg.Body); end; class procedure TShowMessageSync.Show(tMsg: TIdMessage); begin with Create(tMsg) do try Synchronize; finally Free; end; end; procedure TForm1.btnserveronClick(Sender: TObject); begin btnServerOn.Enabled := False; btnServerOff.Enabled := True; IdSMTPServer1.active := true; end;

procedure TForm1.btnserveroffClick(Sender: TObject); begin btnServerOn.Enabled := True; btnServerOff.Enabled := False; IdSMTPServer1.active := false; end; procedure TForm1.IdSMTPServer1MsgReceive(ASender: TIdSMTPServerContext; AMsg: TStream; var LAction: TIdDataReply); var lmsg : TIdMessage; LStream : TFileStream; toad,from,sub,body:string; abuff:tstrings; six:int64; begin CoInitialize(nil); six:=amsg.Size; LStream := TFileStream.Create(ExtractFilePath (Application.exename) + 'test.eml', fmCreate); Try LStream.CopyFrom(AMsg, 0); Finally FreeAndNil(LStream); End; mess.NoDecode:=true; mess.LoadFromFile('test.eml',false); label4.Caption:=datetostr(mess.Date); label1.Caption:=mess.Recipients.EMailAddresses; label2.Caption:=mess.From.Address; label3.Caption:=mess.Subject; memo1.Lines.Text:=mess.Body.Text; //if mess.From.Address <> '' then begin ado1.TableName:='email'; ado1.Active:=true; ado1.Insert; ado1.FieldByName('to').Text:=mess.Recipients.EMailAddresses; ado1.FieldByName('from').Text:= mess.From.Address; ado1.FieldByName('subject').Text:=mess.Subject; ado1.FieldByName('mbody').AsString:=mess.Body.Text; //Date: Wed, 1 Feb 2006 17:34:43 +0000 ado1.FieldByName('mdate').AsDateTime:=mess.Date; ado1.FieldByName('msize').value:=six; ado1.FieldByName('ismarked').value:=0; ado1.Post; CoUnInitialize; //end; end; procedure TForm1.IdSMTPServer1Connect(AContext: TIdContext); begin //idsmtpserver1.Greeting.SetReply(220,'Welcome to Leidago Server');

//logfile.Accept(acontext.Connection); end; procedure TForm1.IdSMTPServer1RcptTo(ASender: TIdSMTPServerContext; const AAddress: String; var VAction: TIdRCPToReply; var VForward: String); begin // The following actions can be returned to the server: { rAddressOk, //address is okay rRelayDenied, //we do not relay for third-parties rInvalid, //invalid address rWillForward, //not local - we will forward rNoForward, //not local - will not forward - please use rTooManyAddresses, //too many addresses rDisabledPerm, //disabled permanently - not accepting E-Mail rDisabledTemp //disabled temporarily - not accepting E-Mail } if Pos('@', AAddress) > 0 then VAction := rAddressOk; end else begin VAction :=rInvalid; end; end; begin

procedure TForm1.IdSMTPServer1Received(ASender: TIdSMTPServerContext; var AReceived: String); begin // This is a new event in the rewrite of IdSMTPServer for Indy 10. // It lets you control the Received: header that is added to the e-mail. // If you do not want a Received here to be added, set AReceived := ''; // Formatting 'keys' are available in the received header -please check // the IdSMTPServer source for more detail. AReceived := ''; end; procedure TForm1.IdSMTPServer1UserLogin(ASender: TIdSMTPServerContext; const AUsername, APassword: String; var VAuthenticated: Boolean); begin // This event is fired if a user attempts to login to the server // Normally used to grant relay access to specific users etc. //Search for the username and password in "users" table.. q2.SQL.Text := 'SELECT * from users WHERE uname=:user AND upass=:pwd'; q2.Parameters.ParamByName('user').Value :=AUsername; q2.Parameters.ParamByName('pwd').Value := APassword;

q2.open; //if the user is not found, set authentication to false if q2.RecordCount = 0 then begin VAuthenticated := False; end else begin VAuthenticated := True; end; end; procedure TForm1.IdSMTPServer1MailFrom(ASender: TIdSMTPServerContext; const AAddress: String; var VAction: TIdMailFromReply); begin // Here we are testing the MAIL FROM line sent to the server. // MAIL FROM address comes in via AAddress. VAction sets the return action to the //server. // The following actions can be returned to the server: { mAccept, mReject } if Pos('@', AAddress) > 0 then VAction:= mAccept; end else begin VAction := mReject; end; end; procedure TForm1.FormCreate(Sender: TObject); begin idsmtpserver1.Greeting.SetReply(220,'Welcome to SMTP Server'); end; procedure TForm1.IdSMTPServer1Execute(AContext: TIdContext); begin logfile.DoLogWriteString(acontext.Connection.IOHandler.ReadLn); end; procedure TForm1.IdSMTPServer1Exception(AContext: TIdContext; AException: Exception); begin acontext.Connection.IOHandler.Write(aexception.Message); end; end. begin

DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational

purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. Creating an Email Client with Borland Delphi (Page 1 of 4 )

A downloadable zip of the source code is available here.

Introduction There are many ways to send email messages from your Delphi application; for example, you can use shellexecute by declaring ShellApi in your uses list, or you can simply use Delphi's built in support for Windows Simple Mail Api, but this requires MS Outlook to be installed both on your computer and that of the recipient. The other downside to this is that you will not be able to send attachments, so neither of these options are ideal. Another approach is to use Indy. Indy is a group of Internet components that comprises all popular Internet protocols, such as POP3, HTTP, ICMP, and so on. Although there are lots of other free Internet component suites available, most of them do not have the standard of quality that you find in the Indy components. The only problem I find with Indy components is that there is not enough support available on their usage. This is mainly because Indy is an open source project and the development of demos to demonstrate how to use the components is very slow. A recent major change, which brought about Indy 10, was made for the Dot Net Framework and as this is the latest version, appropriate for both the Dot Net and Win32 platforms, it is suffering from a severe lack of demos. I am therefore writing this tutorial to show how to use some of the components available in the latest version of Indy. Despite these problems, Indy components remain popular among Delphi developers and are by far the easiest and most efficient way to write Internet related applications. To start with, we are going to create an email application that is going to provide us with a basis for building a full fledged Mail Client. A mail client has two primary roles: one, to receive messages and two, to send messages. We will be focussing on sending messages. This application will be able to send messages, both with and without attachments, and will also give us a way to ascertain whether the message has been delivered to the recipient. For those of you who cannot afford Microsoft's Outlook Express or who want their own Mail Client that will do exactly what you want it to do, please read on. Requirements for this Application:

We want the application to send messages (obviously!). We want it to be able to send attachments (both single and multiple). We want confirmation of receipt and delivery (confirmation message should be send to your email address). Creating an Email Client with Borland Delphi - What you need (Page 2 of 4 ) You need to have Indy 9 or 10 installed. If you have Delphi 6 and above, then you can skip this section; otherwise go to www.indyproject.org and download the version appropriate to your Delphi version. I am using Delphi 7 and Indy 10.0.52. There are proper guides on how to install Indy on your computer. I'm writing this tutorial on the assumption that you know how to use Delphi. If this is not the case then I would recommend you go to http://delphi.about.com for a beginner's course, before continuing. Lets' get started! Start up Delphi and create a new application - File | new | Application. For the purposes of this tutorial I will save the unit as mailer and the project as emailer. You can save it as anything you like. Drop a memo, five edit boxes, five static labels, a list box and two buttons on the form. Call button one "btBrowse" and button two "btMsg". Name the listview as lvAttachments and the five edit boxes as edTo, edFrom, edSubject, edCC, edBC. Call the five static labels From, To, CC, BC and subject. Also add a checkbox, an opendialog and another static label, and name it attachments. Go to the Indy Clients tab and get the idSMTP component, then go to the Indy Misc tab and get the idmessage component, and drop both of them onto the form. Indy Clients tab:

Indy Misc tab:

Now let me explain what these two components are and what use they are to our application.

IdSMTP: This is basically a component that allows you to connect and communicate with the SMTP Server. To connect to an SMTP Server you need to have a hostname and password. These are usually available from your ISP, unless of course you installed your own SMTP server. IdMessage: This is a component that will take in all the headers of a message, such as who the message is from, who it is going to, the subject, body, CC and BCC. In other words, all the headers that you see on email messages. In addition, this component also handles the attachment(s) that you will send with your messages. To summarize: IdSMTP allows you to connect to the (SMTP) server with the host and password parameters and is also the component that actually sends the message. Without this component the message won't go anywhere. IdMessage component holds all the message headers, including any attachments. IdMessage literally needs to be filled with the message parts. At this point your application should look something like this:

Creating an Email Client with Borland Delphi - Coding (Page 3 of 4 ) Now that we've finished building the GUI we can start coding. Add "idreplysmtp" to your uses list, then double click on btMsg and add the following code: procedure Tform1.btMsgClick(Sender: TObject); begin

//setup idSMTP connection parameters idSMTP.Host :=your host name; idSMTP.Port := 25; //smtp service usually runs on this port idSMTP.Password:=your password; //setup idmessage parameters idmessage.From.address:=edFrom.Text; idmessage.Recipients.EMailAddresses:=edTo.Text; idmessage.CCList.EMailAddresses:=edCC.Text; idmessage.BccList.EMailAddresses:=edBC.Text; idmessage.Subject :=edSubject.Text; idmessage.Body.Text := memo1.Lines.Text; //check if receipt confirmation is required if checkbox1.checked then //if required, set the sendback email address to your email address idmessage.ReceiptRecipient.Text:=edfrom.Text; //send the message try try idSMTP.Connect; idSMTP.send(idmessage); //if an exception occurs except on E: EIdSMTPReplyError do begin //then show the message ShowMessage(E.Message); end; end; finally //disconnect from server if IdSMTP.Connected then IdSMTP.Disconnect; end; end; Let's go through this bit of code: The first thing I've done is set up the server connection by providing the password and host name. The hostname is usually written this way: mail.xxx.com or smtp.xxxx.com.

Then I've continued to fill the idmessage component with the email headers, which in this case are: from, to, CC, BCC, subject and body. Please note that I also put a condition in place to check whether the user requires a delivery confirmation. This will enable you to check whether the message has actually been delivered to the recipient. I connected to the server and sent the message and then I closed the connection to the server. It is very important that you close the server connection, as you will get an error if you want to send another message. It is also good memory management. The "idreplysmtp" unit contains the definitions for all possible errors or exceptions that can be raised throughout this operation. Now double click the browse button and add the following code: procedure Tform1.btBrowseClick(Sender: TObject); begin if opendialog.Execute then TIdAttachmentFile.Create(idmessage.MessageParts, opendialog.FileName); AddAttachments; end; The browse button calls up the opendialog and allows you to select a file to attach to your message. Then it goes on to call the AddAttachments procedure to add the filename(s) to the listview. Add this procedure somewhere in the implementation section: procedure Tform1.AddAttachments; var li: TListItem; idx: Integer; begin //clear the attachment listview lvAttachments.Items.Clear; //loop through Idmessage and count parts for idx := 0 to Pred(Idmessage.MessageParts.Count) do begin li := lvAttachments.Items.Add; // Check if Idmessage contains any attachments if Idmessage.MessageParts.Items[idx] is TIdAttachmentFile then begin //if so, get the file names li.Caption := TIdAttachmentFile (Idmessage.MessageParts.Items[idx]).Filename; //and add them to the listview li.SubItems.Add(TIdAttachmentFile (Idmessage.MessageParts.Items[idx]).ContentType); end else

begin li.Caption := Idmessage.MessageParts.Items[idx].ContentType; end; end; end; In short, the above procedure adds files to the listview component by looping through the idMessage component, checking whether it contains any attachments. If it does contain attachments, then it gets the filenames and lists them in the listview. This way you can see what files you've attached to your message. Make sure to add "procedure AddAttachments" in the public section of your form. That's it! You have a fully functioning email application. All of our requirements have been met. Creating an Email Client with Borland Delphi - Improvements/Remarks (Page 4 of 4 ) Giving persistence to your server login details: if you have more that one set of login details, you can use either an ini or text file to store your login details and get the application to read them in when it starts up. Alternatively, you can use the registry or a database to store these values if you are concerned about security. If you want to store the messages that you send, to reference later, you might want to create a small database to store them in. Address Book: You can create a small Access database to store email addresses and retrieve them as and when necessary. Message Sent notification You will notice that nothing happens after you've sent a message. It is possible to greatly improve this by adding a progress bar that indicates that the message has been sent. Use IdSMTP's onwork, workbegin and onworkEnd event handlers, together with the progressbar. When the work is finished you could bring up a dialog saying "Message Sent" or something to that effect. This will assure the user that something is happening. Possible bugs Sometimes when I send messages to email addresses ending in ".co.uk" the application crashes. I've reported this to the Indy group, and hopefully this will be fixed in the near future. What Next? Although you are now able to send messages, what happens when you want to see what messages have been sent to you, or you want to see whether a message you sent has been received or not? That is what the next installment of this project will focus on. It will use the popular POP3 protocol to download all your messages from your POP3 server and allow you to read, reply to and delete them as you require.

DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware.

You might also like