Amazon SNS with Delphi: Push notifications, SMS and publish-subscribe pattern

Delphi users developing with Amazon Web Services SDK for Delphi now can use yet another service: Amazon SNS (Amazon Simple Notification Service).

Amazon SNS is a managed service that provides message delivery from publishers to subscribers (also known as producers and consumers). Publishers subscribers by sending messages to a topic, which is a logical access point and communication channel. Clients can subscribe to the SNS topic and receive published messages using a supported endpoint type, such as Amazon Kinesis Data Firehose, Amazon SQS, AWS Lambda, HTTP, email, mobile push notifications, and mobile text messages (SMS).

It’s an affordable service. At the time this article was written, sending 1 million push notifications costs $0.50, while sending 1 million notifications via HTTP(S) costs $0.60. You can find more by visiting Amazon SNS pricing page.

Use cases

Amazon SNS can be used to implement a publisher/subscriber system, to send SMS messages, to send mobile push notifications, among others. Some common use cases are listed below:

  • Application integration: Applications can communicate with each other by sending message to topics and receiving messages via notifications. For example, you can develop an application that publishes a message to an SNS topic whenever an order is placed for a product. This message can be consumed by other applications for further processing.
  • Application alerts: Applications can send notifications when something happen, for example, when a critical error occurs, or when a specific indicator value is higher than a threshold.
  • User notifications: Amazon SNS can send push email messages and text messages (SMS messages) to individuals or groups. For example, you could send e-commerce order confirmations as user notifications.
  • Mobile push notifications: And of course, you can send push notifications to your mobile applications to notify your users of any important information related to your app.

Using Amazon SNS with AWS SDK for Delphi

You can refer to our first article about AWS SDK for Delphi to learn more about the concepts, credentials and basic usage. Once you learn about it, you can easily use the following code snippets to perform some specific operations using Amazon SNS.

To start with, you should of course create the SNS client:

var
  Client: IAmazonSimpleNotificationService;
begin
  Client := TAmazonSimpleNotificationServiceClient.Create;
end;

The following code shows how to create a topic (which you can use to publish messages to it) and get its ARN, which will be used for further operations:

var
  TopicArn: string;
begin
  TopicArn := Client.CreateTopic('test-name').TopicArn;
end;

You can then set or get the topic attributes, or even delete it if you need to:

var
  TopicArn: string;
  SetAttrRequest: ISetTopicAttributesRequest;
  GetAttrResponse: IGetTopicAttributesResponse;
begin
  // set topic attribute
  SetAttrRequest := TSetTopicAttributesRequest.Create(TopicArn, 'DisplayName', 'My topic');
  Client.SetTopicAttributes(SetAttrRequest);

  // verify topic attributes
  GetAttrResponse := Client.GetTopicAttributes(TopicArn);
  DisplayName := GetAttrResponse.Attributes['DisplayName']);

  // delete new topic
  Client.DeleteTopic(TopicArn);
end;

Next step is to add subscriptions to the topic. You can setup it to send notifications to HTTP endpoints, e-mail, SMS messages, other Amazon services, etc. The following example shows how to subscribe the topic to an e-mail address, so messages published to topic will be sent via e-mail. This example waits for the subscription operation to finish to get the subscription ARN. With the subscription ARN you can later perform operations on it, like removing the subscription.

function SubscribeTopic(const TopicArn, EmailAddress: string): string;
var
  Latest: TDateTime;
  Response: IListSubscriptionsByTopicResponse;
begin
  // subscribe an email address to the topic
  Client.Subscribe(TSubscribeRequest.Create(TopicArn, 'email', EmailAddress));

  // wait until subscription has been confirmed, wait time for two minutes
  Latest := IncMinute(Now, 2);
  while Now < Latest do
  begin
    // get subscriptions for topic
    Response := Client.ListSubscriptionsByTopic(TopicArn);

    // test whether the subscription has been confirmed
    if Response.Subscriptions[0].SubscriptionArn <> 'PendingConfirmation' then
      Exit(Response.Subscriptions[0].SubscriptionArn);

    // wait
    Sleep(15 * 1000);
  end;
end;

And this is another example of subscription. In this case, we’re subscribing to an Amazon SQS queue. Messages will be forwarded to the queue, which can be later processed by reading the existing messages in the queue. The example also sets proper permission to the queue, otherwise the SNS topic wouldn’t have permission to send messages to it.

function SubscribeQueue(Client: IAmazonSimpleNotificationService;
  const TopicArn: string; SQSClient: IAmazonSQS; const SQSQueueUrl: string): string; 
var
  GetAttrResponse: IGetQueueAttributesResponse;
  GetAttrRequest: IGetQueueAttributesRequest;
  SQSQueueArn: string;
  Policy: TPolicy;
  PolicyStr: string;
  TopicArn: string;
  SetAttrRequest: ISetQueueAttributesRequest;
begin
  // Get the queue's existing policy and ARN
  GetAttrRequest := TGetQueueAttributesRequest.Create;
  GetAttrRequest.QueueUrl := SQSQueueUrl;
  GetAttrRequest.AttributeNames.Add(TSQSConsts.ATTRIBUTE_ALL);
  GetAttrResponse := SQSClient.GetQueueAttributes(GetAttrRequest);
  SQSQueueArn :=  GetAttrResponse.Attributes['QueueArn'];

  if  GetAttrResponse.Attributes.TryGetValue('Policy', PolicyStr) then
    Policy := TPolicy.FromJson(PolicyStr)
  else
    Policy := TPolicy.Create;
  try
    SetLength(Result, 0);
    if not HasSQSPermission(Policy, TopicArn, SQSQueueArn) then
      AddSQSPermission(Policy, TopicArn, SQSQueueArn);

    Result := Client.Subscribe(TopicArn, 'sqs', SQSQueueArn).SubscriptionArn;

    SetAttrRequest := TSetQueueAttributesRequest.Create;
    SetAttrRequest.QueueUrl := SQSQueueUrl;
    SetAttrRequest.Attributes.Add('Policy', Policy.ToJson);
    SQSClient.SetQueueAttributes(SetAttrRequest);
  finally
    Policy.Free;
  end;
end;

Once topic is created and has some subscriptions to it, all you need to do is publish messages to the topic. The messages will be then sent to the subscribers:

  // publish a message to the topic
  Client.Publish(TPublishRequest.Create(TopicArn, 'Test message', 'Subject'));

If you also want to write code for the subscribers, you can read the sent message and process it. Messages are sent as JSON format, and AWS SDK for Delphi already provides high-level classes to process it. You can easily parse the message from JSON and even validate it. Each message sent from Amazon SNS has a signature generated from a certificate. The message provides an URL you can use to download a certificate and check if the signature is valid by using the certificate’s public key. AWS SDK for Delphi automatically does that for you (download the certificate and check the valid signature) with a single line of code:

// Parse an SNS message from JSON and validate signature:
function GetMessage(const Json: string): AWS.SNS.Message.TMessage;
begin
  Result := AWS.SNS.Message.TMessage.ParseMessage(Json);
  if not Result.IsMessageSignatureValid then
    raise Exception.Create('Invalid message: bad signature');
end;

And finally, a totally different example, the code used to send a mobile push notification to an arbitrary mobile number.

var
  Client: IAmazonSimpleNotificationService;
  Request: IPublishRequest;
begin
  Client := TAmazonSimpleNotificationServiceClient.Create;
  Request := TPublishRequest.Create;
  Request.PhoneNumber := '+184298765321';
  Request.Message := 'Hello from AWS SDK for Delphi!';
  Client.Publish(Request);
end;

What’s next

Stay tuned for more services to be added to AWS SDK for Delphi! You can also be part of it. Let us know what do you think and what service you want to be added, and why. Share your needs, we can listen and adjust our roadmap, depending on community feedback. And of course, also feel free to comment below with your thoughts and what did you think about Amazon SNS support.

(*) Photo by Torsten Dettlaff from Pexels

Leave your comment at forum.landgraf.dev