Welcome to python-pop3server’s documentation!

Contents:

Indices and tables

a python based POP3 Server implementation

due to the lack of pure python based POP3 Servers without mass of dependencies (twisted, ...) I’ve created this POP3 Protocol based implementation. The initial need for it was to get an application ported which was only able to use POP3 a mechanism. As Microsofts Exchange POP3 implementation isn’t really Cluster able the idea to have some kind of proxy/translater as perdition but with protocol change (for example POP3 to IMAP4).

so don’t expect to much from this Proof-of-concept as the focus is only to have a single Application transparently talking to an IMAP server even though it’s implementation is POP3 only.

currently implemented:

  • POP3 Server accepting requestes forwarding to one (start up parameter based) IMAP Server
  • POP3 Protocol types:
    • QUIT
    • STAT
    • LIST
    • RETR
    • DELE
    • NOOP
    • RSET
    • TOP
    • UIDL
    • USER
    • PASS

known limitations:

POP3 is an ASCII only protocol so what ever is stored on the IMAP side is converted to ascii with flag ‘ignore’. In principal this shouldn’t be a problem as your current implementation isn’t able to read UTF8 mails too but I didn’t have time to test all possibilities to avoid exceptions if convert doesn’t work.

seen as:
UnicodeDecodeError: ‘utf8’ codec can’t decode byte 0xfc in position 1847: invalid start byte

fix assumed for 1.1

Example usage:

Terminal 1:

server:

$ ./pop3server.py -b IMAP --backend_address=192.168.192.13 --backend_port=143 -p 10110
serving POP3 service at 127.0.0.1:10110
2014-03-16 17:50:03,180 [POP3Server.DEBUG 240]: S: +OK POP3 server ready
2014-03-16 17:50:05,935 [POP3Server.DEBUG 382]: C: USER
2014-03-16 17:50:05,936 [POP3Server.DEBUG 396]: S: +OK
2014-03-16 17:50:09,589 [POP3Server.DEBUG 382]: C: PASS
2014-03-16 17:50:09,589 [POP3Server.DEBUG 338]: trying to acquire Lock for michi
2014-03-16 17:50:09,590 [POP3Server.DEBUG 342]: stating imap connection
2014-03-16 17:50:09,590 [POP3Server.DEBUG 66]: IMAP: connecting to 192.168.192.13:143
2014-03-16 17:50:12,281 [POP3Server.DEBUG 396]: S: +OK maildrop locked and ready
2014-03-16 17:50:15,259 [POP3Server.DEBUG 382]: C: STAT
2014-03-16 17:50:15,278 [POP3Server.DEBUG 99]: IMAP: fetching INBOX ['2']
2014-03-16 17:50:15,279 [POP3Server.DEBUG 106]: IMAP: retrieve 1
2014-03-16 17:50:15,348 [POP3Server.DEBUG 392]: S: +OK 1 81679
2014-03-16 17:50:22,523 [POP3Server.DEBUG 382]: C: TOP
2014-03-16 17:50:22,530 [POP3Server.DEBUG 388]: S: +OK
2014-03-16 17:53:47,893 [POP3Server.DEBUG 382]: C: QUIT
2014-03-16 17:53:47,894 [POP3Server.DEBUG 137]: IMAP: expunge
2014-03-16 17:53:47,910 [POP3Server.DEBUG 392]: S: +OK POP3 server signing off

Terminal 2:

client:

$ telnet localhost 10110
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
+OK POP3 server ready
USER michi
+OK
PASS xxxxxxxx
STAT
+OK maildrop locked and ready
TOP 1 10
+OK
...
Header + 10 Lines Body supressed ...
QUIT
+OK POP3 server signing off
class pop3server.MailboxLocker

POP3 Mailboxes are single connected, meaning if a user already authenticated successful all others using the same credentials are not allowed to access the same spool. (this would be possible through the backend but breaks POP3 protocol).

acquire()

inline function to unique locking through all the threads

acquire_mailbox(name=None)

retrieve a lock for a specific mailbox name=xx

is_locked(name=None)

return lock status of name=xx

release()

inline function to unique locking through all the threads

release_mailbox(name=None)

release the lock for a specific mailbox name=xx

class pop3server.POP3Backend(protocol=None)

POP3 Backend Interface Class this class defines the methods your Backend implementation should provide

authenticate(username=None, password=None)

authenticate the user with given credentials

cleanup()

cleanup the POP3Backend maildrop for the user (eq. remove files, delete tables, expunge ...

delete(num=None)

remove given item identifier fro the POP3Backend maildrop

destroy()

close handles for POP3Backend

fetch()

populate self.protocol.messages with what ever is in the POP3Backend maildrop for the user

revert()

revert already marked items for deletion/rollback transactions, ...

class pop3server.POP3Backend_IMAP(protocol=None, host=None, port=143, timeout=5.0)

IMAP based Backend this backend provides the “translation” between POP3 and IMAP details as follows:

  • IMAP message -> converted -> ascii (flag ignore=just leave the character out of the Unicode result)
  • IMAP INBOX messages only (if you filter move messages to subfolders they are not recognized by the Backend)
  • POP3 -> plain text authentication only (as this is proxied to the remote)
  • IMAP special user monitor, the user monitor with pwd monitor is used for unittesting and monitoring purpose
authenticate(username=None, password=None)

try to proxy authenticate agains IMAP with POP3 given values

cleanup()

purge all marked message from IMAP spool

delete(num=None)

delete (==flag) message (num=xx) from IMAP spool

fetch()

retrieve all messages from IMAP spool limited to 10 for testing

revert()

revert deleted (==flaged) message from IMAP spool

class pop3server.POP3Backend_IMAPS(protocol=None, host=None, port=993, timeout=5.0)

IMAP based Backend using SSL as transport currently no certificate hanlding is done, silently ignored

class pop3server.POP3Message(content=None)

represents a POP3 Message to be displayed on the User MUA

as_string()

return the complete message

get_body()

return the body of the message

get_headers()

return only the headers of the messages

unique_id()

return a unique ID (based upon POP3 impl. md5 sum of message content)

class pop3server.POP3ServerProtocol(request, client_address, server)

the POP3 Server protocol implementation http://tools.ietf.org/html/rfc1081 and http://www.ietf.org/rfc/rfc1939.txt

APOP(digest=None)

apop command An alternate method of authentication is required which provides for both origin authentication and replay protection, but which does not involve sending a password in the clear over the network.

NOT implemented

AUTHORIZATION()

the authorization or welcome banner

DELE(msg=None)

dele command removes a specific message from the spool

LIST(msg=None)

list command returns either one specific or without arguments a list of all messages enumerated and size Examples:

C:    LIST
S:    +OK 2 messages (320 octets)
S:    1 120
S:    2 200
S:    .
      ...
C:    LIST 2
S:    +OK 2 200
NOOP()

noop command for idle connections to avoid tcp timeouts on firewalls or similar

PASS(credentials=None)

pass command sets the password credentials part

QUIT()

quit transaction and session command

RETR(msg=None)

retr command returns a complete specific message

RSET()

rset command resets all actions taken by the MUA (dele os messages is reverted)

STAT()

stat command returns count and size of messages to the MUA

TOP(msg=None, lines=None)

top command returns from a specific message all headers plus n lines of the body

UIDL(msg=None)

uidl command returns a spool unique message id based upon the md5 hashdigest of the message

USER(name=None)

user command sets the user credentials part

handle()

core routing to handle the MUA command requests