In this programming assignment you will implement a SMTP server that receives mail from remote hosts. Your task is to:
The Requirement
The SMTP server listens at port 25 for a remote connection. When a remote host connects to the server, the server spawns a new thread to serve this client. The parent process continues to listen port 25 for other connections.
In the thread, the client initiates the negotiation and the server replies to the client's request.
During step 2 to step 8, if the client says HELLO again, the server needs to discard all the previous data (except the saved messages) and restarts from step 2. see RFC 821 and RFC 2821 for details.
To simplify the implementation, the server must understand the following SMTP commands, and answer them with appropriate reply codes, for the details of SMTP interaction, read RFC 821 and RFC 2821:
Command | Reply Codes |
---|---|
HELO or EHLO | 250 500 501 503 |
MAIL FROM | 250 500 503 |
RCPT TO | 250 500 503 |
DATA | 354 451 |
QUIT | 221 |
You only need to implement the following message header, if an unrecognized field is detected, treat the previous processed line(s) as message body and process the remaining content as message body:
Message Header Field | Processing |
---|---|
From: | no |
To: | no |
Subject: | yes |
Date: | yes |
Content-Type: | yes |
Content-Transfer-Encoding: | yes |
MIME-Version: | yes |
Message-ID: | no |
Importance: | no |
User-Agent: | no |
field starts with "X" | no |
A subset of MIME extension over SMTP is needed. This extension reserves the traditional SMTP commands and architecture, but it extends the capability of mail service to include items ssuch as such as file attachments, multimedia and richtext formatted email. You can look at RFC 2045 & RFC 2046 for details.
For the ease of programming, all file attachments only use Base64 or
7bit(plain-text) encoding. The Base64
class is
already provided for you. This
links to the Base64
class API homepage. If you want
to use another Base64 java class from public domain, you are free to
do so.
The MIME extension is capable to encapsulate 8-bit character as message text, for example, you can transfer Chinese characters as message text.
In this project, Java SDK Version 1.4.1 is used. Windows platform or UNIX platform are both accepted.
The program consists of four classes:
MailServer | The Mail Server |
MessageSave | Save the message body to system |
SMTPConnection | Thread class for SMTP connection to client |
Base64 | Base64 encoder for MIME |
You need to complete the code in the
SMTPConnection
class and MessageSave
class so
that in the end you will have a program that is capable of receiving
mail and storing it in the system. The code for the other two classes
are provided.
The places where you need to complete the code have been marked
with the comments /* Fill in */
. Each of the places
requires one or more lines of code.
The MailServer
is the frontend of the SMTP server. When
a new connection is established, MailServer
creates a
new object SMTPConnection
for handling this client.
SMTPConnection
is the core part of the server, it
negotiates with the client and responds to every request issued by
the client. After the client sends the whole message to the
server, SMTPConnection
creates another object called
MessageSave
and puts the message body, sender address
and receiver address into it. MessageSave
reads every
line in the data and determines the message header, message body,
MIME header and MIME body. if the message body or MIME body is
base64 encoded, MessageSave
calls Base64
for decoding. Afterwardsl, the message body is broken into the message body
and attachments, and saved into a new directory (directory name
is generated by MessageSave
.)
To make it easier to debug your program, do not, at first,
include the code that opens the socket in SMTPConnection
, but use the following
definitions for fromClient
and toClient
.
This way, your program sends the commands to the terminal. Acting as
the remote host, you will need to give the correct reply codes. When
your program works, add the code to open the socket to the server.
fromClient = new BufferedReader(new InputStreamReader(System.in)); toClient = System.out;
The lines for opening and closing the socket, i.e., the lines
connection = ...
in the constructor and the line
connection.close()
in function close()
,
have been commented out by default.
Start by completing the method fetch()
and
parseHELO()
You will need this function in many places.
In the function reply()
, you should use the
function writeBytes()
to write the commands to the
server. The advantage of using writeBytes()
instead of
write()
is that the former automatically converts the
strings to bytes which is what the server expects. Do not forget to
terminate each command with the string CRLF.
In MessageSave
class, you need to handle the message
body received by the server; the simplest way to get it right is to
investigate a real SMTP connection,
or create a fake SMTP server and use Outlook or Eudora to send an
email to your fake server, thus you can grab the raw data for
testing. But remember to follow the RFC specification.
You need to identify message header and message body clearly, or otherwise, information may be lost and the whole message may be corrupted.
Don't use a huge file as attachment as the decoding time is long.
In then laboratory, server cannot bind port 25 in UNIX platform; you need to use port number higher than 1024 for testing.