Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, Swift, BASIC, and whatever else I happen to feel like hacking at.

Apple Mail on the Desktop with GeekTool

Jerry Stratton, December 13, 2010

With all of my TaskPaper and Django reminders on the Desktop, I realized I’d better get my Inbox on the Desktop too, or it would start filling up—out of sight, out of mind. I long ago started keeping my inbox empty; letting it accumulate again would not be good.

I found a rudimentary AppleScript on MacWorld hints that shows unread mail. It was also a programmer’s first AppleScript, so it did all sorts of programmer things I don’t personally like in an AppleScript.

I’ve reworked it to look more like what I think AppleScript should look like; just to make it easier for me to update. And I also flipped the read status. I don’t want to see unread messages, I want to see messages that I know I want to deal with. So I only show read messages, and I don’t leave it in my inbox if I don’t want to see it on my Desktop.

[toggle code]

  • set messageList to {}
  • tell application "Mail"
    • repeat with pendingMessage in (messages of inbox whose read status is true)
      • tell pendingMessage
        • --get sender's name
        • set senderName to extract name from sender
        • --if there is no name, or the address line is malformed, better to show just the address
        • if senderName is equal to sender then
          • set senderName to extract address from sender
        • end if
        • --mark flagged messages specially
        • if pendingMessage is flagged status then
          • set bullet to "» "
        • else
          • set bullet to "• "
        • end if
        • copy bullet & senderName & tab & subject & linefeed to end of messageList
      • end tell
    • end repeat
  • end tell
  • messageList as text

It’s fairly simple: it tells the Apple Mail application to get all “messages of Inbox whose read status is true”, i.e., all messages that have been read and are in the inbox. Then it tells each message to get information about itself.

If the message is flagged, it uses a right-pointing double angle as the bullet, otherwise it uses a standard bullet. I’ll sometimes use the flag to remind myself that, hey, this is the one you want to do next.

It compiles an array of lines with the bullet, the subject, and the sender’s name if it can find it. And finally, it converts that list to text.

It uses a neat trick that Mail can do, which I learned from Rob de Jong at MacWorld hints, which is to “extract name from” an address line; you can also “extract address from”; it works with any text that looks like a To or From line. For example:

[toggle code]

  • tell application "Mail"
    • extract address from "John Hobo <jhobo@hoboes.com>"
    • extract name from "\"John Hobo\" <jhobo@hoboes.com>"
  • end tell

The terminology’s a bit weird; it pretty much requires using “set” instead of “copy” because “copy extract name from sender to senderName” scans horribly. On the other hand, “set variable name to extract name from sender” is only marginally better. I expect it made more sense when they tested in very simple cases and were able to use “the result”.

I saved the script as “text” in my personal bin folder, and named it “Inbox”; this gives it a file extension of “applescript”. By saving it as text, changes to it can be tracked by Mercurial.

The command to use it in GeekTool is:

  • /usr/bin/osascript ~/bin/Inbox.applescript

You can run that line on the command line, too.

AppleScript Editor does not support UTF-8, only, as far as I can tell, Mac OS Roman; however, the osascript command does. UTF-8 is better for tracking in Mercurial and provides more bullet options; AppleScript Editor is better for AppleScript. It’s a tossup, but currently I’m using Mac OS Roman because editing AppleScript outside of AppleScript Editor is painful, and I don’t use AppleScript enough to justify buying a third-party editor dedicated to AppleScript.

A couple of other things I ran into:

  • It would be nice if GeekTool could set tab stops. That would make the results more readable.
  • There does not appear to be any way of getting all flagged messages, even through a smart mailbox. There does not, in fact, appear to be any way to select smart mailboxes. This means that my old trick of flagging messages and using a smart mailbox to collect important messages all in one place isn’t as useful. If I want to act on something, I need to move it into my inbox.
  • I also don’t see a way of specifying the order of the messages (without changing their order in the mailbox, and I don’t want the script to interfere with my inbox). Something like “messages of inbox sorted by descending date received” would be nice.

Another nice thing about this, is that I don’t need a separate geeklet for iCal, since iCal emails me anything important and the email lands on the Desktop as soon as I decide not to delete it (or doesn’t land on the Desktop if I do choose to delete it). If you do want to work more closely with iCal, you may find icalBuddy useful.

March 28, 2011: AppleScript, Mail, and deleted messages

One thing I’ve noticed happen occasionally—but not often—with this script is that I sometimes see ghost messages: messages I’ve deleted from my inbox, and no longer appear in my inbox, but do get picked up by AppleScript.

I’m not sure exactly what’s going on here, because the messages do eventually disappear. They just don’t disappear immediately. What appears to be happening is that OS X Mail keeps trashed messages, in its internal SQLite database, in the folder they were trashed from.1 And my guess is that when AppleScript asks for all messages from the inbox, Mail just returns a query on that database.

This is easy to check for in the AppleScript, however. Each message has a “deleted status” on it. If it’s true, the message has been deleted.

So replace the “repeat with pendingMessage…” line with:

  • repeat with pendingMessage in (messages of inbox whose read status is true and deleted status is false)

It seems more than a little weird to be asking Mail specifically to ignore messages that don’t appear to be there in the first place. As far as I can tell, however, they are there, but the OS X Mail GUI is hiding them from you.

  1. <- Autolink URLs
  2. Django SuspiciousOperation ->