Skip to content

Instantly share code, notes, and snippets.

@DaffyDuke
Created March 5, 2017 11:11
Show Gist options
  • Save DaffyDuke/dd5afc6271ae67bbbfce6783c2b009ac to your computer and use it in GitHub Desktop.
Save DaffyDuke/dd5afc6271ae67bbbfce6783c2b009ac to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
 
# Licensed under the Python License (see http://www.python.org/psf/license/)
# Copyright (C) 2008 Pierre Duquesne <stackp@online.fr>
#
# Changelog:
# 20080722 * disable spinning when output is redirected to a file
# 20080718 * Use BODY.PEEK[] in the fetch command as specified in RFC 3501
# (fix by Stefan)
# 20080313 * Initial release
 
import getpass
import imaplib
import email
import email.Parser
import re
import sys
import getopt
from os.path import basename
 
USAGE = """\
usage: %s [--ssl] [--port num] [--password pass] [server] [user]
 
server
The hostname of your imap server
 
user
Your login
 
--ssl
Use an encrypted connection
 
-p num
--port num
Use port number num instead of default port
(Defaults are 143 for unencrypted connection and 993 for ssl)
 
-P pass
--password pass
Password for the server
 
""" % basename(sys.argv[0])
 
class Spinner:
"""A class to show some activity on a character terminal."""
 
def __init__(self, message=''):
self.message = message
self.symbols = list('-\|/')
self.nsym = len(self.symbols)
self.n = 0
 
def spin(self):
print '\r', self.message + self.symbols[self.n],
sys.stdout.flush()
self.n = (self.n + 1) % self.nsym
 
def stop(self, stop_message=''):
print '\r', self.message + stop_message
 
def set_message(self, message):
self.message = message
 
class DummySpinner:
"""A class that mock Spinner and do not spin.
 
Used when output is not a character terminal (e.g. a log file).
 
"""
def __init__(self, message=''):
self.message = message
 
def spin(self):
pass
 
def stop(self, stop_message=''):
print self.message + stop_message
 
def set_message(self, message):
self.message = message
 
 
def foldname_to_filename(folder):
"""Deal with weird characters in folder names."""
filename = re.sub('"(.*)"', ur'\1', folder)
filename = filename.replace('/', '.')
return filename
 
try:
# Parse command line arguments
try:
opts, args = getopt.gnu_getopt(sys.argv[1:], 'pP:h',
['port=', 'password=', 'ssl', 'help'])
except getopt.GetoptError, e:
print 'Error:', e
sys.exit(1)
 
ssl = False
port = None
password = None
for o, a in opts:
if o == '--ssl':
ssl = True
if o == '-p' or o == '--port':
port = int(a)
if o == '-P' or o == '--password':
password = a
elif o in ['-h', '--help']:
print USAGE
sys.exit(0)
 
try:
servername = args[0]
except IndexError:
servername = raw_input("Enter the server hostname: ")
try:
username = args[1]
except IndexError:
username = raw_input("Enter your username: ")
 
# Connect
print 'Connecting to %s as user %s ...' % (servername, username)
if ssl:
IMAP = imaplib.IMAP4_SSL
else:
IMAP = imaplib.IMAP4
try:
if port:
server = IMAP(servername, port)
else:
server = IMAP(servername)
if not password:
password = getpass.getpass()
server.login(username, password)
except Exception, e:
print 'Error:', e
sys.exit(1)
 
# Retrieve folder list
folders = []
foldptn = re.compile('\([^\)]*\) "[^"]*" ([^"]*)')
for fold_desc in server.list()[1]:
folder = foldptn.sub(ur'\1', fold_desc)
folders.append(folder)
 
# Save messages in a separate file for each folder
if sys.stdout.isatty():
spinner = Spinner()
else:
spinner = DummySpinner()
parser = email.Parser.Parser()
succeed = []
failed = []
for folder in folders:
msg = '%s ... ' % folder
spinner.set_message(msg)
try:
resp, info = server.select(folder)
if resp != 'OK':
raise imaplib.IMAP4.error(' - '.join(info))
filename = foldname_to_filename(folder)
fp = open(filename, 'w')
resp, items = server.search(None, "ALL")
numbers = items[0].split()
for num in numbers:
resp, data = server.fetch(num, "(BODY.PEEK[])")
text = data[0][1]
mess = parser.parsestr(text)
fp.write(mess.as_string(unixfrom=True))
spinner.spin()
succeed.append(folder)
spinner.stop('Done.')
fp.close()
except imaplib.IMAP4.error, e:
failed.append(folder)
spinner.stop('Error! (' + str(e) + ')')
server.logout()
 
# Print the folders which failed, if any
if failed != []:
import textwrap
wrapper = textwrap.TextWrapper(initial_indent=' ',
subsequent_indent=' ')
print
print 'WARNING - The following folders could not be saved:'
print wrapper.fill(', '.join(failed))
sys.exit(1)
 
except KeyboardInterrupt:
print ''
print '^C received, stopping.'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment