Opening the Gmail web interface with keyboard shortcuts

Problem: When I’m not in the browser it takes way too many clicks to get to Gmail, my email client of choice. First activate the browser, then find the Gmail tab (which is often tedious) before finally getting to Gmail. It’s worse if I also want to compose an email. For such a common action this is too complicated.

Solution: I wrote an applescript (triggered with Keyboard Maestro), that directly takes me to the Gmail interface, always in the first tab of the browser. I can also directly go to “compose”, or other often used views in Gmail with a keyboard shortcut.

Here is the applescript:

set theGmailLink to ""
tell application "Google Chrome"
  set allWindows to every window

  repeat with eachWindow in allWindows
    set allTabs to tabs of eachWindow
    set i to 0

    repeat with eachTab in allTabs
      set theURL to get URL of eachTab
      set i to i + 1

      if theURL contains "" then
        #I like to keep my windows this size but it can be commented out
        set the bounds of the eachWindow to {0, 0, 1275, 1800}

        set index of eachWindow to 1
        if theURL is not equal to theGmailLink then
          set URL of eachTab to theGmailLink
        end if

        #focus on the gmail tab
        set (active tab index of eachWindow) to i
        return #exit the script if a gmail tab was open already
      end if
    end repeat
  end repeat

  #this gets executed if no gmail tab was open
  set newTab to make new tab at beginning of tabs of front window
  set URL of newTab to theGmailLink

  #I like to keep my windows this size but it can be commented out
  set the bounds of the front window to {0, 0, 1275, 1800}
end tell

Instead of using a link to the inbox for theGmailLink, you can take any other gmail link from the address bar, like compose (""). Now the only thing left is to put it into a simple Keyboard Maestro action:

gmail - open inbox


Now getting to Gmail quickly is super easy, just a keyboard shortcut away.


Omnifocus – Search perspective

In Omnifocus I often need to search for items in my database. The search box is restricted to search only within the contexts or projects that are selected in the current perspective. However, I almost always have to search for actions that are not in the current view.

I now use a keyboard shortcut to immediately select my whole library and place the cursor in the search box, so I can start typing my search right a way. It uses Keyboard Maestro and the power of perspectives in Omnifocus.

First, I created a perspective in Omnifocus called “Search” in the projects view with the Library selected and the following focus values to include everything:

Then I created a Keyboard Maestro Macro that only runs within Omnifocus. It calls the perspective and places the cursor in the search bar:

I find it works more reliably with a time delay, but that may have to be adjusted for you.

Monthly Repeating Macros in Keyboard Maestro

I have some scripts that I want to run every month. So far I’ve been using Script Timer for this, but now I want to consolidate all of these repeating tasks in Keyboard Maestro. However, the scheduling trigger options for Keyboard Maestro only seem to enable weekly schedules at most.

I contacted the makers of Keyboard Maestro about this and Peter got back to me really quickly with a great solution: Create a daily repeating trigger but before running the action, just set up a condition that checks for the day of the month. The action will only execute if the condition is satisfied.

If you want to schedule something for the last day of the month, you can use DAY(TIME()+3600*24) = 1.

I’m only beginning to skim the surface of Keyboard Maestro. What a great app.

Archiving Gmail

On a recent mac power users episode, Katie and David discussed a few email backup systems. They look really useful, but for my needs they are too sophisticated. I just want to download local copies of my email to my mac on a regular basis. So I thought I’d cook up a script for that.

I use gmail, but am using as a back end to do a bunch of sorting and, now, backing up. I decided to go with an applescript that is run every few hours by Keyboard maestro. I wanted a script that looks at the “All Mail” folder of gmail and copies all the recent emails to a local mailbox on my mac.

First, I want to keep track of the last time the backup was run, so I create a .txt file to store the date whenever the backup runs, so I only copy the recent emails since then. I also like to file the emails by year on my mac, so put a piece of code in that checks for the year mailbox and creates it, if it doesn’t exist. There are some emails in my “All Mail” that I never read, so to remove that unread label in my folder I mark them all as read in the end.

John Gruber posted a nifty inbox sweeper script that does something similar, but is not applicable to my workflow, since I like to sweep my inbox manually when I process emails to zero. I did get a neat trick from his script though, which copies all selected emails without looping, speeding up the code. I also used mascripter’s great tutorial on accessing files.

To adopt this, you need to create the LastDate_EmailBackup.txt file and put in a date from which you want to start the backup, e.g. in m/d/y format, and adjust the archive mailboxes to your needs.

set todaysDate to current date 
set theText to todaysDate as string 
set theHomePath to (path to home folder) as string 
set thefilePath to theHomePath & "Library:ScriptSupport:LastDate_EmailBackup.txt" as string 
set oldArchiveDate to date (read file thefilePath from 1) 
set newArchiveDate to oldArchiveDate - 1 * hours --allow for some time cushion
set theOldYear to year of oldArchiveDate as string 
set thenewYear to year of newArchiveDate as string 

tell application "Mail" 
set theMailbox to mailbox "All Mail" of mailbox "[Gmail]" of account "Gmail" 

if theOldYear is thenewYear then 
   set selectedMessages to (a reference to (every message of theMailbox whose date received is greater than newArchiveDate)) 
   if mailbox thenewYear of mailbox "Archive" exists then 
      copy selectedMessages to mailbox thenewYear of mailbox "Archive" 
      set read status of every message in mailbox thenewYear of mailbox "Archive" to true 

      make new mailbox with properties {name:"Archive/" & thenewYear}
      copy selectedMessages to mailbox thenewYear of mailbox "Archive" 
      set read status of every message in mailbox thenewYear of mailbox "Archive" to true 
   end if 
   set selectedMessages to every message of theMailbox whose date received is greater than newArchiveDate 
   repeat with eachMessage in selectedMessages 
      set theDate to date received of eachMessage 
      set theYear to year of theDate as string 
      if mailbox theYear of mailbox "Archive" exists then 
         copy eachMessage to mailbox theYear of mailbox "Archive" 
      else make new mailbox with properties {name:"Archive/" & theYear} 
         copy eachMessage to mailbox theYear of mailbox "Archive" 
      end if 
   end repeat 
   set read status of every message in mailbox thenewYear of mailbox "Archive" to true 
   set read status of every message in mailbox theOldYear of mailbox "Archive" to true 
end if 
end tell 
set eof of file thefilePath to 0 
write theText to file thefilePath starting at eof

UPDATE: An earlier version archived mail from up to 2 days before the last archive date. In it doesn’t seem like this would duplicate a message. However, in the actual Library/Mail folder those messages did get duplicated resulting in a huge number of occupied space. I now archive only email from at most 1 hour before the last archive date to allow for late imports in Gmail from other email addresses. This should keep the number of duplicates to a minimum.