I live my life through OmniFocus.
Between my iPad, iPhone and my Mac, it’s the place that I store all of my tasks and random project stuff. I subscribe to the ‘trusted system’ theory – by knowing that I won’t lose track of something if it’s in OmniFocus, I don’t stress out about my todo list rattling around in my head.
Despite the great iOS apps, I inevitably have to process a lot of tasks that begin as email. The Mac version uses the Services menu to allow you to capture text and create list items easily. Unfortunately, due to current platform limits, there’s no such convenience on iOS. That means that by default, going through my email inbox and creating OmniFocus tasks isn’t all that doable on iOS. This troubled me.
Yes, Omni does provide their ‘Send to OmniFocus’ email address – you forward your message to it and it returns it back to you with a reply that contains a URL to populate the app with that task. It’s nice that they include this but come on, let’s be honest: it’s a hack. The messages aren’t linked the same way that they are when you use the Mac service and I just generally don’t like the idea of polluting my email with these extra messages.
Since my Mac at home is running 24×7, I wondered if there was a way I could use AppleScript to create my own solution. Here’s what I’m doing now:
In iOS 5, Apple added the ability to flag a message, just as you’ve been able to do on the desktop forever. I created an AppleScript that looks for flagged messages. When it finds them, it adds them to OmniFocus and links them back to Mail.app, just like the Services action does. It then also unflags the message, resetting the state back to normal. This script runs every five minutes.
What this means is that I can now just add a flag to a message on my iPhone or iPad and know that it will be picked up by OmniFocus.
There’s one serious downside – since Google’s Exchange implementation for Gmail is seriously strange (some might say broken), it doesn’t work there. While Exchange ActiveSync supports flags, the Google implementation does not. If you decide to use ActiveSync to access your Gmail account (i.e. to get contact and calendar sync, push, etc…), this will likely not work for you.
Anyway, this script has been so useful to me that I’m sharing it here. Feel free to use / hack on this yourself as it fits your needs.
I’ve never done anything in AppleScript before so if you’re an AS expert, don’t laugh too hard.
Comments
21 Comments so far. Leave a comment below.For those asking, you can automate AppleScript runs via cron, for example:
5,15,30,45,55 * * * * osascript “script_name.scpt” >> /dev/null
I really like this concept. Unfortunately, the messages for which this would be most helpful are on an Exchange server, so the script doesn’t work for me yet (it’s coded for IMAP only). I’m trying to tweak the script and I found the applescript dictionary for mail.app, but I’m not seeing anything related to Exchange. (IMAP, POP, and iCloud are the only account types listed.) Do you know if that means applescript can’t tap into the Exchange account at all?
Excellent question. Unfortunately, I don’t know the answer to that. I don’t have an Exchange account to test with.
Works well with Keyboard Maestro too on a time trigger, for those of us unfamiliar with cron…
Nice!!!
Thanks for the work..
Picked this up via MacSparky! You are now in my RSS feed…
Dear Hunter,
many thanks for this great script. I run into problems, as the script found my inbox, but not any flagged messages. OS is Lion and the account is an exchange account. Do you have any idea what the problem might be? Please see below the script’s reply.
Best,
Carl
tell application "Mail"count every account
--> 1
get name of item 1 of every account
--> "xxx"
get mailbox "Inbox" of item 1 of every account
--> mailbox "Inbox" of account "xxx"
count every message of mailbox "Inbox" of account "xxx" whose flagged status = true
--> 0
end tell
From other feedback I’ve received, Exchange is acting up a little bit. If there’s anyone else out there that knows the answer, please post here!
On my Mac I switched from exchange to imap for mail purpose only, i.e. calendar and adressbook are still synchronising over the exchange server resulting in the best of both worlds: Your script is running and the advantages of the exchange-server are still available. The mobile clients (iphone/ipad) are still running on exchange for mail also. Now everything works very smooth.
Maybe this concept is also a solution for others?
Again: many thanks for this great script!
I wonder if a good workaround to Gmail’s IMAP strangeness would be to make a special label (IMAP folder) and monitor it for any new messages that are put in it. When they are, an OmniFocus task is created and the message is removed from the IMAP folder. But would this break Mail’s ability to find the message when you try to navigate to it from the OmniFocus task?
I just flagged a message I received in my gmail account on my iPad and after I checked Mail on the Mac (10.6.8), it showed up as flagged there as well. Unflagging it on the Mac and updating Mail on the iPad cleared the flag there. Maybe there are some cases where it doesn’t work, but it apparently isn’t the case that it never works.
Did you have some actual basis for the comments about Gmail’s IMAP implementation being the reason for this not working? There’s a big gulf between “I tried it once and it didn’t seem to work (but I only spent 30 seconds and I don’t actually know anything about IMAP but I saw some guy say Gmail has a weird IMAP implementation)” and “This won’t work with Gmail because they don’t implement section 5.3.2.9 of the IMAP spec”
I can flag a message on my Gmail IMAP account on one Mac and it will be flagged when I check the account on another Mac set up the same way, though sometimes it takes a little while to update. Maybe the Mail app on your iOS gadget just hadn’t yet written the change back to the server due to your choice of Fetch settings, or Mail on your Mac hadn’t pulled in the change.
Most unfortunate that the link the script creates doesn’t work with the iOS Mail apps, but that’s Apple’s fault. Thanks for posting the script! I would say anyone reading this who thinks it might be useful should try it, rather than just concluding it won’t work because they use Gmail.
I tested it a dozen times with Gmail and never got it to work reliably. Also, I opened a bug with Apple and Engineering told me it was Gmail’s issue and they closed the bug. From what I’ve been told, when you flag something in Gmail, it assigns the flagged label, it doesn’t set the flagged attribute on the message that other IMAP clients recognize. All of that said, I am not an IMAP expert and I’ve never implemented the RFC. If someone wants to figure out definitively why it doesn’t work reliably, I’d be curious to know.
If you know different, I’d love to hear more details. I have a couple of Gmail accounts and it’s a pain this doesn’t work with them. Perhaps there’s some sort of setup difference? Mail.app has my Gmail accounts set as IMAP – AFAIK, nothing custom. I’m running Lion on the Desktop, not Snow Leopard. Perhaps that’s a factor.
I have my various mail apps set to check fairly aggressively and in my tests, even after 60+ minutes I wouldn’t see a state change.
Very curious, indeed! My Gmail accounts are all straight out of the box. In fact, I just created another one to test it again after you responded. I’m not an IMAP geek, either, but I can click on the yellow star on the gmail webpage as well as the next guy, and if I do, the flag eventually follows suit on my Macs and iPads, and vice versa. That strongly suggests that they are all using the same signaling mechanism. A friend now at Google used to be an iMAP geek at Apple, I’ll ask him next time I see him. As a former engineer in a big software organization, I’m always a bit skeptical when told by engineering management that the problem was someone else’s fault
Oh, Apple Engineering could be wrong. They’ve certainly closed bug reports of mine in the past erroneously.
Anyway, if you do get a chance to ask your friend, I’d love to hear the details. It would be awesome if this could all work seamlessly.
I spoke to my friend, who said he is unaware of any Gmail implementation details with regards to stars/flagging, but that he uses it all the time without difficulty in conjunction with Mail.app, the gmail web app, and the Mail for iPod touch. Maybe it’s all in the wrist
Just to be clear – for both of you guys, when you use the flag function in the native iOS Mail app, that flag makes it’s way to Mail.app on the Mac? I think that’s what we’re all saying but since it doesn’t work for me at all in either of my accounts, it’s a surprise to hear.
In talking to a few other people in relation to this script, I’m definitely not alone. I’d love to determine what the other variable is.
Upon closer inspection, I may have figured this out… Turns out, my iPhone was setup to use Gmail as Exchange, not as IMAP. That appears to be where the breakage is (Exchange ActiveSync supports flags but it appears Google’s implementation does not). So, it’s likely true that the IMAP bit works fine and those of us with trouble are using ActiveSync to access Gmail, to access the extra features that come with that option. Sounds like to get push, calendar and contact sync, you have to give up flags… I’ll update the post.
Yes, flag goes from iOS Mail to Mac Mail to gmail web view. I’m using IMAP, I think my friend does also. Sounds like you found the sticking point.
Working with Exchange!
Exchange accounts are of type “unknown”. Awesome
I’ve been using this for over a month, so it’s about darn time I sent it back to you.
I have Exchange server side rules moving some messages into different folders. However, I want the flagging to still look in those, so I created a list. I use 0 and 1 to keep certain folders near the top of the pile.
Secondly, rather than just unflagging the email message, I want to clean up my inbox(es). So any email that’s sent into Omnifocus also gets moved into the 1OMNIFOCUS folder on my Exchange account (even if I flagged it in a different account. I’m weird like that). The mail URL still finds that message but it saves me a step of filtering it. I only want to touch a message once when I’m processing my inbox.
on run
set _exchange_interesting_mailboxes to {"Inbox", "0GROUP1", "0GROUP2"}
set _omnifocus_followup to "1OMNIFOCUS"
with timeout of 90000 seconds
-- first find our Exchange account so we only store follow up items there
tell application "Mail"
repeat with _acct in accounts
set _acct_status to enabled of _acct
if _acct_status is true then
set _acct_type to account type of _acct
if _acct_type is unknown then
set _acct_server to server name of _acct
set _acct_name to name of _acct
if _acct_server contains ".SOMETHING TO IDENTIFY YOUR EXCHANGE SERVER" then
set exchange_account to _acct_name
end if
end if
end if
end repeat
end tell
tell application "Mail"
repeat with _acct in accounts
set _acct_status to enabled of _acct
if _acct_status is true then
--Look For Flagged Messages in the INBOX
set _acct_name to name of _acct
set _acct_type to account type of _acct
if _acct_type is unknown then
#set _inbox to _acct's mailbox "Inbox"
set _mailbox_list to _exchange_interesting_mailboxes
else
#set _inbox to _acct's mailbox "INBOX"
set _mailbox_list to {"INBOX"}
end if
repeat with _mbx in _mailbox_list
set _inbox to _acct's mailbox _mbx
set _msgs_to_capture to (every message of _inbox whose flagged status is true)
repeat with eachMessage in _msgs_to_capture
set theStart to missing value
set theDue to missing value
set theOmniTask to missing value
set theTitle to the subject of eachMessage
set theNotes to the content of eachMessage
set theCombinedBody to "message://%3c" & message id of eachMessage & "%3e" & return & return & theNotes
tell application "OmniFocus"
tell default document
set newTaskProps to {name:theTitle}
if theStart is not missing value then set newTaskProps to newTaskProps if theDue is not missing value then set newTaskProps to newTaskProps if theCombinedBody is not missing value then set newTaskProps to newTaskProps set newTask to make new inbox task with properties newTaskProps
end tell
end tell
set flagged status of eachMessage to false
move eachMessage to mailbox _omnifocus_followup of account exchange_account
end repeat
end repeat
end if
end repeat
end tell
end timeout
end run
Hunter
Have stumbled on your script and if I could get it to work it would complete my workflow!!!
Problem I have is twofold…
1. I’m an applescript novice (make that complete novice!!)
2. have compiled the script and popped it into com.apple.mail
3. I have then used Mail Act on to call the script for flags – does this run continuoalsy or do I need to put a time mechanism in here?
3. when I run the cript from applescript editor I get the following error…
error “Mail got an error: Can’t get item 2 of every message of mailbox \”INBOX\” of account \”Phil Personal\” whose flagged status = true. Invalid index.” number -1719
Help – any advice guidance gratefully received!
Cheers
Phil
AppleScript is not a language I have much experience in myself so I’m not sure if I’ll be able to help. Maybe someone else will see this and knows the answer!
I’m having the same issue.
I also got the same error. Traced it to having inactive accounts in my list of accounts that were being processed. The first few items in the list of my accounts were active and were processed. The next one was inactive and Hunter’s script tried to process it and failed raising an exception, terminating the script.
Two solutions:
1: Wrap the contents of the first repeat block in a “try” block
2: Test if the acct is active and only process it of that’s true.
I went with 2: because AS is slow enough when processing mail. Here’s the revision:
on run
tell application "Mail"
repeat with _acct in imap accounts
--Look For Flagged Messages in the INBOX
set _acct_name to name of _acct
log _acct_name
if _acct is enabled then
set _inbox to _acct's mailbox "INBOX"
set _messages to ¬
((every message of _inbox ¬
whose flagged status is true))
repeat with eachMessage in _messages
set theStart to missing value
set theDue to missing value
set theOmniTask to missing value
set theTitle to the subject of eachMessage
set theNotes to the content of eachMessage
set theCombinedBody to "message://%3c" & message id of eachMessage & "%3e" & return & return & theNotes
tell application "OmniFocus"
tell default document
set newTaskProps to {name:theTitle}
if theStart is not missing value then set newTaskProps to newTaskProps if theDue is not missing value then set newTaskProps to newTaskProps if theCombinedBody is not missing value then set newTaskProps to newTaskProps set newTask to make new inbox task with properties newTaskProps
end tell
end tell
set flagged status of eachMessage to false
end repeat
end if
end repeat
end tell
end run