Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added option to move mails from one mailbox to another #7

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions imapcopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,24 @@

:copyright: (c) 2013 by Christoph Heer.
:license: BSD, see LICENSE for more details.

example usage:
python imapcopy.py -m -c -l 10 incoming.mail.net:143 [email protected]:password incoming.mail.net:143 [email protected]:password INBOX INBOX

"""

import sys
import hashlib
import imaplib
import logging
import argparse
import re


class IMAP_Copy(object):

pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)')

source = {
'host': 'localhost',
'port': 993
Expand All @@ -31,7 +38,7 @@ class IMAP_Copy(object):
mailbox_mapping = []

def __init__(self, source_server, destination_server, mailbox_mapping,
source_auth=(), destination_auth=(), create_mailboxes=False, skip=0, limit=0):
source_auth=(), destination_auth=(), create_mailboxes=False, skip=0, limit=0, move_mails=False):

self.logger = logging.getLogger("IMAP_Copy")

Expand All @@ -42,6 +49,7 @@ def __init__(self, source_server, destination_server, mailbox_mapping,

self.mailbox_mapping = mailbox_mapping
self.create_mailboxes = create_mailboxes
self.move_mails = move_mails

self.skip = skip
self.limit = limit
Expand Down Expand Up @@ -84,9 +92,14 @@ def disconnect(self):
self._disconnect('source')
self._disconnect('destination')

def parse_uid(self, data):
match = self.pattern_uid.match(data)
return match.group('uid')

def copy(self, source_mailbox, destination_mailbox, skip, limit):
# Connect to source and open mailbox
status, data = self._conn_source.select(source_mailbox, True)
self.logger.info("opening source mail with readonly=%s" % str(not self.move_mails))
status, data = self._conn_source.select(source_mailbox, not self.move_mails)
if status != "OK":
self.logger.error("Couldn't open source mailbox %s" %
source_mailbox)
Expand Down Expand Up @@ -127,9 +140,16 @@ def copy(self, source_mailbox, destination_mailbox, skip, limit):
message = data[0][1]
flags = data[1][8:][:-2] # Not perfect.. Waiting for bug reports

self._conn_destination.append(
result = self._conn_destination.append(
destination_mailbox, flags, None, message
)
if self.move_mails:
try:
self.logger.info("Deleting mail")
res, del_data = self._conn_source.store(msg_num, '+FLAGS', '\\Deleted')
self.logger.info("Returned: %s" % str(res))
except Exception as e:
self.logger.info("ERROR: failed to remove: %s\n" % str(e))

copy_count += 1
message_md5 = hashlib.md5(message).hexdigest()
Expand All @@ -142,6 +162,13 @@ def copy(self, source_mailbox, destination_mailbox, skip, limit):
limit, copy_count))
break

if self.move_mails:
self.logger.info("Expunging mails")
try:
self._conn_source.expunge()
except Exception as e:
self.logger.info("Error whilst expunging mails: %s" % str(e))

self.logger.info("Copy complete %s => %s (%d out of %d mails copied)" % (
source_mailbox, destination_mailbox, copy_count, mail_count))

Expand All @@ -150,6 +177,8 @@ def run(self):
self.connect()
for source_mailbox, destination_mailbox in self.mailbox_mapping:
self.copy(source_mailbox, destination_mailbox, self.skip, self.limit)
except Exception as e:
self.logger.info("ERROR: whilst connecting: %s" % str(e))
finally:
self.disconnect()

Expand All @@ -174,6 +203,9 @@ def main():
parser.add_argument('-c', '--create-mailboxes', dest='create_mailboxes',
action="store_true", default=False,
help='Create the mailboxes on destination')
parser.add_argument('-m', '--move_mails', action="store_true",
dest='move_mails', default=False,
help='move mails(delete from src)')
parser.add_argument('-q', '--quiet', action="store_true", default=False,
help='ppsssh... be quiet. (no output)')
parser.add_argument('-v', '--verbose', action="store_true", default=False,
Expand Down Expand Up @@ -214,7 +246,7 @@ def check_negative(value):
imap_copy = IMAP_Copy(source, destination, mailbox_mapping, source_auth,
destination_auth,
create_mailboxes=args.create_mailboxes,
skip=args.skip, limit=args.limit)
skip=args.skip, limit=args.limit, move_mails=args.move_mails)

streamHandler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
Expand Down