Path: csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail From: Tim Golden Newsgroups: comp.lang.python Subject: Re: Creating PST files using Python Date: Wed, 4 Nov 2015 10:08:41 +0000 Lines: 68 Message-ID: References: <873907D8-7E21-4F08-AF07-A83F766802BA@cajuntechie.org> Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit X-Trace: news.uni-berlin.de O7Uj+o9vGkRn6ib2KaiAuQyTX8Gs0yYfSxTjUDXEYHRg== Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.001 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'subject:Python': 0.05; 'sys': 0.05; 'url:pipermail': 0.05; 'cc:addr:python-list': 0.09; 'skip:o 60': 0.09; 'subject:files': 0.09; 'subject:using': 0.09; 'def': 0.13; 'wed,': 0.15; 'cc:name:python list': 0.16; 'from:addr:timgolden.me.uk': 0.16; 'from:name:tim golden': 0.16; 'maildir': 0.16; 'message-id:@timgolden.me.uk': 0.16; 'multipart': 0.16; 'received:74.55.86': 0.16; 'received:74.55.86.74': 0.16; 'received:io': 0.16; 'received:psf.io': 0.16; 'received:smtp.webfaction.com': 0.16; 'received:webfaction.com': 0.16; 'tjg': 0.16; 'url:gz': 0.16; 'wrote:': 0.16; 'obviously': 0.16; 'archive': 0.18; 'python?': 0.18; '2015': 0.20; 'cc:2**0': 0.20; 'cc:addr:python.org': 0.20; '%s"': 0.22; 'os,': 0.22; 'am,': 0.23; 'import': 0.24; 'header:In-Reply-To:1': 0.24; 'module': 0.25; "i've": 0.25; 'header:User-Agent:1': 0.26; 'chris': 0.26; 'outlook': 0.28; 'raise': 0.29; 'allows': 0.30; "i'm": 0.30; 'code': 0.30; 'folder': 0.30; 'skip:g 30': 0.30; 'option': 0.31; 'anyone': 0.32; 'url:python': 0.33; 'pst': 0.33; 'skip:d 20': 0.34; 'skip:c 30': 0.35; 'done': 0.35; 'nov': 0.35; 'quite': 0.35; 'project': 0.36; 'url:org': 0.36; 'subject:: ': 0.37; 'skip:p 20': 0.38; 'files': 0.38; 'copying': 0.38; 'skip:o 20': 0.38; 'does': 0.39; 'enough': 0.39; 'received:192': 0.39; 'url:mail': 0.40; 'skip:u 10': 0.61; 'show': 0.62; 'charset:windows-1252': 0.62; 'more': 0.63; 'skip:w 30': 0.64; 'mailbox': 0.64; 'from:addr:mail': 0.70; '(ie': 0.84; 'conversation': 0.84; 'wiring': 0.84; 'to:none': 0.91 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Thunderbird/38.0.1 In-Reply-To: X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.20+ Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Xref: csiph.com comp.lang.python:98217 On 03/11/2015 22:12, Chris Angelico wrote: > On Wed, Nov 4, 2015 at 6:09 AM, Anthony Papillion > wrote: >> Does anyone know of a module that allows the wiring of Outlook PST >> files using Python? I'm working on a project that will require me >> to migrate 60gb of maildir mail (multiple accounts) to Outlook. I don't know if this is quite what you were after but, if automating Outlook is an option (ie using its COM object model), the code below is an *extremely* Q&D approach to adding a PST and copying the messages in a mbox one by one. Obviously I've done just enough to show that it's viable, and none of the more complicated work around conversation ids, multipart messages etc. TJG #!python3 import os, sys import gzip import mailbox import urllib.request import win32com.client dispatch = win32com.client.gencache.EnsureDispatch const = win32com.client.constants PST_FILEPATH = os.path.abspath(os.path.join(os.path.expandvars("%APPDATA%"), "scratch.pst")) if os.path.exists(PST_FILEPATH): os.remove(PST_FILEPATH) ARCHIVE_URL = "https://mail.python.org/pipermail/python-list/2015-November.txt.gz" MBOX_FILEPATH = "archive.mbox" def download_archive(url, local_mbox): with gzip.open(urllib.request.urlopen(url)) as archive: with open(local_mbox, "wb") as f: print("Writing %s to %s" % (url, local_mbox)) f.write(archive.read()) def copy_archive_to_pst(mbox_filepath, pst_folder): archive = mailbox.mbox(mbox_filepath) for message in archive: print(message.get("Subject")) pst_message = pst_folder.Items.Add() pst_message.Subject = message.get("Subject") pst_message.Sender = message.get("From") pst_message.Body = message.get_payload() pst_message.Move(pst_folder) pst_message.Save() def find_pst_folder(namespace, pst_filepath): for store in dispatch(mapi.Stores): if store.IsDataFileStore and store.FilePath == PST_FILEPATH: return store.GetRootFolder() download_archive(ARCHIVE_URL, MBOX_FILEPATH) outlook = dispatch("Outlook.Application") mapi = outlook.GetNamespace("MAPI") pst_folder = find_pst_folder(mapi, PST_FILEPATH) if not pst_folder: mapi.AddStoreEx(PST_FILEPATH, const.olStoreDefault) pst_folder = find_pst_folder(mapi, PST_FILEPATH) if not pst_folder: raise RuntimeError("Can't find PST folder at %s" % PST_FILEPATH) copy_archive_to_pst(MBOX_FILEPATH, pst_folder)