Short Message Peer-to-Peer (SMPP) is a protocol used by the telecommunications industry for exchanging
messages between Short Message Service Centers (SMSC) and/or External Short Messaging Entities (ESME).
Introduction
In this post I will build a simple app that will send SMS using the SMPP protocol, bootstraped with Spring
Boot. I will use the Cloudhopper SMPP library for sending SMS. For
the Camel Component example, refer to this Camel Post.
SMPP is a level-7 TCP/IP protocol, which allows fast delivery of SMS messages. The most conmmonly used
versions of SMPP are v3.3, the most widely supported standard, and v3.4, which adds transceiver support
(single connections that can send and receive messages).
Create a simple Spring Boot Application using any of the bootstrap options.
Add the following to your pom.xml after creating your Spring-Boot application:
Configuring the SMPP Session
In order to start using SMPP to send messages, you need to establish a session. The session is usually
short-lived; we will implement long-lived sessions later in this post by extending the session
periodically.
To bind a session, we need a SmppSessionConfiguration and SmppClient. The SmppSessionConfiguration
class contains the configurable aspects of the SmppSession. In this class you can configure the:
Host: [smpp.serviceprovider.com]
Port: default 2775
System Id: [username]
Password: [password]
BindType: TRANSCEIVER, TRANSMITTER or RECEIVER
Version: 3.3, 3.4, 5.0
Configuring this class will look something like the following:
NOTE: Be sure to replace the values for Host, SystemId and Password.
I have set the bind-type as TRANSCEIVER because I want to be able to send SMS and receive delivery
receipts.
What I have to do next is create the SmppClient:
The DefaultSmppClient constructor takes an ExecutorService and expected number of sessions. In the
example above I am creating a CachedThreadPoolExecutor and assigning 2 concurrent sessions.
With these two in place I can now establish my SmppSession:
In the above snippet, we are using a DefaultSmppSessionHandler. Later in this post I will create a
custom SmppSessionListener that can handle delivery receipts.
At this point all necessary configuration is done. Everything wired up together until this point should
look like this:
Add your phone number to destinationAddress and run the application. Remember to use the international
phone number format.
At this point you are done and can choose not to follow the rest of this post.
Making it Better
You may have noticed that, we hardcoded certain things like username, password and host in the source code.
This does not make the app very portable. Let’s make use of externalized configuration, which has extensive
support in Spring-Boot.
I will create a class ApplicationProperties which contains all the external properties we need:
At the beginning of this post I talked about receiving delivery receipts. The default implementation of
SmppSessionListener is to discard received PDUs. So I will extend the default implementation class and
handle delivery receipts in there:
The DeliveryReceipt class is a utility class I created to extract delivery details from PduRequest.
I will not paste the contents of the class here (it is quite lengthy), you can view its contents in the
Github repository.
We just need to register this handler to take advantage of the delivery receipt handling:
If you run the application now, you will see delivery receipts printed in the console. This solution
however is far from ideal. As I said earlier, the Sessions are short-lived; given a scenario where
a mobile device is switched off, the SMS will be delivered only when the device is switched back on.
In this same scenario, the SMPP Session may be closed when the delivery is received, leading to lost
delivery receipts. To overcome this limitation I have to design the application to periodically refresh
the session before it un-binds.
I will use EnquireLinkResp to periodically extend the session:
I have added annotation on top of the class to @EnableScheduling which allows spring to process
the @Scheduled annotation. The fixedDelayString value ${sms.async.initial-delay} is set in the
application.yaml file:
This will cause the application to enquire link every 30 seconds. This solution is far from perfect. When
internet connectivity is lost on the server running the application, this will not work. Also when the
Session unexpectedly unbinds this solution will not work. I have implemented a more robust solution
on the persistent branch of the Github repository accompanying this post.
Before we wrap up, it is not very good practice to store sentive information in plain text on files. There
are several best practices and solutions out there e.g. using Vault from Hashicorp. I am going to implement
the simplest solution by using environment variables:
Conclusion
In this post we looked briefly at the SMPP protocol and its usage within the JVM. We also covered how to
use Spring Boot to make developing an SMPP client easier.
As usual you can find the full example to this guide in the github repository. Until the next post, keep
doing cool things .