How to get your mails back (from a public folder)

Posted on Wed 30 October 2019 in python

You may use this script to get a sub tree of a public folder forest back into eml format, which then can be imported into other email oriented solutions. You also may need to change the auth_type for the Configuration object and the access_type for the Account object. Both may differ in your environment.

# Public folder download (c) by Sven Ludwig
# 
# Public folder download is licensed under a
# Creative Commons Attribution-ShareAlike 4.0 Unported License.
# 
# You should have received a copy of the license along with this
# work.  If not, see <http://creativecommons.org/licenses/by-sa/4.0/>.

import sys
import getpass
import argparse

from exchangelib import Account, Folder, Credentials, Configuration, NTLM, DELEGATE
from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter

# Tell exchangelib to use this adapter class instead of the default
BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter

parser = argparse.ArgumentParser()
parser.add_argument('--server',   help="Server to be contacted",                 default=None)
parser.add_argument('--account',  help="Account to be used (Email address)",     default=None)
parser.add_argument('--path',     help="Path to be dumped",                      default=None)
parser.add_argument('--username', help="Username to be used for authentication", default=None)
args=parser.parse_args()

if sys.stdin.isatty():
    if (sys.version_info > (3, 0)):
        def getInput(description, parser=None, password=False):
            if parser is not None:
                return parser
            if password:
                return getpass.getpass(description)
            return input(description)
    else:
        def getInput(description, parser=None, password=False):
            if parser is not None:
                return parser
            if password:
                return getpass.getpass(description)
            return raw_input(description)

else:
    def getInput(description, password=False):
        return sys.stdin.readline().rstrip()


try:
    print("Enter basic configuration")
    print("====================================================================")
    server   = getInput("Server (exchange.example.com):    ", args.server)
    account  = getInput("Account (name.surname@exam.pl):   ", args.account)
    path     = getInput("Path (a/b/c):                     ", args.path)
    username = getInput("Username:                         ", args.username)
    password = getInput("Password:                         ", password=True)
except KeyboardInterrupt:
    print()
    print("Aborted")
    sys.exit(0)

credentials = Credentials(username, password)
config = Configuration(server=server, credentials=credentials,auth_type=NTLM)
a = Account(account, config=config, autodiscover=False, access_type=DELEGATE)

a.root.refresh()
a.public_folders_root.refresh()

current_folder = a.public_folders_root

for subdir in path.split('/'):
     if subdir.strip() == '': continue
     current_folder = current_folder / subdir

paths=[current_folder]
for path in current_folder.walk():
     path.refresh()
     paths.append(path)
     print(path.absolute)
     print(path.total_count)

for path in paths:
     for item in path.all().iterator():
          with open('{0}-{1}.eml'.format(str(path.absolute).replace('/','_'), item.message_id), 'w') as f:
                f.write(item.mime_content)

Please be aware that the information you put into this form will be stored with this site. If you want to get rid of your post, please contact me. I'll delete it, if you can proove that you are the author.

Please also be not shocked that you get a cookie after writing a comment. This will be last 30 minutes and enables you to delete your comment on your own. You can decide to not accept it.

Please additionally do not try to dry your pet in a microwave oven. This may kill your pet and harm the microwave device. Both outcomes of that story should be avoided.