CRSMail is built upon standards.
The main goal of CRSMail was flexibility. A new feature could be added by simply creating a new class implementing
the required interface. Then by listing this class in the config file the new feature is available. The entire
architecture builds on this idea.
A mail server needs two main servers an smtp server to accept incomming mail and a pop3 server to allow mail
to be downloaded and read. The server assumes each of these run in their own threads. At startup the mail server
starts the threads then main exits.
I guess I better start with some use case diagarams.
User Checking mail
+----+ +-------+ +-----------+
|User|<---POP3--->|CRSMail|<--Plugin-->|POP3 Server|
+----+ +-------+ +-----------+
User Sending mail
+----+ +-------+ +-----------+
|User|<---SMTP--->|CRSMail|<--Plugin-->|SMTP Server|
+----+ +-------+ +-----------+
Someone sending mail to a local user from the outside
+----+ +-----------+ +-------+ +----------+ +-----------+ +-------------+ +--------------+
|User|-SMTP->|Mail Server|-internet->|CRSMail|->|SMTPServer|->|User Plugin|->|StorageManger|-->|Storage Plugin|
+----+ +-----------+ +-------+ +----------+ +-----------+ +-------------+ +--------------+
Someone sending mail to a local user that gets forwarded somewhere else
+----+ +-----------+ +-------+ +----------+ +------------------+ +-----------+
|User|-SMTP->|Mail Server|-internet->|CRSMail|->|SMTPServer|->|ForwardMail Plugin|->SMTP->|Mail Server|
+----+ +-----------+ +-------+ +----------+ +------------------+ +-----------+
Configuring the server. Plain text file
+-----+ +-------+
|Admin|--->|Notepad|
+-----+ +-------+
Server configuration
The entire server is configured by use of a config file. Each line consists of a key=value pair.
Any line starting with a # is ignored. This is handled by com.calvinrsmith.shared.ConfigManager If a key is
found called ConfigManager.DB with a value of true then after the parsing ConfigManager hits a database table for
the rest of the key/value pairs. If a key is hit more than once then the new value is appended to any current
value.
Now lets talk about the server startup.
To start the server run class com.calvinrsmith.CRSMail.Server.Mail On startup
the class com.calvinrsmith.CRSMail.Config is loaded to load the options from the mail.conf
file. Then the server starts the ball rolling by loading services and servers after which it's job
is over. A service is a class that want's to be initilized at startup for example a database service
will want to login to the database at startup and setup it's connection pools. A server is a class that will
wait for an incomming connection and then handle the connection. Each service must start before the next one
begins to start. Each server is derived from a thread so they all start at the same time.
What should be a service and what should be a server? Simple. Anything that listens for an
incomming port connection should be a server. Anything that will be needed by more than one server should be
a service thus keeping hidden interaction between servers to a minimal. If two servers are very closly linked and
no other server would ever need to talk to them then they could just talk directly.
NOTE: There is only one instance of every service.
Current services and what they do:
com.calvinrsmith.CRSMail.server.DBService - Manage connections to the database. Uses
com.calvinrsmith.shared.DBPool for connection pooling
com.calvinrsmith.CRSMail.server.UsersService - Manage the users of the system.
com.calvinrsmith.CRSMail.server.StorageService -Store the users messages.
Current servers and what they do:
com.calvinrsmith.CRSMail.server.SMTPServer - Handle SMTP connections. Incomming mail
com.calvinrsmith.CRSMail.server.POP3Server - Handle POP3 connections. Mail checks.
com.calvinrsmith.CRSMail.server.TransferMailServer - Transfer mail from another account to this one.
In depth detail of the classes already mentioned:
UsersService - CRSMail can manage mail for multiple domains each of which could get their user names from more than
one place. For example for domain1 the user names come from the configuration file and a database table, domain2
gets it's user names from an LDAP server, domain3, get's it's names from the domain1 user table and then adds
a new table for some other names and domain4 will accept any user listed in it's section of the config file as well
as any user in it's table which is in it's own database.
To accept this wide array of users all the users information are handles by a Users service. Then any server
that wants to check if a user is local can call the service with the name of the user and what domain the
user is in.
StorageService - Manages where the messages are stored. This gives the CRSMail storage independence. This
service defines an interface for plugins to support various methods of storing mail. The simplist is to store each
message in it's own file under the users directory. Other ideas would be to use a database or another servers
format to make it easy to migrate from the other server to CRSMail. Using a database could give a quick response
time, however, the attachments should probably not be stored in the databsase.
TransferMailServer - Transfer mail from another email address to one hosted by CRSMail. This gives the user
the ability to check several mailboxes at once. An option could be inserted so that if the system looks for a
reply-to address and if not found the insert one of the address just checked. This allows any replied messages to
get replied back to where the first one came from.
MailAPI
MailAPI is a package to send and recieve mail. com.calvinrsmith.MailAPI.SendMail is the interace for
sending mail. There is low level API to send each line of the an RFC822 message as well as a high level API to
send mail by specifing the subject, body and attachments. The high level API simply encodes the message to RFC822
then calls the low level api to send the message. SMTP messages can be sent with com.calvinrsmith.MailaPI.SMTP
This simply sends the mail once. If the send fails then it gives up. com.calvinrsmith.MailaPI.QueueSMTP
can be used to insert a message into a queue and uses SMTP to send the message. If the send fails then the
message goes back to the end of the queue to be tried again later. QueueSMTP extends SMTP so that either can be
used just as easily. QueueSMTP uses a seperate thread to manage the queue. What other kinds of SendMail should
there be? com.calvinrsmith.MailAPI.CheckMail is an interface for checking mail. Once again both high level and
low level API's are provided for getting the RFC822 message or just strings for the subject, body and filenames for
the attachments. POP3 implements CheckMail to allow for checking of pop3 servers. IMAP4 can be created to allow
for the checking of IMAP servers.
In the case of webmail it will use the high level routines exlusivly whereas the server will use mostly the
low level routines.
There will also be some classes to encode a message into MIME and to decode it from MIME.
Here are the relevent RFC's:
Layout of an email message
SMTP Protocol
POP3 Protocol
MIME Types part 1
MIME Types part 2
Future enhancments to the system:
Built in mailing list. Sending mail to qwert.list@server.com will send the message to
everyone on the qwert list.
Other ideas as to how to use the server.
Configure it for SMTP only, using an SMTP plugin that can fax as the only plugin. Give this plugin a user name. Now
every time someone emails fax@faxserver.com the fax is sent. If you also want to run a mail server then the plugin could
be used in the server as everything else. However if you want a dedicated fax server and a dedicated mail server and don't
wish to worry about emailing the fax to the right mail server you can use ForwardMail to forward the mail for fax to the
fax server which will in turn fax it. Neat huh?