"""A POP3 client class. Based on the J. Myers POP3 draft, Jan. 96 Author: David Ascher [heavily stealing from nntplib.py] """ __version__ = "0.01a - Feb 1, 1996 (with formatting changes by GvR)" # Example (see the test function at the end of this file) TESTSERVER = "localhost" TESTACCOUNT = "test" TESTPASSWORD = "_passwd_" # Imports from types import StringType import regex import socket import string # Exception raised when an error or invalid response is received: error_proto = 'pop3.error_proto' # response does not begin with + # Standard Port POP3_PORT = 110 # Line terminators (we always output CRLF, but accept any of CRLF, CR, LF) CRLF = '\r\n' # This library supports both the minimal and optional command sets: # Arguments can be strings or integers (where appropriate) # (e.g.: retr(1) and retr('1') both work equally well. # # Minimal Command Set: # USER name user(name) # PASS string pass_(string) # STAT stat() # LIST [msg] list(msg = None) # RETR msg retr(msg) # DELE msg dele(msg) # NOOP noop() # RSET rset() # QUIT quit() # # Optional Commands (some servers support these) # APOP name digest apop(name, digest) # TOP msg n top(msg, n) # UIDL [msg] uidl(msg = None) # class POP3: def __init__(self, host, port = POP3_PORT): self.host = host self.port = port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(self.host, self.port) self.file = self.sock.makefile('rb') self._debugging = 0 self.welcome = self._getresp() def _putline(self, line): line = line + CRLF if self._debugging > 1: print '*put*', `line` self.sock.send(line) # Internal: send one command to the server (through _putline()) def _putcmd(self, line): if self._debugging: print '*cmd*', `line` self._putline(line) # Internal: return one line from the server, stripping CRLF. # Raise EOFError if the connection is closed def _getline(self): line = self.file.readline() if self._debugging > 1: print '*get*', `line` if not line: raise EOFError if line[-2:] == CRLF: line = line[:-2] elif line[-1:] in CRLF: line = line[:-1] return line # Internal: get a response from the server. # Raise various errors if the response indicates an error def _getresp(self): resp = self._getline() if self._debugging > 1: print '*resp*', `resp` c = resp[:1] if c != '+': raise error_proto, resp return resp # Internal: get a response plus following text from the server. # Raise various errors if the response indicates an error def _getlongresp(self): resp = self._getresp() list = [] while 1: line = self._getline() if line == '.': break list.append(line) return resp, list # Internal: send a command and get the response def _shortcmd(self, line): self._putcmd(line) return self._getresp() # Internal: send a command and get the response plus following text def _longcmd(self, line): self._putcmd(line) return self._getlongresp() # These can be useful: def getwelcome(self): return self.welcome def set_debuglevel(self, level): self._debugging = level # Here are all the POP commands: def user(self, user): user = str(user) return self._shortcmd('USER ' + user) def pass_(self, pswd): pswd = str(pswd) return self._shortcmd('PASS ' + pswd) def stat(self): retval = self._shortcmd('STAT') rets = string.split(retval) numMessages = string.atoi(rets[1]) sizeMessages = string.atoi(rets[2]) return (numMessages, sizeMessages) def list(self, msg=None): if msg: msg = str(msg) return self._longcmd('LIST ' + msg) else: return self._longcmd('LIST') def retr(self, which): which = str(which) return self._longcmd('RETR ' + which) def dele(self, which): which = str(which) return self._shortcmd('DELE ' + which) def noop(self): return self._shortcmd('NOOP') def rset(self): return self._shortcmd('RSET') # optional commands: def apop(self, digest): digest = str(digest) return self._shortcmd('APOP ' + digest) def top(self, which, howmuch): which = str(which) howmuch = str(howmuch) return self._longcmd('TOP ' + which + ' ' + howmuch) def uidl(self, which = None): if which: which = str(which) return self._longcmd('UIDL ' + which) else: return self._longcmd('UIDL') def quit(self): resp = self._shortcmd('QUIT') self.file.close() self.sock.close() del self.file, self.sock return resp if __name__ == "__main__": a = POP3(TESTSERVER) print a.getwelcome() a.user(TESTACCOUNT) a.pass_(TESTPASSWORD) a.list() (numMsgs, totalSize) = a.stat() for i in range(1, numMsgs + 1): (header, msg, octets) = a.retr(i) print "Message ", `i`, ':' for line in msg: print ' ' + line print '-----------------------' a.quit()