Making Apple Mail, Gmail, IMAP and AppleScript work together

If you’ve tried AppleScripting Mail (e.g. to archive mail messages) and you use Gmail, you’ve probably run into issues. The reason is that Gmail by default does some things that are non-IMAPpy.

Apple’s been trying to work nice with Gmail as of Lion (something I’m not sure is a good idea, but that’s beside the point).

Here’s how to make Gmail work like a normal IMAP service, which also makes Mail behave like a normal IMAP client (and makes your AppleScripts work as you’d expect).

  • Gmail > Settings > Labels
    • Turn off “Show in IMAP” for:
      • Important
      • Chats
      • All Mail

Quit and restart Mail (or Mailbox > Synchronize > your Gmail accounts).  It’ll churn for a while, and your gmail accounts should disappear from the “Archive”  mailbox on the left sidebar in Mail.

This simple change to your settings makes Gmail act like a normal IMAP server.  The basic premise is that you’re turning off labels that are subsets or duplicates of other mailboxes (well, and Chats, which is just something you don’t want showing up in mail unless you want all your google chats showing up as email messages).  IMAP requires that a mail message be in one, and only one, folder.  Gmail’s “labels” apply zero or more labels to a message (zero means it’s “archived”, and still shows up in “all mail”). This makes IMAP messy.  The fix above cleans up that mess.

If you’re curious about details, and about how to archive mail using AppleScript, read on.

All Mail is the real problem here: it’s every message you ever sent (and, depending on your settings, every message you ever deleted).  If you’re using AppleScript, say to archive messages, then “mailbox of message …” will always be “All Mail”.  If you “move theMessage to theArchiveMailbox” (assuming “theMessage” is a message and “theArchiveMailbox” is a mailbox), Mail will misbehave and add a label for theArchiveMailbox, while still leaving the old label.  So, it’ll appear in your inbox (for example) AND your archive mailbox (in Gmail, you’ll see it has 2 labels).  This isn’t really Apple’s fault (except that they’re pandering to consumer’s use of Gmail): since IMAP by design puts a message in a folder, and only one folder, “mailbox of message” can only return one folder.  If you’re using Gmail though, which “folder” is the message in if you can only return one folder?  “All Mail” is the logical answer.

So, if you stop Gmail from being a bad IMAP citizen by turning off “All Mail”, Mail can (and does) behave like a normal IMAP client again. “mailbox of message” will properly show the mailbox the message is in again.

So then if you want to archive your mail message from AppleScript, you do this:

tell application "Mail"
    set theMessage to selection --- Get the selected messages
    set accountName to name of account of mailbox of theMessage --- To find an archive mailbox.
    --- This gets a mailbox that contains "Archive".  Uses "last" so you could have
    --- "Archive 2014-02" and "Archive 2014-03" and it'd use "Archive 2014-03".
    set theArchiveMailbox to last item of (mailboxes of account accountName whose name contains "Archive")
    set theMessageId to message id of theMessage --- So we can find it again once it's moved.
    move theMessage to theArchiveMailbox --- Moves the message to the archive
end tell

Notice that line where we get the message id? That’s because theMessage is a reference to a message in an IMAP mailbox. Well, you just moved that message to a new mailbox. But, your reference still points to the old mailbox (e.g. ‘message 123 of mailbox “INBOX” of account “[email protected]” ‘). The “message id of theMessage” however is unique across all messages (everywhere in the world). So if you want to find your message in the archive (e.g. to mark it read, prove it’s moved, etc) you can do this:

set movedMessage to item 1 of (messages of theArchiveMailbox whose message id is theMessageId)

If your message is there, movedMessage will contain a reference to it. If it’s not, that’ll generate an error (because you’ll be referencing item 1 of an empty list).

btw, don’t confuse “id of theMessage” (a number that has limited meaning only within Mail) with “message id of theMessage” (which is the unique message ID that the RFCs require all email messages to have).  We use the “message id” here to uniquely identify and find the moved message.