File: class/Workbook/Examples/Lecture14/pymail.py
#!/usr/local/bin/python
######################################################
# use the Python POP3 mail interface module to view
# your pop email account messages; runs on top of
# sockets (the mail server may be a remote machine),
# and uses the rfc822 module to extract mail header
# information; this is a very simple command-line
# browsing interface, but is a start at a scriptable
# replacement for things like MS-Outlook (I wrote
# this right after my ISP took away telnet access);
# also see the library manual for modules multifile
# and mimetools to handle multi-part messages and
# decoding, and the imaplib module for IMAP4 servers;
# uses StringIO to make msg text a file-like object;
# retrieving messages does not delete them--keeps a
# list of messages to delete and reconnects on exit;
# it would be easy to throw the index in a Tkinter
# ilstbox and display messages in a scrolled text
# box, as a GUI mail interface--see PyMailGui.py.
######################################################
import poplib, rfc822, string, StringIO
def connect(servername, user, passwd):
print 'Connecting...'
server = poplib.POP3(servername)
server.user(user) # connect, login to mail server
server.pass_(passwd) # pass is a reserved word
print server.getwelcome() # print returned greeting message
return server
def loadmessages(servername, user, passwd, loadfrom=1):
server = connect(servername, user, passwd)
try:
print server.list()
(msgCount, msgBytes) = server.stat()
print 'There are', msgCount, 'mail messages in', msgBytes, 'bytes'
print 'Retrieving:',
msgList = []
for i in range(loadfrom, msgCount+1): # empty if low >= high
print i, # fetch mail now
(hdr, message, octets) = server.retr(i) # save text on list
msgList.append(string.join(message, '\n')) # leave mail on server
print
finally:
server.quit() # unlock the mail box
assert len(msgList) == (msgCount - loadfrom) + 1 # msg nums start at 1
return msgList
def deletemessages(servername, user, passwd, toDelete, verify=1):
print 'To be deleted:', toDelete
if verify and raw_input('Delete?')[:1] not in ['y', 'Y']:
print 'Delete cancelled.'
else:
server = connect(servername, user, passwd)
try:
print 'Deleting messages from server.'
for msgnum in toDelete: # reconnect to delete mail
server.dele(msgnum) # mbox locked until quit()
finally:
server.quit()
def showindex(msgList):
count = 0
for msg in msgList: # strip,show some mail headers
strfile = StringIO.StringIO(msg) # make string look like a file
msghdrs = rfc822.Message(strfile) # parse mail headers into a dict
count = count + 1
print '%d:\t%d bytes' % (count, len(msg))
for hdr in ('From', 'Date', 'Subject'):
try:
print '\t%s=>%s' % (hdr, msghdrs[hdr])
except KeyError:
print '\t%s=>(unknown)' % hdr
#print '\n\t%s=>%s' % (hdr, msghdrs.get(hdr, '(unknown)')
if count % 5 == 0:
raw_input('[Press Enter key]') # pause after each 5
def showmessage(i, msgList):
if 1 <= i <= len(msgList):
print '-'*80
print msgList[i-1] # this prints entire mail--hdrs+text
print '-'*80 # to get text only, call file.read()
else: # after rfc822.Message reads hdr lines
print 'Bad message number'
def savemessage(i, mailfile, msgList):
if 1 <= i <= len(msgList):
open(mailfile, 'a').write('\n' + msgList[i-1] + '-'*80 + '\n')
else:
print 'Bad message number'
def msgnum(command):
try:
return string.atoi(string.split(command)[1])
except:
return -1 # assume this is bad
helptext = """
Available commands:
i - index display
l n? - list all messages (or just message n)
d n? - mark all messages for deletion (or just message n)
s n? - save all messages to a file (or just message n)
m - compose and send a new mail message
q - quit pymail
? - display this help text
"""
def interact(msgList, mailfile):
showindex(msgList)
toDelete = []
while 1:
try:
command = raw_input('[Pymail] Action? (i, l, d, s, m, q, ?) ')
except EOFError:
command = 'q'
# quit
if not command or command == 'q':
break
# index
elif command[0] == 'i':
showindex(msgList)
# list
elif command[0] == 'l':
if len(command) == 1:
for i in range(1, len(msgList)+1):
showmessage(i, msgList)
else:
showmessage(msgnum(command), msgList)
# save
elif command[0] == 's':
if len(command) == 1:
for i in range(1, len(msgList)+1):
savemessage(i, mailfile, msgList)
else:
savemessage(msgnum(command), mailfile, msgList)
# delete
elif command[0] == 'd':
if len(command) == 1:
toDelete = range(1, len(msgList)+1) # delete all later
else:
delnum = msgnum(command)
if (1 <= delnum <= len(msgList)) and (delnum not in toDelete):
toDelete.append(delnum)
else:
print 'Bad message number'
# mail
elif command[0] == 'm': # send a new mail via smtp
try: # reuse existing script
execfile('smtpmail.py', {}) # run file in own namespace
except:
print 'Error - mail not sent' # don't die if script dies
elif command[0] == '?':
print helptext
else:
print 'What? -- type "?" for commands help'
return toDelete
if __name__ == '__main__':
import sys, getpass, mailconfig
mailserver = mailconfig.popservername # ex: 'starship.python.net'
mailuser = mailconfig.popusername # ex: 'lutz'
mailfile = mailconfig.savemailfile # ex: r'c:\stuff\savemail'
mailpswd = getpass.getpass('Password for %s?' % mailserver)
if sys.platform[:3] == 'win': raw_input()
print '[Pymail email client]'
msgList = loadmessages(mailserver, mailuser, mailpswd) # load all
toDelete = interact(msgList, mailfile)
if toDelete: deletemessages(mailserver, mailuser, mailpswd, toDelete)
print 'Bye.'