Do you ever need to send an email, but hate the thought of opening Gmail and seeing an inbox full of expectations?
On this week’s episode of Systematic, Merlin told Brett how much he enjoys using Drafts on iOS to quickly send an emails to solve exactly that problem. He also mentioned there isn’t an easy way to achieve the same thing on the Mac. Since I wanted such a tool to exist, I decided to take a whack at it and see what I could come up with.
I thought the best fit for such a tool would be a system service. As much as I still enjoy using TextExpander to process text, copying the email content to the clipboard and typing a snippet is inelegant and leaves room for error. A system service can be called from pretty much any application with a quick keyboard shortcut of my choosing. Besides, I’ve never created a system service before and where’s the challenge if I don’t try something new?
How Does it Work
Like Drafts, it uses the first line of input as the subject of the email and lines three through the end for the body, assuming you’ll leave a blank line between the subject and body. Optionally, you can launch an empty Gmail message by using your key command with an empty selection .
The service uses Gmail’s URL syntax which allows fields to be prepopulated in the address bar. It’s the same idea behind the YouTube URL scheme that allows you to do things like link to a specific time in a video. For my purposes I would need the syntax for subject, body and opening the compose window in full screen . As it happens, those URL parameters are as follows:
subject: su= body: body= full screen compose: fs=1
Just like YouTube, these parameters are concatenated with an ampersand, creating a URL that looks like this:
When using the service, you can compose your message in any application, then, when you’re ready to send it, select the text and hit your keyboard shortcut. As long as you’ve previously logged into Gmail in your browser, you’ll be taken directly to a full-screen compose window awaiting your recipient’s email address. And even better, after you hit send, you won’t be taken back to your inbox.
This being the complete hack that it is, there are some limitations to the service.
First, it’s plain text only. Since the content of the message passes through the location bar of your browser, there’s no way (that I can tell) to pass rich text. My hope was to be able to write emails in Markdown and process the text before sending, but as of yet, I haven’t been able to figure out how to make that happen.
Second, and this is a big one, there is a limit on the length of the email. It may sound like a deal breaker, but in practice it’s not as inconvenient as you might imagine. Because this hack uses a URL to pass the email information, we’re limited by the maximum URL length supported by the browser. Yes, there is a maximum URL length.
In my testing, I found the maximum length of a working URL was 1465 characters. The result was the same for both Chrome and Safari. Since the service is adding extra characters to the email content in order to create a functioning URL, the length of the actual email content is limited to around 1350 characters.
It’s a bummer that this limitation exists, but if you’re writing a longer email and you’d still like to avoid your inbox, I suggest launching a blank Gmail message (as mentioned above) and composing your message in the browswer or using the service with only the subject line selected and pasting in the body text manually .
If you’d like to tweak the code or use it in another way, here it is.
#!/bin/python import sys import re import subprocess import urllib from sys import stdin, stdout tinput = stdin.read() def subject_sel(s): line_list = re.split('\n', s) sub_final = line_list return sub_final def body_sel(b): line_list = re.split('\n', b) body_final = "\n".join(line_list[2:]) return body_final full_url = "open https://mail.google.com/mail/?view=cm&ui=1&fs=1&tf=1&su=" + urllib.quote(subject_sel(tinput)) + "&body=" + urllib.quote(body_sel(tinput)) process = subprocess.Popen(full_url.split(), stdout=subprocess.PIPE) output = process.communicate()