Quixotic, Appscript, Mail

January 17th, 2009  |  Published in ruby

I don’t know why I get into these things.

Below is a script that takes the selected messages in Mail.app and saves them to Yojimbo, which I like a lot for keeping schtuff.

Some things that might have told me to quit and use someone else’s AppleScript instead of rolling my own:

First, I couldn’t figure out how to make rb-appscript work with references between apps. So the part that grabs the attachment from Mail has no way to say to the part that imports the attachment to Yojimbo, “Hey … this object here is a file. Deal with it.” Instead, the file has to be stowed somewhere then picked up for use by Yojimbo.

Second, Yojimbo can’t import everything … like zip files, for instance. So instead of just doing something to catch exceptions I decided to go and read the MIME types of attachments then check them against an array of legal file types.

On the other hand, I can tag the attachments as they’re imported, and this is much faster than dragging the attachments into Yojimbo, because I can tie it to a Mail Act-On keystroke (and because Mail.app gets really slow with attachment handling sometimes, even if you don’t mind mousing).

And there’s one other good reason to do stuff like this: I’d rather get the practice with Ruby than crib AppleScript from someone else. I’ll take foo.split(',') over set AppleScript's text item delimiters to "," any day of the week.



require 'rubygems'

require 'appscript'

require 'mime/types'

require 'osax'

include OSAX

include Appscript

mail = app("Mail")

yoj = app("Yojimbo")

tmpdir = "/Users/mph/tmp"

legal_files = ["image/gif", "image/jpeg", "application/pdf", "image/png", "application/word","text/plain", "application/msword", "text/html"]

messages = mail.selection.get

messages.each do |m|

  m.mail_attachments.get.each do |a|

    tmpfile = "#{tmpdir}/#{a.name.get}"


    a.save(:in => tmpfile)

    type = MIME::Types.type_for(tmpfile)[0]


    if legal_files.include?(type)


      item = yoj.database_items.last

      taglist = osax.display_dialog("Enter tags for #{a.name.get}", :default_answer => "", :buttons => ['Cancel', 'Okay'],  :default_button => 2, :with_icon => :note).fetch(:text_returned).split(",")


      taglist.each {|t| item.add_tags(t)}


      osax.display_dialog("Yojimbo can't import #{a.name.get} - (filetype: #{type})", :with_icon => :stop)







Leave a Response

© Michael Hall, licensed under a Creative Commons Attribution-ShareAlike 3.0 United States license.