The requirement: Given an Outlook message, detach any attachments to the filesystem and replace them in the message by a shortcut.
Although ostensibly two different things, Outlook and Exchange are pretty tightly coupled in reality. This code uses the CDO technique, an IDispatch-based mechanism under the application name MAPI.Session. For any work with CDO I highly recommend the CDOLive website.
The approach is to iterate over the messages in a folder, interrogating each one as to its attachments. If any of the attachments is a file (ie is not itself a link), save the file to the file system using a simple incrementing counter approach and add a new attachment of the same name which is a link to the newly-created file on the file system. Finally, delete the now unneeded original attachment. Please note the warning below: the code as presented has few safeguards and should be considered illustrative only.
The code below is pared to the bone for readability. Naturally you'll need checks galore. The only safeguards I've retained are that the code doesn't in fact delete the existing attachments: the line's commented out; and that it only tries to detach file attachments, ie you can run it again on the same folder and it won't try to create links to links!
import os, sys
import win32com.client
win32com.client.gencache.EnsureDispatch ("MAPI.Session")
ATTACHMENTS_FOLDER = "c:/temp"
COUNTER = 1
def process_attachment (attachment):
global COUNTER
basename = attachment.Name.encode ("utf-8", "ignore").lower ()
root, ext = os.path.splitext (basename)
while True:
try:
filepath = os.path.join (ATTACHMENTS_FOLDER, "%d%s" % (COUNTER, ext))
print "Trying", filepath
open (filepath, "r")
except IOError:
break
else:
COUNTER += 1
try:
attachment.WriteToFile (filepath)
except:
return 0
else:
attachments = attachment.Parent
new_attachment = attachments.Add ()
new_attachment.Position = 0
new_attachment.Type = win32com.client.constants.CdoFileLink
new_attachment.Source = filepath
new_attachment.Name = attachment.Name
## attachment.Delete ()
return 1
def process_message (message):
print "Message:", message.Subject
attachments = message.Attachments
for n_attachment in range (1, attachments.Count + 1):
attachment = attachments.Item (n_attachment)
if attachment.Type == win32com.client.constants.CdoFileData:
if process_attachment (attachment):
message.Update ()
if __name__ == '__main__':
session = win32com.client.gencache.EnsureDispatch ("MAPI.Session")
session.Logon ()
messages = session.Inbox.Messages
message = messages.GetFirst ()
while message:
process_message (message)
message = messages.GetNext ()