schedule Gmail drafts for sending with GmailSendLater

I have often found myself writing emails late at night but, wanting to keep up appearances of propriety, preferring to have those emails sent at more respectable hours. I looked around on the internet and found some tools that would do this for Gmail. There are Chrome extensions with fancy UIs, like Boomerang and rightinbox, but they cost money and only seem to work in desktop browsers. I also came across GmailDelaySend, which uses the recent Google Apps Script API to accomplish much of the same functionality for free. I poked around GmailDelaySend’s code and decided that I’d prefer an alternative interface, where the time at which an email should be sent is placed in a custom label instead of in the message itself. Hence, my slavish GmailSendLater was born.

GmailSendLater is a Google Apps Script web app, which means that it installs some code that runs in the cloud and you can interact with it via a website. GmailSendLater’s web interface is here: if you haven’t installed the script this link will prompt you to install it; if you have installed it then you can use the web interface to view debug logs or manually trigger the script to run. There’s more information on the Github wiki.

Sending a draft email with GmailSendLater is a 3-step process:

  1. You label the draft with a label like “send at 2pm” and then take a nice afternoon nap.
  2. GmailSendLater runs (every 15 minutes by default), and replaces your label with a new label like GmailSendLater/sending_at Thursday, February 13, 2014 2:00:00 PM GMT-0900. This allows you to verify that GmailSendLater understands when to send the draft. If you remove this GmailSendLater/sending_at … label, the draft will not be sent.
  3. GmailSendLater sends any drafts that should be sent at the current time.


Figuring out the correct timezone in which to interpret sending times is a bit tricky. GmailSendLater uses the timezone of the draft email, as opposed to the timezone in which the script runs. Some informal testing has confirmed that, at least for me, the GmailSendLater script was running in US Central Time even though my email messages are created in my time zone, US Eastern Time. It also seems possible to get the time zone associated with the user’s Gmail account, which is potentially different still. I haven’t found a need for this third option but perhaps it will arise someday. The SugarJS library that GmailSendLater uses for parsing dates has a limited understanding of timezones, and one can use clunky dates like “30 August 14:30+13:00” to specify timezones by their UTC offset.

Google Apps Script isn’t quite enough

In an initial version of GmailSendLater, I used the Google Apps Script API to send email drafts. This mostly worked except that the GAS API doesn’t have a way to directly send a draft email, so (inspired by GmailDelaySend) I was (ab)using functionality for sending new messages and replying to/forwarding existing email threads. A copy of the draft would be created with the same content, and the copy would be sent.

This copy-and-send approach broke message threading. Most annoyingly, the original draft email could be moved to the Trash but not formally discarded. While the desktop browser version of Gmail is happy to suppress the presence of trashed draft emails within a thread, the Android app does not do this. So, when an email was sent, it would appear twice within a thread: once as a draft and then as a sent email. Ugh. These trashed drafts do not appear in the Drafts listing on the Android Gmail app, so finding them and discarding them is tedious.

Fortunately, I came across a StackOverflow post that showed how to use the Gmail API from Google Apps Script. This allows for first-class manipulation of draft emails, allowing them to be sent directly. This solution, which GmailSendLater adopts, appears to offer the same experience as pushing the send button in Gmail directly, preserving threading and avoiding the pollution of trashed draft messages.

Try it out

GmailSendLater is free and open-source. I’ve been using it for a few months now and have found it very helpful. Bug reports and feature requests are welcome!