Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Dr.Bob's Delphi Notes Dr.Bob's Delphi Clinics Dr.Bob's Delphi Courseware Manuals
 Dr.Bob Examines... #97
See Also: Dr.Bob's Delphi Papers and Columns

This updated article was first published in the The Delphi Magazine issue #133.

Using Short Message Services in Delphi applications
Short Message Service (better known as SMS) is a popular technique to send a short message from one cell or mobile phone to another. I use it a lot, especially around New Year to send wishes to my friends and familiy members (the ones that I do not see in person that day). Like the internet e-mail technology, the initial use of SMS was highly underrated, and today it's in fact one of the most used aspects of mobile phones.If only the mobile phone keyboard wasn't so tedious to use...
In fact, the use of SMS has grown so much, that for a number of recent projects, I've had the request to add SMS capabilities to the application.Not specifically to allow the user to construct an SMS message and send it to where ever the user wants to, but more as a notification for the back-office.In an e-commerce situation, it could happen that the store runs out of a stock for a particular item.Of course, this can be signalled by some kind of business rule, which should be picked up by the back office.And a notification can also be sent by e-mail.But not everyone checks his or her e-mail every five minutes (not everyone is like me), so the request was to send the notification using an SMS message.Obviously hoping that only a few such situations would arise, and the receiver wouldn't be buried under tons of SMS messages (recognised by connoisseurs as SMS spam).
To cut a long story short, in this article I'll show you how to compose and automatically send SMS messages from all kinds of Delphi applications, from Win32 to ASP.NET web forms.

SMS Gateway
The first task was to find some kind of SMS gateway; a provider that would allow me to contact this service over the internet, and would send the SMS message to a mobile phone.There a number such providers, all offering a somewhat similar service.

Mollie
As first choice, I've selected Mollie in The Netherlands, who have a Dutch website at http://www.mollie.nl (apart from registering and purchasing SMS credits in Dutch, all the technical information you need is in this article).
From Mollie you can purchase SMS credits starting at a price of 13 eurocent per credit (for 100 credits) down to 11 cents for 1000 credits or more, and even as low as 5,5 cent for mega SMS spammers who need 100,000 credits or more.For my own purposes, which will be illustrated shortly, I've purchased 1000 credits for 110 Euro (plus VAT).Credits remain valid for 12 months after purchase.
Note that it's credits and not SMS messages, since mollie actually offers two SMS gateways (a few more described on their website).One is connected to Dutch mobile phone operators, and is the preferred one for my own local application.This one charges 1,2 credit for each SMS message.The other SMS gateway uses a more economic route based on the combination of operator and country to send the SMS message, and costs only 1 credit per SMS message.
My personal experience showed little difference in performance or reliability between the two gateways. For more information, see the Mollie website itself.

KAPOW!
Note that even if you don't want to use the Dutch mollie.nl service, many other SMS gateway service providers offer the same HTTP API interface that I'll cover in the remainder of this article.In the UK, I've found KAPOW! at http://www.kapow.co.uk/ (the first SMS gateway in the UK), providing a similar HTTP API interface.Note that KAPOW! requires a 50 pound fee to modify the “From-id / originator” of your SMS messages to something other than the default kapow.co.uk.When purchasing SMS credits (prices start at 8.5p per credit for 100 credits, down to 5p if you purchase 50.000 credits or more), your first purchase gets you an additional 50 credits for free, so I got a total of 150 credits for 8.50 pound sterling (plus VAT).
KAPOW! offers only one SMS gateway, where one SMS message costs one credit.Credits remain valid for 12 months here as well.
Once you've registered yourself at Mollie or KAPOW! you have a username and password (of your own choice), and you need to use these for each SMS message that you want to send.The code that I've written in this article will need the username and password, being passed as parameters, so the example projects won't really succeed in sending an SMS message until you have your own registration information.
Of course, feel free to search and select your own SMS gateway provider; most will offer a HTTP API that works in a similar way.

Mollie's HTTP API
The easiest way to send an SMS is to send a HTTP request to Mollie.For this, mollie provides the URL http://www.mollie.nl/xml/sms/ which must be followed by field=value combinations for the username, password, originator (the sender's phone number), recipient (a comma separated list of receivers' phone numbers), and the message itself.As optional parameters you can also specify the gateway (by default set to 1), the deliverydate and the type of SMS (which can be set to normal, wappush, vcard, flash, binary or long).A normal text SMS message can be up to 160 characters in size.For a binary SMS message you can also specify the udh header, and for a wappush SMS message you can also specify the URL for the wappush content.These will not be covered here, but it may be good to know that it's possible in case you need it.
As simple example, sending an SMS message “Hello, world!” from my home phone number 3149254xxxx to my mobile phone number +31-6-2820xxxx can be done with the following call, which can be used as single one-line long URL in a browser:

  http://www.mollie.nl/xml/sms/?username=***&password=***
    &originator=3149254xxxx&recipients=3162820xxxx&
    gateway=2&message=Hello, world!
Note that it's important to enter the recipients phone number correctly, especially in the testing phase when the message doesn't seem to arrive at its destination.A simple typo in the recipients phone number made me send the same test message over and over again (to someone else's phone I'm afraid).
The result of the call to the Mollie SMS Gateway is an XML document, which can contain either a success or an error message, for example as shown in the listing below, which is the result of using an incorrect phone number for the recipients field.
  <?xml version="1.0"?>
  <response>
    <item type="sms">
      <recipients>0</recipients>
      <success>false</success>
      <resultcode>25</resultcode>
      <resultmessage>No correct recipients found.</resultmessage>
    <item>
  </response>
A success message obviously has the value true inside the success field, resultcode 10 and resultmessage containing “Message successfully sent.”, plus the actual number of recipients in the recipients field (which can be more than one, since you can list multiple recipients separated by commas).

KAPOW!'s HTTP API
Using KAPOW! there is a similar HTTP API available, using a sendsms.php script.The base URL is http://www.kapow.co.uk/scripts/sendsms.php and we again need to pass the username and password fields (similar to the Mollie HTTP API).
By default KAPOW! uses the From-id or originator that belongs to the username / password combination which by default is set to kapow.co.uk unless you pay the 50 pound to set it to something else.Once you've paid this 50 pounds, you can also pass a from_id field in the HTTP request with your name or phone number.The recipient using KAPOW!'s HTTP API is specified using the mobile field, and the message itself is passed in the sms field.
Repeating the previous example, this time using the KAPOW!'s gateway, results in the following single one-line long URL in a browser:

  http://www.kapow.co.uk/scripts/sendsms.php?username=***&password=***
    &mobile=3162820xxxx&sms=Hello, world!
The response from the KAPOW!'s HTTP API is a single string, which can be: OK, USERPASS (in case of an incorrect username/password combination), NOCREDIT or ERROR.The OK string is followed by the number of credits left, or the string CREDIT if no more credits are left.

SMS in Win32 using WININET
Now that the details of the HTTP request are known, it's time to write some code to make this request (and get the appropriate response).In the Win32 world, apart from using Indy, one of the easiest ways to make a HTTP request is to use WinINET and open a URL, reading the response as a file.Using WinINET (available through the WinINET unit), we first have to open an internet connection using the InternetOpen call, an then can use the InternetOpenURL to send the HTTP request to.With a call to InternetReadFile we get the response, which in the case of the SMS gateway service consists of an XML file with either a success confirmation or an error message if the SMS request failed.The URL and internet connection then need to be closed in the clean-up section.
The following code listing shows a unit Mollie that contains a stand-alone function SendSMS which takes the Username, Password, Originator, Recipients and Message string parameters, implementing the WinINET solution just outlined.

  unit Mollie;
  interface

    function SendSMS(const Username, Password, Originator, Recipients,
      Message: String; Gateway: integer = 1): String;

  implementation
  uses
    SysUtils, WinINET, HttpAPP;

    function SendSMS(const Username, Password, Originator, Recipients,
      Message: String; Gateway: integer = 1): String;
    const
      URL = 'http://www.mollie.nl/xml/sms/?username=%s&password=%' +
            's&originator=%s&recipients=%s&gateway=%d&message=%s';
      ResponseSize = 1024;
    var
      hSession, hURL: HInternet;
      Request: String;
      ResponseLength: Cardinal;
    begin
      hSession := InternetOpen('DrBob42', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
      try
        Request := Format(URL,[Username,Password,Originator,Recipients,Gateway,HttpEncode(Message)]);
        hURL := InternetOpenURL(hSession, PChar(Request), nil, 0,0,0);
        try
          SetLength(Result, ResponseSize);
          InternetReadFile(hURL, PChar(Result), ResponseSize,
            ResponseLength);
          SetLength(Result, ResponseLength)
        finally
          InternetCloseHandle(hURL)
        end
      finally
        InternetCloseHandle(hSession)
      end
    end;

  end.
Note that the Gateway is passed as default argument, using gateway 1 by default. You may want to use the somewhat cheaper second gateway for your own SMS sending purposes.
The following code listing contains the unit KAPOW which also defines and implements the function SendSMS.Note that this function has no default parameter for the gateway, but defines a default parameter for the originator instead.
  unit KAPOW;
  interface

    function SendSMS(const Username, Password, Recipients, Message: String;
      const Originator: String = ''): String;

  implementation
  uses
    SysUtils, WinINET, HttpApp;

    function SendSMS(const Username, Password, Recipients, Message: String;
      const Originator: String = ''): String;
    const
      URL = 'http://www.kapow.co.uk/scripts/sendsms.php?username=%s'+
        '&password=%s&mobile=%s&sms=%s';
      ResponseSize = 1024;
    var
      hSession, hURL: HInternet;
      Request: String;
      ResponseLength: Cardinal;
    begin
      hSession := InternetOpen('DrBob42', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
      try
        Request := Format(URL,[Username,Password,Recipients, HttpEncode(Message)]);
        if Originator <> '' then
          Request := Request + '&from_id=' + Originator;
        hURL := InternetOpenURL(hSession, PChar(Request), nil, 0,0,0);
        try
          SetLength(Result, ResponseSize);
          InternetReadFile(hURL, PChar(Result), ResponseSize, ResponseLength);
          SetLength(Result, ResponseLength)
        finally
          InternetCloseHandle(hURL)
        end
      finally
        InternetCloseHandle(hSession)
      end
    end;

  end.
If you use another SMS Gateway, then it's likely you will have to write your own version of the SendSMS function based on these two examples.
I've used the Win32 units to write a simple application that will allow the user to click on images representing family members, then writing a simple message in the editbox and clicking on the button to send the SMS message.This avoids people from having to enter a phone number (and it also allows people without a mobile phone of their own to send an SMS message to friends and relatives).Figure 1 gives an impression offering the choice between myself, my wife and two kids, being used in the summer holiday season by my mother among others.

Clicking on an image will load the colour photo (instead of the black-and-white one), and will remember in a field called Recipient which image is now the active one. The actual sending of the SMS message is done with just one call to SendSMS, using an array of mobile phone numbers, as shown in the following code listing:

  procedure TForm1.btnSMSClick(Sender: TObject);
  // Recipient contains the number of the active image, range 1..4
  const
    Mobile: Array[1..4] of String =
      ('3162820xxxx', '3164867xxxx', '3164985xxxx', '3164867xxxx');
  begin
    Mollie.SendSMS('username', 'password', '31649254xxxx', Mobile[Recipient], edtMessage.Text)
  end;
Note that in this listing I'm passing “username” and “password” as the fake username and password, and I've also “protected” the mobile phone numbers by leaving the last four digits out.

Unicode Update
The source code for the units for Mollie and Kapow were written using a pre-Unicode version of Delphi. In Delphi 2009 and higher, a String is a Unicode String, consisting of WideChar characters. As a result, the code would no longer compile or work without some minor changes.
The InternetReadFile method no longer uses a PChar type for its second argument, but a PAnsiChar type. As a result, the SendSMS function itself returns an AnsiString and not a (Unicode) String. Including a few casts, the new code, which compiles with Delphi 7 and above (I haven't tested older versions of Delphi), is as follows:

  unit Mollie;
  interface

    function SendSMS(const Username, Password, Originator, Recipients,
      Message: String; Gateway: integer = 1): AnsiString;

  implementation
  uses
    SysUtils, WinINET, HttpApp;

    function SendSMS(const Username, Password, Originator, Recipients,
      Message: String; Gateway: integer = 1): AnsiString;
    const
      URL = 'http://www.mollie.nl/xml/sms/?username=%s&password=%s' +
            '&originator=%s&recipients=%s&gateway=%d&message=%s';
      ResponseSize = 1024;
    var
      hSession, hURL: HInternet;
      Request: String;
      ResponseLength: Cardinal;
    begin
      hSession := InternetOpen('DrBob42', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
      try
        Request := Format(URL,[Username,Password,Originator,Recipients,Gateway,
          HttpEncode(Message)]);
        hURL := InternetOpenURL(hSession, PChar(Request), nil, 0,0,0);
        try
          SetLength(Result, ResponseSize);
          InternetReadFile(hURL, PAnsiChar(Result), ResponseSize, ResponseLength);
          SetLength(Result, ResponseLength)
        finally
          InternetCloseHandle(hURL)
        end
      finally
        InternetCloseHandle(hSession)
      end
    end;

  end.

And this modified unit (you can download the new source code here) is still used today even with Delphi XE and higher.

Sending SMS from .NET
Apart from sending SMS messages from Win32 VCL application, I also had a real business need to be able to integrate the capability of sending SMS messages from commercial ASP.NET web applications.
To produce a 10% pure safe and managed solution in the .NET world (especially for ASP.NET applications), we have to play a different ballgame.WinINET is not a safe and managed technology, and although we could perhaps use Indy for .NET, I'm always more inclined to use a solution which is natively available.When using the facilities from the .NET Framework, we can use HttpWebRequest and HttpWebResponse classes (found in the System.NET namespace) to construct our code.
The following code listing contains the native .NET implementation for Mollie's SendSMS function, which can be called from a WinForms, VCL for .NET or ASP.NET web application.

  unit Mollie.NET;
  interface

    function SendSMS(const Username, Password, Originator, Recipients,
      Message: String; Gateway: integer = 1): String;

  implementation
  uses
    System.NET, System.IO;

    function SendSMS(const Username, Password, Originator, Recipients,
      Message: String; Gateway: integer = 1): String;
    var
      Req: HttpWebRequest;
      Res: HttpWebResponse;
      ResStream: Stream;
      Reader: StreamReader;
      U: URI;
    begin
      U := URI.Create('http://www.mollie.nl/xml/sms/?' +
        'username=' + Username + '&password=' + Password +
        '&originator=' + Originator + '&recipients=' + Recipients +
        '&gateway=' + Gateway.ToString +
        '&message=' + Message, False);
      Req := HttpWebRequest.CreateDefault(U) as HttpWebRequest;
      Req.Method := 'GET';
      Res := Req.GetResponse as HttpWebResponse;
      ResStream := Res.GetResponseStream;
      Reader := StreamReader.Create(ResStream);
      Result := Reader.ReadToEnd;
      Reader.Close
    end;

  end.
Note that we cannot directly create an instance of the HttpWebRequest class, but we have to use the CreateDefault factory method instead. The same thing applies to the HttpWebResponse, which cannot be created by itself, but is the returned result of the GetResponse method of the HttpWebRequest.
Apart from using the HttpWebRequest and HttpWebResponse methods, we can also use the WebClient class, creating an instance and calling the DownloadData method while passing the URL with the SMS request.For the Mollie SMS gateway, this would result in a single line, creating the WebClient instance and calling the DownloadData method, finally casting the result to a String, as shown in the next code listing.
    Result := String(
      WebClient.Create.DownloadData('http://www.mollie.nl/xml/sms/?' +
        'username=' + Username + '&password=' + Password +
        '&originator=' + Originator + '&recipients=' + Recipients +
        '&gateway=' + Gateway.ToString +
        '&message=' + Message));
Finally, the last code listing contains the SendSMS function for .NET using the KAPOW! SMS gateway, using the WebClient code as well.
  unit KAPOW.NET;
  interface

    function SendSMS(const Username, Password, Recipients, Message: String;
      const Originator: String = ''): String;

  implementation
  uses
    System.NET;

    function SendSMS(const Username, Password, Recipients, Message: String;
      const Originator: String = ''): String;
    begin
      if Originator <> '' then
        Result := String(
          WebClient.Create.
            DownloadData(' http://www.kapow.co.uk/scripts/sendsms.php?' +
              'username=' + Username + '&password=' + Password +
              '&from_id=' + Originator + '&mobile=' + Recipients +
              '&sms=' + Message))
      else
        Result := String(
          WebClient.Create.
            DownloadData(' http://www.kapow.co.uk/scripts/sendsms.php?' +
              'username=' + Username + '&password=' + Password +
              '&mobile=' + Recipients + '&sms=' + Message));
    end;

  end.
Note that we don't have to close or free the WebClient instance, that will be taken care of by the .NET Garbage Collector.
The Mollie.NET and KAPOW.NET units can be used in VCL for .NET, WinForms as well as ASP.NET web applications, and I've successfully implemented SMS notifications in a number of real-world ASP.NET web applications using this technique (including the on-line Delphi Courseware store).

Summary
Sending SMS messages isn't limited to mobile phones, but can also be done from VCL or .NET Delphi applications, offering a new way to alert the (back) office to certain situations, or just sharing news with your friends and relatives without using the mobile keyboard to enter your message.The HTTP API is easy to use, and can be called from a Win32 client using WININET, and from a .NET client using a HttpWebRequest class from the System.NET namespace.
If you decide to use another SMS gateway (other than Mollie or KAPOW) you can write your own HTTP API using unit with the examples provided in this article.You can download the source code from the Mobile Moves page on my website. If you have any questions or comments, feel free to contact me.


This webpage © 2008-2010 by Bob Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.