Last night at the New York ColdFusion User Group (NYCFUG), Aaron Foss gave a presentation on using SMS short codes with the free service, TextMarks, to integrate text messaging into your ColdFusion applications. It was a really good presentation and one that inspired me to come home and immediately start trying out TextMarks (at least as a place to start). I don't have any great ideas for SMS integration at this point; but, it looked so easy, I had to give it a go.
Basically, TextMarks provides a shared short code - 41411 - that all members of the site must use. To differentiate one member service from another, you need to select a keyword. This keyword then must be sent with the text message as the first piece of data. So, for example, I obtained the keyword, "bennadel". As such, all users that want to access my services must send text messages that start out with "bennadel":
41411 >> bennadel ......
The "bennadel" keyword is just a routing device and is not part of the actual request data.
NOTE: The reason there are "shared" short codes is because having a dedicated short code is extremely expensive! I'm talking tens of thousands of dollars a year.
You don't actually have to put any of your processing on TextMarks. What TextMarks does is act as a proxy to your web-based application. When you create your keyword (routing value), you define a URL to which TextMarks should pass on the request as a GET post. You then accept the request, do whatever processing you need to do, and return a very simple HTML page. Here is a screen shot of the keyword setup form:
As you can see, very simple. For the keyword "bennadel," I defined the following URL:
In order to make the requests usable, TextMarks provides a number of variables that you can replace into your URL. So, for example, if you look at the URL that I provided, I am using the variable "\0". This \0 variable gets replaced with the entire request made by the user. There are a number of other variables available like Phone Number and unique ID, but for my testing purposes, the raw request was sufficient.
For my first SMS-enabled ColdFusion application, I kept it extremely simple: random number generation (do I know how to party or what?!?). Let's take a look at the page I have at the above URL:
<!--- Param the request data. In TextMarks, we are going to set up "smsdata" to contain the "\0" data, which is the entire request made by the user. ---> <cfparam name="url.smsdata" type="string" default="" /> <!--- Now that we have the SMS data, let's break it up into an array so that we can start to treat it like actions. NOTE: I am using multiple delimiters because TextMarks allows the user to use several different keyword delimiters. ---> <cfset tokens = listToArray( trim( url.smsdata ), " ,*-" ) /> <!--- Now that we have the data collection, let's examine it to see how we should process the given request. Of course, before we start testing it, we have to make sure that at least the first item exists. ---> <cfparam name="tokens[ 1 ]" type="string" default="" /> <!--- Wrap the processing in a try/catch so if something does go wrong, we can catch it and return a response. ---> <cftry> <!--- Check the first data item. ---> <cfswitch expression="#tokens[ 1 ]#"> <!--- The user wants to get a random value. For easy of use, we are allowing the user to use any of the following values to access this action. ---> <cfcase value="r,rnd,rand,random" delimiters=","> <!--- Now that we know we are in the "Random Number" action, let's param our arguments. ---> <cfparam name="tokens[ 2 ]" type="string" default="" /> <cfparam name="tokens[ 3 ]" type="string" default="" /> <!--- Check to see how many arguments the user passed. To be simple, we will based this on the number of numeric arguments they passed. ---> <cfif ( isNumeric( tokens[ 2 ] ) && isNumeric( tokens[ 3 ] ) )> <!--- We have both a lower and an upper limit to our random range. ---> <cfset randomValue = randRange( tokens[ 2 ], tokens[ 3 ] ) /> <cfelseif isNumeric( tokens[ 2 ] )> <!--- We have only an upper limit to our random range. As such, we will treat the lower range as 1. ---> <cfset randomValue = randRange( 1, tokens[ 2 ] ) /> <cfelse> <!--- We have no lower or upper limit on our range. As such, we will assume that this person is doing a boolean randomization between zero and one. ---> <cfset randomValue = randRange( 0, 1 ) /> </cfif> <!--- At this point, we should have a randomly selected value for the user. Create the reponse text. Remember, we don't have to worry about white space here as that will be cleaned later on. ---> <cfsavecontent variable="responseData"> Random Value:<br /> <cfoutput>#randomValue#</cfoutput><br /> </cfsavecontent> </cfcase> <!--- ---------------------------------------------- ---> <!--- ---------------------------------------------- ---> <!--- The first argument that they passed was not recognized by our system. Let's send back a default instruction set. ---> <cfdefaultcase> <!--- When building the response data, don't worry about leading / trailing white space - that will be stripped out later on. ---> <cfsavecontent variable="responseData"> Command list:<br /> rand<br /> rand N<br /> rand M N<br /> </cfsavecontent> </cfdefaultcase> </cfswitch> <!--- Catch any exception. ---> <cfcatch> <!--- An error occurred. Alert the user and. ---> <cfsavecontent variable="responseData"> Ooops<br /> An error occurred.<br /> Check your inputs.<br /> </cfsavecontent> </cfcatch> </cftry> <!--- At this point, we should have a valid response in our respondData variable. Now, we need to clean it up for SMS response. Let strip out the extra white space, including the leading / trailing line spaces. NOTE: TextMarks will automatically take care of stripping out our <BR /> tags and replacing them with text-valid line breaks. ---> <cfset responseData = reReplace( trim( responseData ), "(?m)(^[ \t]+|[ \t]+$)", "", "all" ) /> <!--- Convert the respond data into a binary variable so that we can easily stream it back using CFContent without having to be fanatical about clearing the content buffer. ---> <cfset binaryResponse = toBinary( toBase64( responseData ) ) /> <!--- Set headers. ---> <cfheader name="content-length" value="#arrayLen( binaryResponse )#" /> <!--- Stream content back as HTML. By using the Variable attribute, we are ensuring that no extra white space is being passed back. ---> <cfcontent type="text/html" variable="#binaryResponse#" />
As you can see, the above code produces a very simple HTML page. It's almost not even an HTML page at all; I call it HTML only because you can use the <br /> tags to define line breaks (TextMarks knows how to replace those with valid SMS-style line breaks).
Once the request starts, I take the raw request data submitted by the user and break it up into an array. Remember that your keyword ("bennadel" in my case) is not submitted as part of this request data - the keyword is simply a routing device used to point to the above URL. With the array of data in hand, I then check to see how the request needs to be processed. Because there is nothing on the TextMarks side that ties us to any particular type of request data, this URL can be used to handle all sorts of requests; in my example, I am randomly selecting a value, but, simply by using different CFCase values, I could start adding more functionality to this service at any time.
To show you that this is working, here is a screenshot of my iPhone:
As you can see, I texted "bennadel rand 1 100" to TextMarks. TextMarks, in turn, sent "rand 1 100" to my URL, and I returned the HTML page with the randomly selected value:
As you can see, TextMarks put some ads at the bottom of the SMS response; this is just something you have to put up with if you want to use the free service. TextMarks offers Pro accounts that will get rid of the ads for a certain number of text messages per month.
You might ask yourself why not just use the CFMail gateways to send SMS text messages? There's nothing inherently wrong with doing that. However, those mail gateways are provided as a courtesy by the cellular carriers, and if you abuse them, they will have no problems shutting a particular address down. Also, monitoring an email inbox for SMS messages is not the easiest thing to do.
Right now, I don't have any really great ideas for adding SMS capabilities to my ColdFusion applications; but, knowing that these options exist plants the seeds for new ideas. I am sure I'll be looking into this service more deeply to see what other kinds of goodness I can get out of it's API.
Want to use code from this post? Check out the license.