The Legal implications of SPAM
In 2003 President G. W. Bush signed a new law named “Controlling the Assault of Non-Solicited Pornography And Marketing (CAN-SPAM) Act of 2003” which is an approach to the growing number of complaints over commercial spam-emails. In this context, a commercial email is "any electronic mail message the primary purpose of which is the commercial advertisement or promotion of a commercial product or service.“ Thus, in order to regulate the traffic of commercial email, the US congress determined that all recipients of such a kind of emails must have the right to decline them.
Regarding this, having an automatized system to allow recipients of commercial emails to decide whether or not they want to be sent email from an organization becomes pretty handy, specially for people involved in marketing and sales who are very prone to inadvertently spam their potential clients.
Clear Nexus: a type-safe and functional solution
Clear Nexus is a two-part service consisting of a Chrome extension which communicates to a back-end server process. It allows you to determine if the owner of an email address has unsubscribed from your organization's commercial emails, which means that sending content to that address would violate the CAN-SPAM law, as well as offering an easy way for recipients to start rejecting emails by letting them join a do-not-contact list maintained by the back-end.
At Stack Builders, we believe that Functional Programming is a great way to write composable and modular applications. That’s why when making the technical decisions about which technologies to use for the implementation of Clear Nexus, we chose two of the heavyweight contenders in this field. First, we chose Haskell (and the Servant library) for the back-end, since, from our experience as software developers, it has been an amazing tool when it comes to building expressive, type-safe applications.
Unfortunately, the usual choice for building Chrome extensions is vanilla JavaScript. If you're reading this post, perhaps you've had problems with debugging JavaScript applications, since due to its dynamic typing, errors need to be detected at runtime. This problem is even more evident when you have to design such programs that typically rely on a multitude of side-effects, for example, when manipulating the browser’s DOM or in handling asynchronous processes.
Fortunately, in JavaScript-land, many people have become aware of these issues and they have come up with different solutions. One of those solutions is PureScript: our second contender in Clear Nexus. PureScript is this tiny language that is pretty much like Haskell, but compiles to easy-to-read-and-reuse JavaScript. This means we can do DOM manipulations, asynchronous operations, AJAX requests and many other common things programmers are used to doing in JavaScript, without leaving type safety and composability behind.
Implementation of a Chrome extension in PureScript
When designing Clear Nexus there were three main concerns:
- How to querying the DOM of the Gmail’s main page in order to get information from the textarea.
- How to handle asynchronous operations with the Chrome-storage API.
- How to handle asynchronous requests to the Clear Nexus back-end.
Basically, Clear Nexus keeps a loop querying the Gmail’s DOM for emails typed in the compose text-area. Once an email is detected, an AJAX request is sent to the back-end and when it answers back, the extension processes the response and determines if the requested email is either subscribed or unsubscribed. After this, the loop starts again and the extension keeps listening to new events in the compose area.
PureScript has a pretty handy Foreign Function Interface (FFI) which allows you to easily introduce third-party modules from the enormous JavaScript ecosystem. Thus, PureScript is ideal for adding type-safety to JavaScript foreign functions and also, its monadic and I/O features -similar to Haskell’s- make it a great option to handle effectful asynchronous operations in a modular way.
In this fashion, it was possible to approach all of the aforementioned concerns properly:
-
Where possible the Gmail’s DOM is manipulated with the purescript-dom library, but we found that some operations are still cumbersome to do with PureScript and so they were directly implemented in vanilla JavaScript -for example, the operation to paste the unsubscription link in the main textarea and given a type with the FFI. Thus we could make use of browser's built-in functionality and bring it into the PureScript world with type safety.
-
The FFI was used to wrap some operations of the Chrome-storage API - for example, in order to store the admin-token in the storage, we wrapped a function which used the Chrome.storage.sync.set operation, and gave it a type inside PureScript. On the other hand, as manipulating the Chrome-storage is effectful, a Chrome effect was specifically defined to add better specificity to the functions manipulating it.
-
The main loop of the application was implemented as a “recursive callback” between two functions which call each other when an asynchronous operation has completed: The first one executes a callback when an email has been detected in the compose text-area. The second operation is the callback itself which performs the request to the back-end and which subsequently performs more asynchronous actions depending on the answer of the back-end. Nonetheless, this callback calls again the first operation to repeat the loop.
In order to handle the complexity described in the third point, two PureScript modules were used: 1) purescript-aff which provides the Aff monad to handle asynchronous callbacks in continuation passing style, which is a step further from promises to handle a pipe of asynchronous actions.2) The module Control.Monad.Eff.Uncurried of the package purescript-eff which allowed us to implement the callback to be called recursively, so that the main loop of the application could be completely implemented as PureScript code without the need of turning to vanilla JavaScript.
Conclusion
At Stack Builders, we are passionate about technologies that promote best practices and design patterns in the software industry. We believe that open source is a great way to disseminate this knowledge throughout the community, so we're releasing our Chrome extension under the MIT license.
If you'd like to learn more about how to write Chrome extensions in PureScript, take a look at our repo and contribute either by leaving your comments, describing issues or opening pull requests!
Finally, if your team needs help in constructing application front or back-ends using functional languages, reach out to us at Stack Builders and we'd be happy to discuss your project with you.
Getting started
If you'd like to use Clear Nexus for your own sales and marketing efforts, you can sign up for a free account here.
You can install the extension directly from the Chrome store and you can find a Getting Started
page about the Clear Nexus application and extension in the tutorial page of the official web site.