Results 1 to 3 of 3

Thread: Receiving SMS Messages via Shortcodes & Keywords

  1. #1
    Senior Member noonoo1's Avatar
    Join Date
    Jul 2007
    Location
    Wales, UK
    Posts
    3,261

    Default Receiving SMS Messages via Shortcodes & Keywords

    Receiving SMS Messages via Shortcodes & Keywords

    Back around 1998, more and more billboards started to display some odd messages, along the lines of "Visit us on the web at www.companyname.com". This was a major shift in advertising and gave marketers another avenue to explore. It was, of course, the beginning of the Internet's move from academia to the mainstream, and the proliferation of Web sites seemed to happen almost overnight.

    Here in 2010, we're now back in 1998 territory. This time it's the mobile Web that has everybody excited. The thought of potential customers being able to access services from anywhere - and not just in front of a PC - has marketers drooling. SMS plays an important role. On billboards ads, one is very likely to see something like "text companyname to 81707 for more information". This is a shortcode/keyword combination. By texting the specified keyword (companyname in the example above) to the specified shortcode (81707 in the example), a mobile system can perform some type of action, defined by the company offering the keyword/shortcode. This may be as simple as sending a "Thanks for contacting us, we'll be in touch" message back to the user, or beginning some kind of workflow process. Or, as in our example above, the user may receive a text message back containing a URL to a mobile Web site.

    But just how do developers go about setting up keyword/shortcodes? And how do they process incoming messages to those keyword/shortcodes? Let's take a look at how to do this. We'll build upon the system we've built in previous articles that allows us to send SMS messages and to process delivery receipts. We'll build on the basic message processing system we built in the delivery receipts article. Remember we're using SQL Server and Visual Studio (C#) to build our system.

    Obtaining a Keyword/Shortcode
    In the Sending SMS Messages article, we talked about ways of sending SMS messages, and demonstrated how to do this using an aggregator called iTagg. We also need to use an aggregator to set up keyword/shortcodes. You have two options here:

    Purchase a dedicated shortcode This is the expensive option. Expect to pay several thousand pounds for a dedicated shortcode. ITV, for example, has the dedicated shortcode 63330. This means ITV can set up any keyword they like on this shortcode; no other company has access to it. It is purely for ITV's exclusive use.
    Purchase a keyword on a shared shortcode This is what most companies use. An aggregator provides a shared shortcode (so called because several companies use keywords on the same shortcode), and the aggregator's clients purchase keywords to use on it. iTagg own the shared shortcode 60300. So client 1 may purchase the keyword mobile. If client 2 comes along and also wants the keyword mobile, they cannot have it as it has already been assigned. Client 2 would have to select an alternative keyword.
    The costs of purchasing a keyword/shortcode vary from aggregator to aggregator. You can expect to pay a monthly or annual fee for the use of the platform and a monthly rental fee for the keyword/shortcode. Some aggregators allow you to pay a fee and have a certain number of keywords - contact the aggregators to determine what price point works best for you.

    One last important point - make sure you choose your aggregator carefully. Once you've chosen an aggregator any advertising of your keyword/shortcode will be showing the shared shortcode used by the aggregator - effectively locking you in. I strongly recommend you run some tests with the aggregators you're interested in before making a final decision.

    Configuring a Keyword/Shortcode
    Once you have a keyword/shortcode, how do you set it up? It's pretty easy. You give the aggregator a Web address, and the aggregator forwards any inbound messages they receive on your keyword/shortcode to the specified Web address. Depending upon the aggregator, there are two ways you can provide the Web address:

    Provide the Web address to the aggregator's support team, who will then configure it for you (this is the only method of configuration for certain aggregators)
    Log on to the aggregator's control panel and change the URL yourself
    The second option is much preferred, as it gives you the ability to quickly change the URL yourself. The first option puts a reliance on the aggregator's support team.

    Here's the iTagg control panel, listing available keywords:



    Figure 1 iTagg Control Panel

    Clicking on the keyword allows you to configure details for the keyword/shortcode. There are a number of options - you can choose to forward messages on to a URL, and/or to an e-mail address. Clicking on the E-mail/URL Forwarder option displays a screen allowing you to configure the relevant pieces of information:



    Figure 2 Configuring Keyword URL

    Once you've configured these pieces of information, you're ready to receive inbound SMS messages - as long as you have a system present to process them, of course. Let's build that system after we've looked at how iTagg send inbound messages to us.

    iTagg Inbound Messages
    iTagg send all inbound SMS message requests over HTTP POST. Here are the parameters iTagg send to our Web listener page:

    Source This is the mobile number the message was sent from. So if you sent the message from your mobile number, the value for this field would be your mobile number
    Dest The shortcode the message was delivered to, e.g. 60300
    Dtime The delivery time of the message from the mobile network - in the format YYYYMMDDHHMM.
    Message The message body received
    Network The network the source mobile number uses. This is passed as a code:
    10 - O2
    15 - Vodafone
    20 - 3
    30 - T-Mobile/Virgin
    33 - Orange
    99 - Other
    Different aggregators use different codes

    Message_id The unique identifier assigned to the message by the aggregator
    Message_after_match Message_after_match contains the body of the message sent after the keyword has been matched
    Matched_keyword This is the keyword that was matched. This can be used to quickly match up keywords in multi-keyword systems
    Matched_subkeyword This is usually blank. iTagg allows keywords to be set up as sub-keywords (e.g. "example" could be extended with sub-keywords 1, 2 - so the user would send "example1" and "example2"
    Note that these parameters are specific to iTagg - they will differ for each individual aggregator. For example, Tanla pass the following parameters:

    ServiceID (Tanla service number)
    MOID (aggregator ID)
    Operator ID (denotes which network the sender uses)
    Date (date/time the message was received)
    From (the mobile number the message was sent from)
    To (the shortcode the message was sent to)
    Message (the message body)
    It's important to look at the API documents for the aggregator you're planning to use (iTagg's API documents can be found at their Web site). Using iTagg, let's enhance our existing system to process inbound messages.

    Building the Database
    Here's the SQL Server database script from the delivery receipts article, with one minor alteration:

    USE master

    -- Delete the database if it already exists
    IF EXISTS(SELECT [name] FROM sys.DATABASES
    WHERE [name] = 'MobiforgeMessageDemo')
    BEGIN
    DROP DATABASE MobiforgeMessageDemo
    END

    GO

    -- Create the database
    CREATE DATABASE MobiforgeMessageDemo

    GO

    USE MobiforgeMessageDemo

    -- Add the Messages table
    CREATE TABLE [Messages]
    (
    AggregatorMessageID VARCHAR(40),
    InboundMessage BIT,
    Originator VARCHAR(12),
    Recipient VARCHAR(12),
    MessageDate DATETIME DEFAULT GETDATE(),
    MessageBody VARCHAR(160),
    MessageDelivered BIT DEFAULT 0
    )

    GO

    -- Stored procedure to insert a message
    -- Amended to accept an optional Message Date
    CREATE PROCEDURE usp_InsertMessage
    @AggregatorMessageID VARCHAR(40),
    @InboundMessage BIT,
    @Originator VARCHAR(12),
    @Recipient VARCHAR(12),
    @MessageBody VARCHAR(160),
    @MessageDate DATETIME = NULL
    AS
    BEGIN

    SET NOCOUNT ON

    IF (@MessageDate IS NULL)
    BEGIN
    INSERT INTO [Messages]
    (AggregatorMessageID, InboundMessage, Originator,
    Recipient, MessageBody)
    VALUES
    (@AggregatorMessageID, @InboundMessage, @Originator,
    @Recipient, @MessageBody)
    END
    ELSE
    BEGIN
    INSERT INTO [Messages]
    (AggregatorMessageID, InboundMessage, Originator,
    Recipient, MessageBody, MessageDate)
    VALUES
    (@AggregatorMessageID, @InboundMessage, @Originator,
    @Recipient, @MessageBody, @MessageDate)
    END

    SET NOCOUNT OFF

    END

    GO

    -- Stored procedure to update a message's delivery status
    CREATE PROCEDURE usp_MarkMessageAsDelivered
    @AggregatorMessageID VARCHAR(40)
    AS
    BEGIN

    SET NOCOUNT ON

    -- iTagg pass message IDs with a -3 when sending messages,
    -- but do not pass the -3 in delivery receipts. So we check
    -- if we can find the message first, and if we can't we append
    -- a -3 to the end of the ID
    IF NOT EXISTS (SELECT AggregatorMessageID
    FROM [Messages]
    WHERE AggregatorMessageID = @AggregatorMessageID)
    BEGIN

    SET @AggregatorMessageID += '-3'

    END

    UPDATE [Messages]
    SET MessageDelivered = 1
    WHERE AggregatorMessageID = @AggregatorMessageID

    END
    We've made one change to this script - in the usp_InsertMessage stored procedure. We've added an optional @MessageDate parameter. If this is passed we insert the date into the table; otherwise we use the current date/time.

    Amending the Listener Web Page
    When we added the ability to process delivery receipts to our simple messaging system, we introduced a listener Web page. We configured this in the iTagg control panel. We'll now amend the listener to detect whether a delivery receipt or inbound message has been received, and we'll process it accordingly.

    Here's the original code:

    protected void Page_Load(object sender, EventArgs e)
    {
    try
    {
    // Check if some POST data was passed
    if (Request.InputStream != null)
    {
    StreamReader sr = new StreamReader(Request.InputStream);

    // Convert the POST stream to a string
    // We remove the xml= tag at the front, otherwise the XML will not parse
    string inputStream = sr.ReadToEnd().Replace("xml=", string.Empty);

    // Create a delivery receipt
    iTaggDeliveryRecipt dr = new iTaggDeliveryRecipt(inputStream);

    // Write out the delivery receipt details to the trace
    Trace.Write("iTagg DR data: " + inputStream);

    Trace.Write("DR submission ref: " + dr.SubmissionRef);
    Trace.Write("DR status: " + dr.Status);

    // Only process if the status is "delivered"
    if (dr.Status == "Delivered")
    {
    // Try and update the database
    SqlConnection conn = new SqlConnection(
    "Data Source=DEVSQL;Initial Catalog=MobiforgeMessageDemo;Integrated
    Security=true");

    SqlCommand cmd = new SqlCommand("usp_MarkMessageAsDelivered", conn);
    cmd.CommandType = CommandType.StoredProcedure;

    // Make sure we set the aggregator message ID
    cmd.Parameters.Add(new SqlParameter("@AggregatorMessageID",
    dr.SubmissionRef));

    conn.Open();
    cmd.ExecuteNonQuery();
    conn.Close();

    // Show we updated the database in the trace
    Trace.Write("Successfully updated database.");
    }

    // A different status has been received, so we output a message to show
    // this
    else
    {
    Response.Write("Message was not delivered. Status: " + dr.Status +
    "<BR>");
    }

    // Write out a confirmation message at the end
    Response.Write("OK");
    }
    }
    catch (Exception ex) // Output the error details
    {
    Response.Write("Error occurred whilst processing: " + ex.Message);
    Trace.Write("Error occurred whilst processing: " + ex.Message);
    }
    }
    The changes we'll make are:

    Add a class to represent an inbound SMS message
    Add a method to inspect the POST data and determine whether a delivery receipt or inbound SMS message has been received
    Move the delivery receipt processing into a separate method
    Add a method to process an inbound SMS message
    Change the Page_Load event to call the appropriate methods and process inbound requests
    The Inbound SMS Message Class
    The inbound SMS message class does nothing more than parse the inbound data from iTagg and convert it to properties on the class. This makes it easier for us to insert the message into the database.

    using System;
    using System.Collections.Generic;
    using System.Web;

    /// <summary>
    /// Summary description for InboundSmsMessage
    /// </summary>
    public class InboundSmsMessage
    {
    private string _aggregatorMessageID = string.Empty; //The aggregator message ID
    private string _originator = string.Empty; // The message originator
    private string _recipient = string.Empty; // The message recipient
    private DateTime _messageDate = DateTime.MinValue; // Date/time the message was received
    private string _messageBody = string.Empty; // The message body

    // Public accessors
    public string AggregatorMessageID
    {
    get { return _aggregatorMessageID; }
    set { _aggregatorMessageID = value; }
    }

    public string Originator
    {
    get { return _originator; }
    set { _originator = value; }
    }

    public string Recipient
    {
    get { return _recipient; }
    set { _recipient = value; }
    }

    public DateTime MessageDate
    {
    get { return _messageDate; }
    set { _messageDate = value; }
    }

    public string MessageBody
    {
    get { return _messageBody; }
    set { _messageBody = value; }
    }

    /// <summary>
    /// Accepts Input Stream parameter as a string and populates class properties
    /// </summary>
    /// <param name="InputStream"></param>
    public InboundSmsMessage(string InputStream)
    {
    // Obtain the parameter values by splitting on the ampersand
    string[] parameters = InputStream.Split(new char[] { '&' });

    // And now we can loop around the parameters and process each value
    // Note that we don't process every value iTagg send to us as we don't need them all
    for (int i = 0; i < parameters.Length; i++)
    {
    // Separate parameter name and value
    string[] parameterValues = parameters[i].Split(new char[] { '=' });

    // Should have two values
    if (parameterValues.Length == 2)
    {
    // Assign the value to the appropriate class property
    switch (parameterValues[0])
    {
    case "source":
    _originator = parameterValues[1];
    break;

    case "dest":
    _recipient = parameterValues[1];
    break;

    case "dtime":
    // Length should be 12
    // 4 digits for YYYY
    // 2 digits for MM
    // 2 digits for DD
    // 2 digits for HH
    // 2 digits for MM
    if (parameterValues[1].Length == 12)
    {
    int year = Convert.ToInt32(parameterValues[1].Substring(0, 4));
    int month = Convert.ToInt32(parameterValues[1].Substring(4, 2));
    int day = Convert.ToInt32(parameterValues[1].Substring(6, 2));
    int hour = Convert.ToInt32(parameterValues[1].Substring(8, 2));
    int minute = Convert.ToInt32(parameterValues[1].Substring(10, 2));

    DateTime dateToProcess = new DateTime(year, month, day, hour, minute, 0);
    _messageDate = dateToProcess;
    }
    break;

    case "message":
    _messageBody = parameterValues[1];
    break;

    case "message_id":
    _aggregatorMessageID = parameterValues[1];
    break;
    }
    }
    }
    }
    }
    There's not much to say about this code; it's self-explanatory. In the real world we'd add try/catch blocks, constants for literal values, and better processing around dates.

    POST Data Processing Method
    The method to check if the POST data returns a Boolean - true if we're processing a delivery receipt, false if we're processing an inbound SMS message.

    /// <summary>
    /// Determines whether we should process a delivery receipt or an inbound SMS message
    /// </summary>
    /// <param name="inputStream">The data to check</param>
    /// <returns></returns>
    private bool deliveryReceiptReceived(string inputStream)
    {
    // Assume we're processing an inbound SMS message
    bool deliveryReceiptReceived = false;

    // If the input stream contains a delivery receipt XML element,
    // return delivery receipt
    if (inputStream.Contains("itagg_delivery_receipt"))
    {
    deliveryReceiptReceived = true;
    }

    return deliveryReceiptReceived;
    }
    We perform a simple check for a delivery receipt value, and if we find that value we know we're processing a delivery receipt.

    Move Delivery Receipt Processing Into a Separate Method
    We now move the coding to process a delivery receipt from the Page_Load event into a separate method called, originally enough, processDeliveryReceipt.

    /// <summary>
    /// Process the inbound delivery receipt and add it to the database
    /// </summary>
    /// <param name="inputStream"></param>
    private void processDeliveryReceipt(string inputStream)
    {
    // Create a delivery receipt
    iTaggDeliveryRecipt dr =
    new iTaggDeliveryRecipt(inputStream);

    // Write out the delivery receipt details to the trace
    Trace.Write("iTagg DR data: " + inputStream);

    Trace.Write("DR submission ref: " + dr.SubmissionRef);
    Trace.Write("DR status: " + dr.Status);

    // Only process if the status is "delivered"
    if (dr.Status == "Delivered")
    {
    // Try and update the database
    SqlConnection conn = new SqlConnection(
    "Data Source=DEVSQL;Initial Catalog=MobiforgeMessageDemo;Integrated Security=true");

    SqlCommand cmd = new SqlCommand("usp_MarkMessageAsDelivered", conn);
    cmd.CommandType = CommandType.StoredProcedure;

    // Make sure we set the aggregator message ID
    cmd.Parameters.Add(new SqlParameter("@AggregatorMessageID", dr.SubmissionRef));

    conn.Open();
    cmd.ExecuteNonQuery();
    conn.Close();

    // Show we updated the database in the trace
    Trace.Write("Successfully updated database.");
    }
    else // A different status has been received, so we output a message to show this
    {
    Response.Write("Message was not delivered. Status: " + dr.Status + "<BR>");
    }

    // Write out a confirmation message at the end
    Response.Write("OK");
    }
    This method creates a delivery receipt object and inserts it into the database.

    Add a Method to Process an Inbound SMS Message
    Our penultimate step sees us write a similar method to that above, but to process an inbound SMS message.

    /// <summary>
    /// Processes an inbound SMS message and adds it to the database
    /// </summary>
    /// <param name="inputStream"></param>
    private void processInboundSmsMessage(string inputStream)
    {
    // Create an inbound SMS message
    InboundSmsMessage message = new InboundSmsMessage(inputStream);

    // Write out the SMS details to the trace
    Trace.Write("iTagg SMS data: " + inputStream);

    // Only process if we have valid data
    if (message.AggregatorMessageID != string.Empty)
    {
    SqlConnection conn = new SqlConnection(
    "Data Source=DEVSQL;Initial Catalog=MobiforgeMessageDemo;Integrated Security=true");

    SqlCommand cmd = new SqlCommand("usp_InsertMessage", conn);
    cmd.CommandType = CommandType.StoredProcedure;

    // Set the parameters
    cmd.Parameters.Add(new SqlParameter("@AggregatorMessageID", message.AggregatorMessageID));
    cmd.Parameters.Add(new SqlParameter("@InboundMessage", true));
    cmd.Parameters.Add(new SqlParameter("@Originator", message.Originator));
    cmd.Parameters.Add(new SqlParameter("@Recipient", message.Recipient));
    cmd.Parameters.Add(new SqlParameter("@MessageBody", message.MessageBody));
    cmd.Parameters.Add(new SqlParameter("@MessageDate", message.MessageDate));

    conn.Open();
    cmd.ExecuteNonQuery();
    conn.Close();

    // Show we updated the database in the trace
    Trace.Write("Successfully updated database.");
    }

    // Write out a confirmation message at the end
    Response.Write("OK");
    }
    The InboundSmsMessage class takes care of parsing the input stream; once we have these values we write it to the database.

    If we were following strict OOP guidelines we'd have put the database code in a method on the InboundSmsMessage class called Update(). We'd also have added a similar method to the Delivery Receipt class.

    The Page_Load Event
    All that's left to do now is rewrite the Page_Load event to call the methods we've written.

    protected void Page_Load(object sender, EventArgs e)
    {
    try
    {
    // Check if some POST data was passed
    if (Request.InputStream != null)
    {
    StreamReader sr = new StreamReader(Request.InputStream);

    // Convert the POST stream to a string
    // We remove the xml= tag at the front, otherwise the XML will not parse
    // NOTE - "xml" is only passed if we receive a delivery receipt
    string inputStream = sr.ReadToEnd().Replace("xml=", string.Empty);

    if (deliveryReceiptReceived(inputStream))
    {
    processDeliveryReceipt(inputStream);
    }
    else
    {
    processInboundSmsMessage(inputStream);
    }
    }
    }
    catch (Exception ex) // Output the error details
    {
    Response.Write("Error occurred whilst processing: " +
    ex.Message);
    Trace.Write("Error occurred whilst processing: " +
    ex.Message);
    }
    }
    This method has been greatly simplified. The first part remains the same - we convert the input stream to a string. After that, we check if we've received a delivery receipt and process accordingly.

    We're now ready to try it out!

    Putting It All Together
    Publish the listener to IIS and make sure you can access it through your Web browser. Once you're happy visit iTagg (or your selected aggregator) and set up the URL as the inbound message path by either configuring it in the aggregator control panel, or contacting aggregator support.

    Then try sending in a message. A typical message may look like:



    Figure 3 About to send a message

    Send this message, and after a few seconds it should appear in the Messages database table.



    Figure 4 The updated Messages table

    Summary
    It's not difficult to process inbound SMS messages - in fact, it's quite similar to sending an inbound message. Once you have a simple database configured, it's pretty easy to process the messages and insert them into the database. The main thing to consider is your choice of aggregator - as you'll be tied in to their shortcode it's vital you make the correct choice.

    Our example system has some limitations. Firstly, we don't actually do anything with the inbound message. A further article will show how to do this. Secondly, what we've developed can only support one keyword/shortcode. Say we have keyword1 on 60300 and keyword2 on 60300, and we wanted different messages to be sent back depending upon which keyword/shortcode was used. We'd need to add a Keywords table to the database and link this to the Messages table. We could then amend our stored procedures accordingly and change our class library and listener Web page over to process messages from different keywords. We'll also look at how to do this in a future article.


    RELATED

    CONTENT:
    Handling SMS delivery receipts
    Sending SMS from Apps and Webapps
    Sending SMS with SMPP, Kannel and Java
    SMS Messaging in Android
    One web 2.0 - social edition
    TAGS:
    Developing Developers Messaging C# SMS
    POSTED BY MOKIL 7 HOURS 1 MIN AGO


    Mike McQuillan began developing software professionally after graduating from university with a 1st class Honours degree in Computer Studies in 1999. Since then he has worked for small companies (five employees) and large PLCs, such as Experian. He has developed just about every type of software there is – Windows client/server, Web systems, services, Unix systems, and now mobile systems. He is the Technical Director at m-send, a mobile software development company. He leads the technical direction of the company, covering all areas of mobile development.
    He's been working on mobile since 2006 and has built up a comprehensive knowledge of what works and what doesn’t, especially on the mobile Web. He mainly concentrates on using .NET but can turn his hand to other languages such as Java and C++.
    "Mobile is a great industry to work in – especially at the moment, as we’re essentially the pioneers leading the way – much as others did with the desktop Internet in the 1990s. The fun starts here..."

    Picked up from http://mobiforge.com/developing/stor...codes-keywords
    ENOUGH SAID


    Mobile Web Search, forget google, bookmark... JUST.mobi

    Snowboards.mobi | Convert2.mobi | Caravans for Sale | VOTES.mobi

  2. #2
    Senior Member
    Join Date
    Aug 2007
    Location
    United Kingdom
    Posts
    3,615

    Default

    Several £1,000's for a dedicated shortcode - (ouch!), I'd never have thought it? I guess by their nature (being "short"codes) that there are only so many to go round..... I've not been a fan of shortcodes as they don't seem to cut out much of the 'hassle' of just using a url or a phone number.... but I'm slowing coming around to a rethink ;-)

  3. #3
    Senior Member ChinaMobi's Avatar
    Join Date
    May 2010
    Posts
    1,593

    Default

    I think 2D code scanning to display your website is promising.

Similar Threads

  1. Shortcodes.net
    By seanboy in forum Non-.mobi's
    Replies: 11
    Last Post: 10-05-2010, 09:10 PM
  2. Replies: 0
    Last Post: 01-05-2010, 01:10 PM
  3. Domains for Sale, many receiving hits at Sedo
    By developmy.mobi in forum .mobi's For Sale - Fixed Prices
    Replies: 5
    Last Post: 11-18-2009, 12:35 PM
  4. ShortCodes.net
    By seanboy in forum Non-.mobi's
    Replies: 1
    Last Post: 12-30-2008, 02:53 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
A Yup.mobi Mobile Site
Mobile Dating