Send Time-Delayed SMS on iOS with Drafts.app and Due.app

Tags: , , ,

Bottom Line: This is a custom URL Action for the iOS app Drafts that sends an SMS message to Due.app to be sent later.

You may have heard some of the buzz lately about Drafts. I wasn’t sure what it was all about, but on a whim I decided to give a shot to both Drafts ($2.99 iPhone and $3.99 iPad) and Pythonista ($5, universal).

Possibly the biggest cause for buzz about Drafts is its implementation of x-callback-url, which is essentially a way for one iOS app to launch and optionally send information to a second app, then optionally return the user to the first app. The “sandbox” in iOS generally prevents apps from directly communicating with one another, and so this helps to build a bridge between them. While at first blush Drafts may seem like “just another notepad” app that can send data to other apps, it also allows you to built custom email, Dropbox, and URL actions that give you a way to automate some cool tasks with a single click (or maybe a few). For example, the email actions can send a pre-formatted email to a given address (e.g. this way to send a note to OmniFocus without leaving Drafts), and the Dropbox actions can automatically upload a pre-formatted text file to a predefined Dropbox folder. This is perfect for remotely triggering apps on your computer via Hazel or folder actions, as I’ve discussed before.

It’s the URL actions that are really changing things up, though. For example, yesterday I saw a post on Lifehacker about a new app for sending time-delayed texts. This is one of the few features that I really miss from my jailbroken days; being in medicine means I’m often up much earlier in the morning than my peers, and I hate to risk waking them with a text. However, if I wait to send the text, there’s a pretty good chance that I’ll either forget or get busy. Sometimes, I’ll set a reminder with Due to send the text later — this is a pretty good solution, especially since Due can attach a contact’s phone number to a reminder so that checkin the reminder launches you right into a phone call or text to that person.

However, I got wondering how Due would handle a URL. The dev team at Due has always seemed very forward thinking and clever (not to mention friendly)… so I put in a task with the title http://n8henrie.com … and sure enough, checking the reminder prompted me to open the site. So I tried something else — I put in a reminder with the title drafts:// … and it worked like you might imagine, sending me to Drafts.app.

After (quite) a bit of thinking, I dreamed up a URL action for drafts that would make a reminder in Due (using Due’s x-call-back-url support), and afterwards return to Drafts. The reminder in Due would be a link to Drafts, that — when checked — would open Drafts and trigger the “Message” action. Here’s the thing, though — the initial Drafts action would pass the text contents of the screen (in Drafts) to Due, which would then pass them back to Drafts, which would then pass them to the message. In this way, I could compose a message to a friend in Drafts, and click the “Text Later” action (my name for this URL action). Due would launch and I’d choose when I wanted to be reminded. When the reminder launches, I just check it off and my message appears — all I have to do is choose a recipient.

It took quite a bit of tinkering with URL encoding all the special symbols and spaces in the message, but I finally got something to work. The hardest part was figuring out why Due kept giving me some kind of warning about sync and backing up… it seems like it had something to do with case-sensitivity. In my testing, using Due:// at the beginning provokes the problem, and due:// works great. Weird. Oh, one other thing — I was testing these URLs in Notes.app, so I could easily compose on my Macbook and test on my iOS devices, but this ended up costing me a significant amount of time. I eventually discovered that clicking + holding a link in Notes.app and using the “copy link” popup copied a url-encoded version of the link to the clipboard, not the link verbatim. I found that instead, if I clicked elsewhere in “Notes” to put it into edit mode (where hyperlinks are no longer clickable), I could then select and copy the links verbatim. I hope that

Anyway, on to the action. Unless there are problems with posting and URL encoding on my blog, the following link should automatically open Drafts and install the URL action. NB: If you have Drafts set to require a “key,” you’ll need to edit the URL to include %26key%3DYourKeyHere immediately after the word Message and before }}. Otherwise, I think the Due reminder should get made correctly but fail to bring things back to Drafts when you check it off.

Click Me from an iOS Device with Drafts.app installed

If that doesn’t work or you prefer not to install the action that way, here is the action as it appears in Drafts; you should be able to C&P it as a new URL action. Once again, if you have Drafts set to require a key, you’ll need to modify it slightly by putting &key=YourKeyHere immediately after Message and before }}.

The only other comment I have is that I used Draft’s “Manage Actions” to set it to delete the text from Drafts once sent, so returning to Drafts from Due brings me to a clean slate, ready for my next task.

Update Mar 05, 2013: Personally, I really like Due’s interface for setting the alarm time and therefore didn’t invest energy into building it into the URL. However, it seems like this is a popular and desirable feature for many people. “The Axx,” Alex Guyot, has expanded considerably on this Drafts to Due idea in his post here. In it, he gives a great overview of problems with and potential solutions to providing a “at time” criteria in the URL, as well as expanding Due’s URL support to a variety of “text later,” “Tweet later,” and “post later” implementations. Well done! Readers may also be interested in my link to imissmymac’s post in the comments section.

  • http://twitter.com/imissmymac imissmymac

    here is a little hack so that you can pre-set the time of the alert (so that Due can parse it). Just put the time in the first line of the draft:

    due://x-callback-url/add?title={{drafts:///create?text=[[body]]&action=Message}}%20at%20[[title]]&x-source=Drafts&x-success=drafts://

    • http://www.n8henrie.com/ Nathan Henrie

      Very nice, thanks for the tip! I had initially thought this might have an issue with the “at 9 pm” (or whatever time) showing up in the body of the text, since it is still visible in the Due reminder, but it looks like the whitespace prevents it from being passed back Drafts. Works great, thanks!

      I’ll also point out that imissmymac has made this into a “tweet later” script, which s/he has posted here: http://imissmymac.com/schedule-a-tweet-for-later-with-due-and-drafts/ . I think there is potential for Due and Drafts to work together in a great number of delayed, semi-automated tasks.

  • Pingback: Schedule a Tweet for Later with Due and Drafts()

  • http://www.n8henrie.com/ Nathan Henrie

    I’ll also note that the Due team has published a few other URL scheme tricks here: http://www.dueapp.com/developer.html. Among them are way to set a [static] absolute or relative due date, or one could use Drafts’ first-line “title” trick (as demonstrated in the comments by imissmymac) to make either of these dynamically configurable. However, the date formatting required by Due seems a bit formidable, hence the convenience of the “at [time]” Due parsing workaround. I imagine a bit of playing with Python’s datetime module and an extra pythonista:// step could work, but that seems like a lot of work. Especially when Due’s ability to set a due date quickly is already so good.

  • goodmartian

    Awesome post. I’ve been messin’ around with Drafts, but haven’t found a way to include a recipient in the URL. Do you know of a way to include even just a ‘hardcoded’ phone number so that the Message window in Drafts is pre-populated?

    • http://n8henrie.com/ Nathan Henrie

      I have not done this, but I *think* it should be readily available using Drafts new Messages Actions: http://agiletortoise.com/support/drafts/message_actions.html

      I would recommend creating a Message action, then you’ll have to modify the &action= part to change it from Message to the name of your new Messages action. The overall scheme of the URL action would be: URL Action: [Make an action in Due to [create (“create?text=[[draft]]”) a draft with this content and [Run the new Messages “&action=” to a specified individual]]]

      If you run into trouble, it will likely be with URL encoding all the stuff. Let me know if you give this a shot; I’m pretty busy today, but I’ll comment if I find time to figure it out.

      • goodmartian

        Thanks, this worked! It’s probably my best bet, but I was trying to find something a bit more dynamic, where I could pass the phone number in the URL action (be it via [[clipboard]] or otherwise). Probably a convoluted solution, but just curious.

        • http://n8henrie.com/ Nathan Henrie

          I’m not sure how to do this with Drafts. I just tried a new Message Action using [[title]] as the recipient and [[body]] as the message, but in my testing it just literally used “[[title]]” for the recipient (instead of using the phone number I put in the first line).

          You seem to enjoy playing with Drafts — I have to recommend Pythonista, if you don’t own it already. I’ve used it to start learning the basics of Python; here are a few of my projects so far: http://n8henrie.com/tag/pythonista/ .

          The reason I bring it up is that I think you could fairly easily make a script in Pythonista to accomplish this. You could use the SMS:// URL protocol to open messages to a contact specified in the URL passed in by Due (therefore dynamic), and use the clipboard module to copy the message body to the iOS clipboard, which you would just have to paste in (I don’t think you can pre-fill the body using the SMS:// protocol). Might be worth a shot.

          • goodmartian

            Thanks for the recommendation. I’ll have to look into Pythonista.