Import Mail.app “Notes” Into Evernote

  • Updated 12/16/2012 to add a contributed AppleScript to import notes from Mountain Lion’s Notes.app to Evernote

  • Updated 5/25/2010 to add the creation date of the Mail.app note to the imported Evernote item.

Mail.app has these things it can store called “notes.” Along with mail-based todos, they’re meant to turn Mail.app into more of a productivity hub. I don’t have a strong opinion about them, mostly because they’re an absolute nightmare if you make the mistake of letting them come near a Gmail account, which I did. The experience was unpleasant enough that I never decided whether I liked them away from a Gmail account or not.

Another weird thing about Notes from a scripting perspective is that when they aren’t tied to an e-mail account, they don’t seem to exist in any way you can get at them if you store them in their little “Notes” hierarchy. Mail.app’s scripting dictionary doesn’t acknowledge the existence of a specific class of things called notes, and scripts don’t find anything inside the folders holding them. AppleScripts trying to talk to the mailbox “Notes” compile but don’t do anything. appscript scripts claim that they’ve got a reference to the mailbox, but return an empty array when you ask for the items within.

Someone on the Evernote forums, however, had a good enough experience with them that he had 400 he wanted to move from Mail.app into Evernote (so I guess the experience wasn’t that great in the end). Like I said, I don’t even care about notes, but I did think “I’ve already done that with messages in Evernote, so I’m sure I can easily repurpose that.” That’s when I discovered the existenceless existence of Notes.

It turns out, though, that you can just make a new mailbox on your Mac and drag all your notes into it, at which point they become messages for purposes of scripting them. The first line of the note is the “message” “subject,” and every line of the note including the first is the “message” “content.”

Once I had that worked out, it was easy to mass import a sample of test notes into Evernote:

I ended up deciding to do it in Applescript when I realized Ruby probably would not be helpful to the original poster. If you count the shebang and require lines, it took 18 more characters in Ruby than in AppleScript.

Here’s another one, contributed in the comments by Lee, for using the new Notes.app found in Mountain Lion:

Inbox Glue

MailTags is handy because it lets you assign due-dates (“tickle dates”) to incoming messages. One problem I’ve got with anything like that, though, is that I’ve already got an inbox for e-stuff in the form of Evernote. It’s possible to forward messages to Evernote for clipping, but I like having a list of actionable messages for a given day in one place, hence the script below.

It goes through my ‘tickler’ mail folder and pulls anything with a tickle date of the current day or earlier, finds Evernote notes tagged with today’s date (I haven’t gotten around to parsing the tags so I can grab earlier notes), and compiles them into a single Evernote note item. I write other to-dos on a printed copy, which gives me a one-stop place to find everything.

One beef: Evernote’s HTML interpreter is sub-par. It doesn’t understand Apple’s message:// URIs, so it’s not possible to dump an Evernote item with hyperlinks to messages as they appear in Mail.app. I’m guessing the way around that might involve importing an HTML file (instead of building a note object and storing HTML in it), but I haven’t bothered testing yet. I just dump plain text into the note for now.

One semi-neat thing is its use of the Mac ‘Summarize’ feature in Applescript. It lets you take something like this article from the AP and render it into a summary:

“President Barack Obama approved adding some 17,000 U.S. troops for the flagging war in Afghanistan, his first significant move to change the course of a conflict that his closest military advisers have warned the United States is not winning.”

The AppleScript syntax for that is just:

summarize "some text" in 1

where “1″ is the number of paragraphs you want back.

In Ruby/appscript, it’s:

osax.summarize("some text")

So when the script goes through the day’s e-mail messages, it passes the message text through the summarizer, which has a better chance of getting me a useful nut than a simple string.slice[0,200] approach (though sometimes it misses in a way that at least provokes some stimulating head-scratching).

One other curiosity in this script. Sometimes native Applescript has to use the ‘using terms from’ convention. MailTags is one such case. It tells Applescript that you’re ‘tell’-ing Mail something, but you need the supplemental dictionary provided by the MailTags add-on. rb-appscript doesn’t allow for that, quite, so you’ve got to do a little dancing around.


#!/usr/bin/env ruby

require 'rubygems'

require 'appscript'

require 'Date'

include Appscript

require 'osax'

include OSAX

require '/Users/mph/lib/ruby/mailtags.rb'

require 'erb'



today = Date.today.strftime("%Y-%m-%d")





title = "Tickler File for #{Date.today.strftime("%A, %B %d")}"

mail = app("Mail", MailTags)

en = app("EverNote")

nb = en.notebooks["tickler"]

ical = app("ical")



note = ""

messages = mail.accounts["Gmail"].mailboxes["tickler"].messages.get

notes = nb.notes.get



todays_notes = []

todays_messages = []



notes.each do |n|

  n.tags.get.each do |t|

    if t.to_s =~ /##{today}/

      todays_notes << n

    end

  end

end



messages.each do |m|

  due_date = m.due_date.get.strftime("%Y-%m-%d")

  if due_date >= today

    todays_messages << m

  end

end



template = <<END



Tickler File for <%= Date.today.strftime("%A, %B %d") %>





Today's Messages

=================================================

<% todays_messages.each do |m| %>

  [  ] <%= m.subject.get %> (due <%= m.due_date.get.strftime("%m/%d") %>)

  from <%= m.sender.get %> on <%= m.date_sent.get.strftime("%A, %B %d") %>



  "<%= osax.summarize(m.content.get).strip %>"







--------------------------------------------------------------------------------------------------

<% end %>





Today's Notes

=================================================



<% todays_notes.each do |n| %>

[  ] <%= n.title.get %>

<%end %>



END



tickle_text = ERB.new(template).result

tickle_note = en.create_note(:title => title, :notebook => "Inbox", :with_text => tickle_text)



Quixotic, Appscript, Mail

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.

 

#!/usr/bin/ruby



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)

      yoj.import(tmpfile)

      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)}

    else

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

    end

    

    File.delete(tmpfile)

  

    end

end

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