Extract attachements from Outlook mails contained in winmail.dat

The idea for this script was born, when I found this post at Apple Support Forum:
Problems with winmail.dat attachments (https://discussions.apple.com/thread/3035481)

Since some month, I got more and more mails born in Outlook, that contained this ugly attachment named winmail.dat, that does not easily show it’s contents.

I tested tnef’s enough, but it did not always work and I love little helpers, that can be hidden behind one click or a keyboard shortcut. So I started to learn, what’s behind this “Microhard” and finally found Mark Simmon’s tool tnef.

Resources:

The script’s workflow:

  • check wether a mail is selected in Mail.app
  • check wether it has an attachment
  • check wether it is winmail.dat
  • let user choose a folder for the unpacked attachments
  • check wether tnef tool is available
  • save the winmail.dat to the given folder
  • check for attachment files in winmail.dat
  • show the filenames in a list
  • unpack the contained files to the folder

If one of the checks fail, the script stops with a message.

Places the script checks for the tnef tool:

  • the script’s bundle/Contents/Resources (in case it is an .app as provided at the link below)
  • the given folder
  • the Applications folder

The script works best, if at scriptstart already a mail containing a winmail.dat attachment is selected.

It is developed and tested on Mac OS X 10.6.7 with latest app software.


# Mail should be open and a mail selected
tell application "Mail"
	# get the selected mail
	activate
	try
		set m to (get first item of (get selected messages of first message viewer))
	on error
		display alert "Please select a Mail with winmail.dat Attachement"
		return
	end try
	
	# check attachement for existence of winmail.dat
	try
		set a to (get first item of (get mail attachments of m))
	on error
		display alert "Selected Mail has no Attachement"
		return
	end try
	if not (name of a as text) = "winmail.dat" then
		display alert "Selected Mail has no winmail.dat attachement"
		return
	end if
	
	set theOutputFolder to (choose folder) as text
	# in this folder the file operations take place:
	# temporary save winmail.dat and unpack contained files
	
	# look for the tnef command:
	# 1. in script bundle Contents/Resources
	# 2. in working folder
	# 3. in /Applications folder
	set tnefPath to ((path to me) as text) & "Contents:Resources:tnef"
	tell application "System Events"
		try
			set tnefInfo to properties of alias tnefPath
		on error
			set tnefInfo to ""
		end try
	end tell
	
	if tnefInfo = "" then
		set tnefPath to theOutputFolder & "tnef"
		tell application "System Events"
			try
				set tnefInfo to properties of alias tnefPath
			end try
		end tell
	end if
	
	if tnefInfo = "" then
		set tnefPath to ((path to applications folder) as text) & "tnef"
		tell application "System Events"
			try
				set tnefInfo to properties of alias tnefPath
			end try
		end tell
		if tnefInfo = "" then
			display alert "Could not find tnef" & linefeed & ¬
				"in the Script Bundle" & linefeed & "nor in " & theOutputFolder ¬
				& linefeed & "nor in Applications folder"
			return
		end if
	end if
	
	# save an existing winmail.dat to the given folder 
	set theSavePath to POSIX path of (theOutputFolder & (id of m as text) & (name of a))
	set theSavePathMsg to POSIX path of (theOutputFolder & (id of m as text) & "message")
	do shell script "rm -f " & theSavePath
	try
		save a in theSavePath
	on error
		display alert "Could not save winmail.dat" & linefeed & "at " & theSavePath ¬
			& linefeed & "Check: folder exists?"
		return
	end try
	
	# prepare the tnef commands
	# tnef is supposed to be in the given folder
	# if not, change the commands
	set cmd to "cd " & (POSIX path of theOutputFolder) & linefeed
	set cmd1 to (POSIX path of tnefPath) & " -t -f " & theSavePath
	set cmd2 to (POSIX path of tnefPath) & " -f " & theSavePath
	
	# check for contained files
	set ret to do shell script cmd & cmd1
	if ret = "" then
		display alert "There are no files in winmail.dat!"
		return
	end if
	
	# just for fun: make a list of contained files
	set my text item delimiters to "\r"
	set theLines to text items of ret
	set my text item delimiters to {""}
	set my text item delimiters to "\t|\t"
	set theFiles to {}
	repeat with f in theLines
		set end of theFiles to item 1 of (text items of f)
	end repeat
	set my text item delimiters to {""}
	set ret to ¬
		(choose from list theFiles with title "Files in Attachment" OK button name ¬
			"Unpack" cancel button name "Cancel" with empty selection allowed)
	if ret = false then # was it canceled?
		do shell script "rm " & theSavePath
		return
	end if
	# ret contains the selected files
	# TODO: only unpack the selected files:
	# unpack all and delete unwanted
	
	# unpack the contained files
	set ret to do shell script cmd & cmd2
	do shell script "rm " & theSavePath
	display alert "Files unpacked to folder" & linefeed & theOutputFolder
end tell

The script can be downloaded as zipped application bundle (https://files.me.com/rhocke/owcno8) containing the tnef tool ready to use. If you want to edit the script, just open winmail.app in the Applescript Editor.

I have this as app in the applications folder and a shortcut defined in the launcher Butler.

Feedback and ideas, how to improve the script (e.g. make it a droplet), are welcome.

By chance have you updated this for Lion? I get an error trying to run it in lion saying the folder doesn’t exist.

Did not use it for a longer time.

I am on Lion too now and tested it:

I confirm, that it is not running on Lion currently.

The reason: The Mail object “mail attachment” returns the generic error “AppleEvent Routine -10000” when being asked to save. This means, that there is some buggy situation now with Lion’s Mail in the scripting area.

Since I am participating in the Apple Seed program I will test it with the preversion of 10.7.2 and report a bug there, if it still crashes.

I will come back, if there is a solution.

It will work again with 10.7.2

So we have to wait :wink:

Thanks