Two ways to Saving E-mail Attachments (AppleScript & Ruby+EWS)

I had this fun project of storing & processing some financial analysis reports. The goal was to receive periodic (bi-weekly) reports that were sent by an automated reporting software. The catch was that these reports were only deliverable via e-mail and the e-mail address they were being delivered to was a Microsoft Exchange account with no POP/SMTP access. Since I had recently been mucking with my Mac rules I figured I’d write a little AppleScipt… Check it out:

(My dev machines already talk to each other over authorized SSH keys so this became a snap)

on perform_mail_action(ruleData)
	tell application "Mail"
		set theMessages to |SelectedMessages| of ruleData
		repeat with themessage in theMessages
			set theAttachments to mail attachments of themessage
				repeat with anAttachment in theAttachments
					repeat 1 times
						if name of anAttachment does not end with ".htm" then exit repeat
						set {seconds:s} to (current date)
						set thePath to "/tmp/reports/" & s & (random number from 10000 to 900000) & name of anAttachment
						save anAttachment in thePath
						set cmd to "scp " & thePath & " ov2:/opt/svn/optisol/src/ruby/transit/reports"
						do shell script cmd
					end repeat
				end repeat
			end try
		end repeat
	end tell
end perform_mail_action

So my fun with AppleScript was short-lived. To have a more reliable solution I switched over to the the pretty decent SOAP API for Microsoft Exchange called Microsoft Exchange Web Services Managed API (or just EWS). And luckily a neat Ruby Gem also exists called Viewpoint that makes life a breeze. In just a few lines of code, here is my script that pulls down a search for the last 7 days of e-mails that have attachments and are sent to a special mailing address:

require 'viewpoint'
require 'kconv' # If on Ruby 1.9
Viewpoint::EWS::EWS.endpoint = EWS_URL #... ''
inbox = Viewpoint::EWS::Folder.get_folder_by_name('inbox')
restrict = { 
  :restriction => { 
    :and => [
      :is_greater_than => [ {:field_uRI => {:field_uRI=>'item:DateTimeSent'}}, {:field_uRI_or_constant => {:constant => {:value=>}}} ],
      :is_equal_to => [ {:field_uRI => {:field_uRI=>'item:HasAttachments'}}, {:field_uRI_or_constant => {:constant => {:value=>true}}} ],
      :contains => [ {:field_uRI => {:field_uRI=>'message:ToRecipients'}}, {:constant => {:value=>''}} ]
search_results = inbox.find_items(restrict)
puts "#{search_results.size} items to inspect/process"
search_results.each do |email|  
  # Attachments are Base64 encoded -- let's unpack and grab the result
  attachment_content = email.attachments.first.unpack('m').first
  puts attachment_content
  # Viewpoint also gives you a handle save method
  # email.attachments.first.save_file

Here are some helpful pages worth referencing

Leave a Reply

Your email address will not be published. Required fields are marked *