In my first part , I talked about the background of an application we are building. With this post, I want to get into the specifics of the first big problem I tackled.
In my previous GTD implementation, I used Evernote as the main tool. One of the features I got for free with that was the ability to receive email from arbitrary email addresses. Evernote gives you a private email address that you can use to forward email to the system, where it will be converted into a note. This is exceedingly helpful in a GTD implementation because for most information workers, a lot of the actions you’ll be tackling on a daily basis originate as emails.
This first thing I ran across in my design is that I want to be able to forward emails to my ServiceNow instance from multiple originating email accounts and have them all associated with the same user. This means that the out-of-the-box behavior cannot be relied on. By default, an Inbound Email Action will create a record owned by the same user whose email matches in the User table (sys_user). I want to do almost the opposite, I want an email address that will create a record for a user no matter what account sent the email.
This sounds like a job for the SMTP addressing loophole. When you send an email address, for most modern email systems addressing to
Given that situation is true, I created a table to hold Email Tokens. This is a very simple table that contains only a string field (the token) and a reference to a user. The basic strategy here is that when an email is received, in order to find out if it is one of these emails sent to the Action Inbox, we will scrutinize the email token. If we find an active email token in the “To” address, then it not only is one of our Action emails to process but it will be linked to the user that owns that email token.
In our application we have a Script Include called DoNowUtil in which we put most (or hopefully all) of the hairy logic. I created a pair of functions called getGTDUser(emailAddress) and hasGTDUser(emailAddress). The former will take in a given email address. If the address has a token and that token has an entry in the table, it will return the sys_id of the user associated with it. The hasGTDUser(emailAddress) does similar work but returns true or false. Now that we have this, we can begin to do some work creating the Inbound Email Action.
I created a new Inbound Email Action against the Action table in our app (note we have two things named “action” in some way). I set the order to 99 because I wanted it to run before the default built-in email actions. I left the type as “None” because I want this to work on either new or forwarded emails. The condition field on whether to run is now pretty simple:
If that is true, this will run. Inside the script (under the “Actions” tab for extra confusion and naming overload) I create a new DoNow Action record and set the opened_by and assigned_to fields to the user found via the email token. I do some parsing of the subject to look for context and priority indicators (more on that in a future post), I set the short_description to a sanitized version of subject line. Originally we were putting the full email.body_text into the description field (remember that our Action record extends Task). We decided that we wanted to use that field for arbitrary information and that it was a tossup if the body of the email was actually valuable context. Instead, we created a more_information HTML field so that we could both maintain the incoming information from the email but also edit a description if so desired.
This strategy has worked pretty well so far. I actually do use this in the production version of our DoNow application. This allows me to have a secret email address to which I can forward emails from my various email accounts, personal and professional. It is pretty close to a clone of the Evernote functionality or a “Send to Kindle” type situation. In practice, I have not run across a problem either sending or receiving emails or having them create my Actions from these emails.
The original implementation of the logic in getGTDUser(emailAddress) was sub-optimal. It looped over the email token table and did a substring look of each token against the email address. If the table was large, that would be grossly expensive. I recently improved it to parse the token out of the email address and then query for that one record. I’m including a screenshot of the code of the improved version.
There is also a big flaw in the current handling of the tokens. Originally my plan was that one would create and delete the tokens at will, and that would be the totality of managing them. However the use case for deleting them is that some rogue process somewhere has discovered the email address with the token and is sending bogus emails creating bogus actions. In that case, deleting the token would just make hasGTDUser(emailAddress) return false. That means that all these bogus emails will fall through to whatever the default Inbound Email Actions are, probably creating an Incident for each one. What is really needed is at least an active column on the table. Even more thorough would be the ability to blacklist and whitelist specific emails from sending. This is in the backlog for the future but not a high priority at this moment.
This has turned out to be an interesting exercise in creating a new strategy for accepting emails inside of ServiceNow. It is not a common use case that an application needs to route emails from multiple sending email addresses to a single user on the instance but if you have that use case, this is a way to accomplish that.
Series so far: