Creating a POP3 Server
(Page 1 of 5 )
A POP3 server is a protocol that follows the RFC 1939 specification. It responds to a set of commands issued by a pop3 client. A POP3 Server is basically a go between, between a pop3 Client and a mail server. In this article, we will create the code to respond to those commands issued by a pop3 client such as Microsoft Outlook or Eudora.
A downloadable file for this article (for testing purposes) is available here.
A downloadable zip of the source code is also available here.
Aim of the Application
To implement the complete set of commands as specified in RFC 1939. We want our POP3 server to be usable by almost any POP3 client.
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, on how to install Indy on your computer.
Code
POP3 works in three states: AUTHORIZATION, TRANSACTION and UPDATE. In the AUTHORIZATION state, the server authenticates the pop3 client; in other words, it asks for a username and password, and will react accordingly. The second state is the TRANSACTION state; in this state, the server is ready to receive commands. It is at this stage that any pop3 client can ask how many email messages there are on the mail server, for example. The third state is the UPDATE state, in which the server updates its contents; for example, it deletes messages that were marked for deletion. Below is a list of commands used in each state:
Basic POP3 Commands (work in all implementations)
* Commands in the AUTHORIZATION state:
USER name
PASS string
QUIT
* Commands in the TRANSACTION state:
STAT
LIST [msg]
RETR msg
DELE msg
NOOP
RSET
* Commands in the UPDATE state:
QUIT
Optional POP3 Commands (only work in some implementations)
* Commands in the AUTHORIZATION state:
APOP name digest
* Commands in the TRANSACTION state:
TOP msg n
UIDL [msg]
POP3 ALWAYS replies with either: +OK (if everything's fine) and -ERR (if everything's not fine).
Below is an intercepted transaction between a POP3 client(Outlook) and our POP3 server(the one you are about to create):
127.0.0.1:1102 Stat Connected.
127.0.0.1:1102 Sent 04/02/2006 03:12:56: +OK Welcome to the POP3
Server<EOL>
127.0.0.1:1102 Recv 04/02/2006 03:12:56: CAPA<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:12:56: +OK Capability list
follows<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:12:56: UIDL<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:12:56: USER<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:12:56: .<EOL>
127.0.0.1:1102 Recv 04/02/2006 03:12:56: USER jack<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:12:56: +OK Password
required<EOL>
127.0.0.1:1102 Recv 04/02/2006 03:12:56: PASS password<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:12:58: +OK Login OK<EOL>
127.0.0.1:1102 Recv 04/02/2006 03:12:58: STAT<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:12:58: +OK 4 161<EOL>
127.0.0.1:1102 Recv 04/02/2006 03:13:00: RETR 1<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:00: +OK message follows<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:00: From:
admin@localhost<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:00: To:
admin@example.com<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:00: Subject: Devarticles
Example1<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:00: <EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:00: This is the msg
body<EOL><EOL><EOL><EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:00: .<EOL>
127.0.0.1:1102 Recv 04/02/2006 03:13:18: RETR 2<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: +OK message follows<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: From: luke@loop.com<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: To:
mess.Recipients.EMailAddresses<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: Subject: Devarticles
example2<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: <EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: Devarticle example2
body<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: .<EOL>
127.0.0.1:1102 Recv 04/02/2006 03:13:18: RETR 3<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: +OK message follows<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: From: jack@loop.com<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: To:
mess.Recipients.EMailAddresses<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: Subject: Devarticle
example3<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:18: <EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:19: The body of the msg<EOL>
127.0.0.1:1102 Sent 04/02/2006 03:13:19: .<EOL>
127.0.0.1:1102 Stat Disconnected.
0.0.0.0:0 Stat Disconnected.
In the above intercept, the very first thing that the pop3 server does when the client connects is send a welcome message, then the login process starts. The pop3 client logs on to the server by giving its username as "jack" and its password as "password." The server checks this out and replies "+OK;" if the log in name or password was wrong, it would have replied with "+ERR." The client then proceeds to request all messages on the server with the command "RETR." Don't worry about all the other commands between authentication and "RETR;" we will get to them shortly.
Since these commands are defined in RFC1939, and new commands are added all the time, it is worth taking a look now and then. As far as this tutorial is concerned, we do not need to worry about that, as our pop3 server will implement all the basic commands needed to run a useful service.
Now that you have an idea of how a pop3 client and pop3 server communicate, let's start coding!
Before we start coding, it is very important that we deal with message storage. When a new message is created and sent, it is usually stored somewhere (mail server). When someone wants to get those messages they need to be retrieved from wherever they are stored.
The RFC1939 does not specify a method of storage, so I choose to store my messages in a Microsoft access database. You can of course use whatever method you like to store the messages. Some people use email files (.eml) to store the messages. For example, if you have two mailboxes, one for Jane and another for John, then you would create folders named Jane and John and store their messages in the .eml format in their respective folders.
If you are going to use a database to store your messages, please go to http://delphi.about.com/ where you will find a database course that I believe is the best on the net. But for now, just follow the code. It is very easy to understand, since you will basically be retrieving and deleting data from a database. I've included a database with this app for you to test with.
Start Delphi, and create a new application. Drop the following components on the form:
Components | From Tab | Rename to: |
Tidpop3server | Indy Server | pops |
TidMessage | Indy Misc | mess |
TidServerInterceplogfile(optional) | Indy Intercept | logfile |
TAdoConncetion | ADO | AdoConnection1 |
TADOtable | ADO | Ado1 |
TADOQuery | ADO | q2 |
Next: Setting the database connections >>
More Delphi-Kylix Articles
More By Leidago