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 Mail.app 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
 
			try
				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 #... 'https://yahoo.com/EWS/Exchange.asmx'
Viewpoint::EWS::EWS.set_auth EWS_USERNAME,EWS_PASSWORD
 
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=>DateTime.now-7}}} ],
      :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=>'your@email.com'}} ]
    ]
  } 
}
 
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
end

Here are some helpful pages worth referencing

You can play music on a locked Mac OS X

At some point today my Macbook Pro, running Mac OS X 10.6.8, locked my screen due to inactivity yet I was still able to control the audio via helper keys on the top row of the keyboard. That’s pretty cool. It made me think of my Android phone, and how that too offers audio controls when locked. It made me think of how designing a product requires attention to the most subtle of details.

When beginning a new project, I often start off in total ignorance at the amount of work that will ensue. I think to myself, “sashimi slices, it’ll all work out” and then I plug away at writing some code, designing some views, and seeing it all come together. At some point I find myself customizing the little pieces of the Application: the footer. Woah, seriously the footer is valuable real estate but I rarely look at it that way. Yet, in it’s tiny form it can hold some of the most important links and people naturally go there. We actually expect a footer on the pages we frequent; we expect it has worthwhile resources that we may need. And what goes into this footer is exactly what I’m talking about: subtle features.

I’ve tried to come up with a name for these features and I think I’ll stick to unoriginality and call them Core Application Functionality – CAFs.

Apple loves their CAFs and it shows. My Macbook Pro understands me. It knows that just because I’m not logged into my computer I still may need to adjust the volume. It knows that physical components of my machine, like sound, need physical controls.

Mac OS X reminds me of how CAFs can make or break an (web) application. For example, looking at user authentication we have a baseline rubric for what we need to use a service. We expect a web application to let us register, login, and logout. That’s the basics. Of course we are missing one very important feature: password reset. Unfortunately, not all web apps are created equally and some fail to provide a password reset mechanism. A missing CAF like this highlights the little attention to detail in core functionality of the Application. That’s pretty bad and what’s worse is how the user is left feeling helpless. A negative experience such as this will have the Application failing — what a silly way to break the bank!

CAF gaps happens. Trust me. As an avid user of new web applications I find myself stuck more often than I’d like. These gaps creep up on start-ups as well as medium-to-large sized companies. They just happen. And they suck. So my advice is to take a moment and ask yourself this, “does my application get me?”