Implementing a mail server in Python (socket programming)

alex gigh cogs2002 at hotmail.com
Mon May 13 12:43:35 EDT 2002


Implementing a mail server in Python (socket programming)

I sent this email earlier with embedded HTML (because of Hotmail...).
So here is the text version

Hi;

I was surfing the web for Python related sources and I found out that
you know some things about Python programming... I want to program a
mail server (socket programming) writen in Python as part of my Computer 
Science degree in
Sussex University but I am very unfamiliar with Python and socket
programming. I was wondering if you could give me a little help or
guidance regarding this matter. Below, I give some more details about
the mail server that I actually have to produce and some questions I have...
I kindly appreciate your help...

***

I have to design and implement a simple mail server. The program is supposed 
to do two things:

A)

Receive emails from standard mailer. To this purpose it must implement the 
basic commands of SMTP, that is

HELO,
MAIL FROM,
RCPT TO,
DATA,
QUIT.

The messages received must be deposited in users mailboxes.
These will be files the format of which must be compatible with standard 
mailer programs
(so that users can actually read their emails!)
Consider the set of users fixed. (So I don't have to do any administration 
like creating users etc...)
I'm allowed to ignore all file locking problems.
Users must be allowed to specify an antispam file (a kill file):
messages that match keywords specified in such a file must be dropped and 
not inserted in the mailbox.


Some questions I have about these requirements... maybe you're able to 
answer them...

1) How shall I design the format of the kill file so that it's suitable
to solve the assignment. Should I use a file of words, an array of words
or any other data structure? Would I compare every single word in all
mails to each of the words in the kill file? THen maybe a search tree
might be handy....

2) How could/should I implement the mailboxes? Shall I create a folder
for each user and have each message saved as a separate or shall I have
a single file for each user and append each message new to this file?
What would be the (dis)advantages of each approach?

I know that mails end with a "." on a single line. How could I append
new messages to a single file for each user if this is the better way?

***

B)

The server must deliver email messages written in the standard rfc822 
format.
To this purpose, in principle I will have to contact a DNS server to obtain 
the name of the mail exchanger (MX) associated to the given address.
To simplify the task, I'm allowed to either ignore this part, and assume 
that all addresses already refer exclusively to mail exchangers, or I can 
use the function queryMX(hostname) provided below for free. (I put this 
function all the way at the bottom of this email in case it's relevant)
After that, I must contact the mail exchanger at port 25 and play the SMTP 
protocol.

Because SMTP works only with 7bit ASCII data, I will have to mime-encode all 
messages containing more complex stuff.
I'm allowed to use the mimify library (and related ones) of the standard 
Python distribution.

Question: The user agent will use pop3 or IMAP to get the mail from the
mailbox. Is this why I have to decode Mime?


***

I must implement the communication protocols using sockets, and not the 
high-level mailer classes available in Python.
I'm allowed however to use any class I like for local computation, eg 
parsing email files and messages, searching headers, do text manipulation, 
and so on.

I'm not supposed to implement any form of error recovery or reporting. While 
receiving messages, it is acceptable to close the connection if the protocol 
is broken and to drop messages to unknown users;
while delivering, it is enough to report to the terminal that delivery is 
not possible if some serious error occur.


***

Could you please give me ideas on how to tackle this programming
exercise? I have read on Internet protocols and I'm familiar with the
Java programming language (but I must use Python!).


Do you know any open source Python project similar to what I have to do
so that I can have a look at them? All the ones I saw use smtplib, which
I think I'm not allowed to use...


Your help is kindly appreciated...

Thank you very much for helping me and sorry for taking your time!


Alex


















***

The provided queryMX function mentioned above:

The function queryMX(hostname)below returns a list of mail exchanger that 
serve host hostname in strict order of preference. The list will have the 
form of a list of pairs

  [(mailexchanger1, IP_address1),(mailexchanger2, IP_address2),....]
where the first component of a pair is the mail exchanger name and the 
second is its IP address. (Notice that if the list is empty, the host has 
not got any mail exchanger and the message cannot be delivered.) For 
instance, invoking queryMX("cogs.susx.ac.uk") the result is:
[('rsunx.crn.cogs.susx.ac.uk', '139.184.48.12'), 
('tsunb.ctn.cogs.susx.ac.uk', '139.184.50.11'),
('tsunx.ctn.cogs.susx.ac.uk', '139.184.50.12'), ('rinka.central.susx.ac.uk', 
'139.184.14.19'),
('suna9.central.susx.ac.uk', '139.184.32.27')]
Note: This code will only work on Solaris. To adapt it to Windows or Linux, 
you will have to adjust the path to the nslookup executable (most likely 
C:\WINDOWS\SYSTEM32\NSLOOKUP and /usr/bin/nslookup).


The code of the function is as follows.

import os,sys,popen2,re

resolver = "/usr/sbin/nslookup -query=mx "

def queryMX(host):
    mx = []
    addr = {}

    fout,fin = popen2.popen2(resolver + host)

    line = fout.readline()
    while line <> '':
        m = re.search(
            'preference\s*=\s*(\d+),\s*mail\sexchanger\s*=\s*([\w\.]+)',
            line)
        if m:
            mx.append((eval(m.group(1)),m.group(2)))
        else:
            m = re.search(
                '([\w\.]+)\s*internet\saddress\s*=\s*([\d\.]+)',
                line)
            if m: addr[m.group(1)] = m.group(2)

        line = fout.readline()

    if mx == []: return mx

    mx.sort()
    result = []
    for i,k in mx:
        try:
            result.append((k,addr[k]))
        except:
            pass

    return result


_________________________________________________________________
MSN Photos is the easiest way to share and print your photos: 
http://photos.msn.com/support/worldwide.aspx






More information about the Python-list mailing list