Designing an email-only Slack interface
← Back to Kevin's homepagePublished: 2018 June 30On the design of Stop Slacking, which lets you interact via email with the poor souls trapped in the endless, no-agenda meeting that is Slack.
In 2018 May Nicki Vance and I spent a month traveling around New Zealand’s South Island via camper van. Everything you’ve heard about that country’s scenic beauty is true: We traveled forested mountain passes, rolling sheep-filled grasslands, lush rain forests, and pristine glacial lakes:
Unsurprisingly, many of these beautiful, remote places had little-or-no cellular connectivity.
The Internet situation was somewhat better in small town hotels and holiday parks, where wifi could usually be had via paper vouchers worth 50 MB or 30 minutes.
This wouldn’t have been an issue if we were 100% on holiday, but Nicki had a part-time retainer doing UX design and strategy consulting with a company in Australia.
Unfortunately, that company communicated almost entirely via Slack.
Slack, for those of you who have only experienced the Internet via direct-fiber-to-San-Francisco, is not exactly a bandwidth-optimized application: Just loading an empty workspace in the web app costs about 8 MB (and that’s before anyone starts posting animated GIFs):
This kind of overhead just isn’t going to work when you’ve only got a spotty cellular connection and a bunch of ADHD Aussies incapable of communicating more than one sentence at a time.
If only there were a text-based, asynchronous communication technology robust enough for intermittent, low-bandwidth connectivity.
Say, some kind of technology that downloaded messages when connectivity was available, allowed one to search, organize, and even compose replies while offline, and then send those replies next time connectivity were available.
Product design
As it turns out, a 1970’s technology known as “Electronic Mail” meets all these requirements!
However, it’s no small challenge to convince an organization to switch its preferred communication medium. In this case, it’d be a fight not just against human inertia, but also against hundreds of millions of dollars worth of VC-funded advertising and startup herd mentality.
Together, these two observations form the core product design constraints:
No buy-in. Slackers shouldn’t need to change their behavior at all. The product should provide value to single individuals, without requiring any action from others.
Email only. All interaction should occur over email; sweet, sweet, async, low-bandwidth email. (No web UI, native apps, or talking cylinders.)
These two constraints lead to an ideal product-usage scenario:
- a slacker sends a direct message or mentions someone (“Hey
@non_slacker
, …”) - the non-slacker receives an email containing the message and relevant context (sender, channel name, etc.)
- the non-slacker replies directly to that email
- their response appears in Slack (either as a direct message or as a threaded reply to the original message)
To implement this interaction, Stop Slacking must be able to:
- monitor for
@non_slacker
mentions and direct messages - post messages on behalf of
@non_slacker
- send and receive emails (and keeping track of which emails correspond to which Slack messages)
We’ll cover these in turn.
Integrating with Slack
Since we can’t require action from a workspace administrator (design constraint #1), a Slack App is off the table.
Fortunately, Slack still supports “legacy” token-based API access, which allows one to programmatically search and post messages via an HTTP API.
Users “sign up” by emailing their workspace token to alertbot@stopslacking.com. Stop Slacking then uses this token to poll the Slack API for direct messages and mentions.
Managing emails
When someone receives a message, Stop Slacking sends them an email. When they reply to this email, Stop Slacking posts their reply — so replies must somehow be associated with a Slack message.
Relying on the presence of the original message text is tricky — there’s no reason to expect Slack messages to be unique (e.g., there may be multiple “@non_slacker
, do you have a minute?” messages in a channel), so the email would need to include some kind of unique identifier.
But that identifier might not make it back in the reply — not all email clients automatically quote emails, they might quote differently, and people might mangle or otherwise remove the identifier.
So, instead of relying on content within the email body, Stop Slacking gives every notification email a unique reply-to
address.
Then, when an reply is received at this unique address, Stop Slacking knows which Slack message the reply is intended for.
In terms of a person’s email address, there are at least three in play:
- The email address associated with that person on Slack (accessible via the Slack API)
- The email address to which Stop Slacking sends notifications
- The email address from which someone sends replies to Stop Slacking
This last address cannot be relied upon because of email spoofing, and is ignored entirely.
As for the first two, there’s no reason to constrain them to be identical — in fact, keeping them distinct enables more capabilities.
For example, receiving notifications from different Slack workspaces at different email addresses (say, example+work@gmail.com
and example+friends@gmail.com
) allows one to easily tag and filter with their email client.
So, Stop Slacking ignores the email address listed in Slack and instead only uses the one provided with the token during initial signup.
Technical implementation
From a technical perspective, Stop Slacking isn’t a particularly interesting application:
- about 400 lines of Clojure
- deployed via uberjar to EC2
- incoming emails received by SES, sent to application via SNS webhook (HTTP POST)
- java.util.concurrent threadpool’s scheduleAtFixedRate polls Slack for new messages
- application state is stored as an EDN flat file
The application state is fairly minimal. It consists of:
- The mapping from
reply-to
addresses to Slack message IDs (needed for handling incoming replies) - The timestamp of the last sent notification (needed to track whether a notification has already been sent for a Slack message)
The only Slack APIs used are search.messages (to poll for messages) and users.info, which is needed to replace user IDs in message text with display names (presumably, Slack stores references to other Slackers within message text as IDs so that messages can always be rendered with someone’s current display name).
Perhaps more interesting was the coding itself — the application couldn’t be run locally within the camper van itself, because simply retrieving the AWS SDK dependency from Maven would cost 160MB. Instead, the application was developed on a throwaway EC2 development machine via SSH.
Nicki and I designed and built the prototype together over a few evenings in New Zealand. Since then, she’s written and illustrated the landing page and refined the product features.
Future work
While we developed Stop Slacking specifically for Nicki’s situation, there are some features that should easily fit within the current design and provide more powerful capabilities:
Allow notifications to “fan out” to multiple addresses. This would allow multiple people to control a single Slack user, which might be helpful in support / public relations contexts on public channels. (Of course, since Stop Slacking relies on email, this functionality can already be implemented via a shared email address or help desk service.)
Allow one to subscribe to general queries, rather than just mentions and direct messages. This wouldn’t require any changes to the current implementation for search/notification, but it does raise questions about the level of “subscription granularity”. E.g., would one subscribe to each query separately, risking multiple notifications per message (one notification per matching query)? Or would a single subscription incorporate multiple queries (and thus require a more complex email “command language” for managing the queries)?
Add structured metadata to notification email bodies so that people could reliably setup email client tagging/filtering (“Send messages containing
includes_animated_gif: true
directly to the trash”).