Latest Tweet:
  • Loading...

One of the cool, but perhaps overlooked features, of Outlook 2007 is the integration of mobile messaging. Today many mobile providers offers some kind of plug-in to Outlook enabling their customers to send SMS messages from Outlook. The implementation and user experience differs for each mobile provider. In Outlook 2007 there is a standard way to supports incoming and outgoing SMS and MMS messages directly from Outlook. You simply implement an XML Web Service consisting of three simple methods. There really isn't too much information available on Outlook Mobile Services in the blog sphere, so hopefully this post and webcast will be a welcome addition. In this post you'll learn how to create a Outlook 2007 Mobile Service. I've also created a screen cast that walks you through the development and deployment process.

This post is the third in a series covering free SMS messages using the Ung1881 service. The first post covered how to wrap the service into a .NET library, while the second covered how to use the .NET library from a Vista Sidebar Gadget. In this post I'm going to discuss how to implement an Outlook 2007 Mobile Service that use the same library to send free SMS messages from Outlook 2007!

Using the Ung1881 Free SMS library and Outlook 2007 Mobile Services you can send free SMS messages directly from Outlook 2007

Your Web Service only need to implement three methods, GetServiceInfo, GetUserInfo and SendXms. I've included a simple class diagram showing the methods you need to implement.

The strings passed back and fourth between server and client contains XML data. The XML structure, and Outlook 2007 Mobile Services in general, is well documented in a comprehensive developer guide up on MSDN. Last week I did some e-mailing with the team behind Outlook 2007 Mobile Services, because I couldn't get it to work by following the code samples up on MSDN. I turned out the samples where written for 1.1, and that the SOAP encoder works a little bit different in .NET 2.0. The problem was that Outlook called the service, but the parameters where always null. In the samples they use SoapRpcMethodAttribute on all methods, instead of traditional SOAP message style. But you can just overlook all the attributes and just use the WebMethod attribute as usual. The entire code of the service is fairly short (less than 200 lines) and is included below.

#region Licence agreement
// Copyright (c) 2007, Jonas Follesø
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Jonas Follesø nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY Jonas Follesø "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Jonas Follesø BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

using System;
using System.IO;
using System.Web;
using System.Xml;
using System.Data;
using System.Text;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Security.Authentication;
using System.Collections.Generic;
using System.Web.Services.Description;
using System.ComponentModel;

using Ung1881;

namespace Ung1881OMS
{
    /// <summary>
    /// A WebService implementing the Outlook 2007 Mobile Service interface.
    /// Allows you to send SMS messages from Outlook 2007!
    /// </summary>
    [WebService(Namespace = "http://schemas.microsoft.com/office/Outlook/2006/OMS")]
    [WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]
    public class OMSService : System.Web.Services.WebService, IOutlookMobileService
    {
        /// <summary>
        /// Returns information about the service. The returned XML contains
        /// information about the service, if it supports SMS, MMS or both etc.
        /// See the ServiceInfo.xml for more information about the XML format.
        /// </summary>
        /// <returns></returns>
        [WebMethodAttribute()]
        public string GetServiceInfo()
        {
            return ReadXml("ServiceInfo.xml");
        }

        /// <summary>
        /// Method authenticating a user and geting user information.
        /// Returns an XML string with some basic user information (phone number and e-mail).
        /// </summary>
        /// <param name="xmsUser">An XML string containing the user credentials.</param>
        /// <returns>An XML string with user information.</returns>
        [WebMethodAttribute()]
        public string GetUserInfo(string xmsUser)
        {
            try
            {
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(xmsUser);

                XmlNamespaceManager nmManager = new XmlNamespaceManager(xml.NameTable);
                nmManager.AddNamespace("o", "http://schemas.microsoft.com/office/Outlook/2006/OMS");                
                
                string username = xml.SelectSingleNode("/o:xmsUser/o:userId", nmManager).InnerText;
                string password = xml.SelectSingleNode("/o:xmsUser/o:password", nmManager).InnerText;

                Ung1881Proxy proxy = new Ung1881Proxy();
                proxy.Login(username, password);
                
                return ReadXml("UserInfo.xml");
            }
            catch (Exception)
            {
                StringWriter stringWriter = new StringWriter();
                XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);

                xmlWriter.WriteStartElement("userInfo", "http://schemas.microsoft.com/office/Outlook/2006/OMS");                
                
                xmlWriter.WriteStartElement("error");
                xmlWriter.WriteAttributeString("code", "invalidUser");
                xmlWriter.WriteAttributeString("severity", "failure");
                xmlWriter.WriteEndElement(); 
               
                xmlWriter.WriteEndElement();

                string error = stringWriter.GetStringBuilder().ToString();

                xmlWriter.Close();
                stringWriter.Dispose();

                return error;
            }
        }

        /// <summary>
        /// Method sending an SMS/MMS message to one or more recepients.
        /// </summary>
        /// <param name="xmsData">An XML string with the list of recepients and the content of the message.</param>
        /// <returns>An XML string with a status message.</returns>
        [WebMethodAttribute()]
        public string SendXms(string xmsData)
        {            
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(xmsData);

            XmlNamespaceManager nmManager = new XmlNamespaceManager(xml.NameTable);
            nmManager.AddNamespace("o", "http://schemas.microsoft.com/office/Outlook/2006/OMS");

            string username = xml.SelectSingleNode("/o:xmsData/o:user/o:userId", nmManager).InnerText;
            string password = xml.SelectSingleNode("/o:xmsData/o:user/o:password", nmManager).InnerText;

            try
            {
                List<string> recipients = new List<string>();
                List<string> messages = new List<string>();

                foreach (XmlNode node in xml.SelectNodes("//o:recipient", nmManager))
                {
                    recipients.Add(node.InnerText);
                }

                foreach (XmlNode node in xml.SelectNodes("//o:content[@contentType='text/plain']", nmManager))
                {
                    messages.Add(node.InnerText);
                }

                Ung1881Client client = new Ung1881Client(username, password);

                foreach (string number in recipients)
                {
                    foreach (string message in messages)
                    {
                        client.SendMessage(number, message);
                    }
                }

                return BuildError("ok", false);;
            }
            catch (AuthenticationException)
            {
                return BuildError("invalidUser", true);
            }
            catch (Exception)
            {
                return BuildError("others", true);
            }
        }

        /// <summary>
        /// Simple helper method reading an file from disk and
        /// returning the content as a string.
        /// </summary>
        /// <param name="fileName">The relative path to the file you want to read.</param>
        /// <returns>The file content.</returns>
        private string ReadXml(string fileName)
        {
            StreamReader sr = new StreamReader(Server.MapPath(fileName), Encoding.Unicode);
            string xml = sr.ReadToEnd();
            sr.Dispose();
            return xml;
        }

        /// <summary>
        /// Simple helper method building the return XML for the SendXms method.
        /// </summary>
        /// <param name="errorCode">The error code.</param>
        /// <param name="failed">If this was a failure or not.</param>
        /// <returns>The XML fragment to return to the client.</returns>
        private string BuildError(string errorCode, bool failed)
        {
            StringWriter stringWriter = new StringWriter();
            XmlTextWriter wr = new XmlTextWriter(stringWriter);

            wr.WriteStartDocument();
            wr.WriteStartElement("xmsResponse", "http://schemas.microsoft.com/office/Outlook/2006/OMS");
            wr.WriteStartElement("error");
            wr.WriteAttributeString("code", errorCode);
            wr.WriteAttributeString("severity", failed ? "failure" : "neutral");
            wr.WriteEndElement();
            wr.WriteEndElement();
            wr.WriteEndDocument();

            wr.Close();
            string returnValue = stringWriter.GetStringBuilder().ToString();
            stringWriter.Dispose();
            return returnValue;
        }
    }
}

Once you have your service up and running you can add a new account in Outlook 2007. In the add account wizard, select "other" and "Outlook Mobile Service" as the account type. This will bring up the "Outlook Mobile Service Account" dialog. Here you enter the URL to the service and your user credentials.

 

Once you've created an Outlook Mobile Service account you get a new item in the "New" menu called "New Text Message". This brings up the new message dialog. When you send your message, Outlook will call your service and the SendXms method.

The installation process isn't as easy as I wish it was, since this is a server application you need to configure IIS. Outlook will only connect to HTTPS sites, so you need to create your own certificate as well. The screen cast walks you through this process. Scott Guthrie has a nice post on IIS7 and self signed certificates over at his blog

The next post in this Free SMS series will be an .NET 3.0 application for Windows XP users who don't have the Vista Sidebar available. Stay tuned! Please drop me a comment if you downloaded and installed the service and found it useful, or have any questions regarding Outlook 2007 Mobile Services.
 

<August 2010>
SunMonTueWedThuFriSat
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234