Boot

Spring Boot and SNS email Example

In this tutorial, we will explain how to send an email or notification through the AWS SNS (Amazon Simple Notification Service) in a spring boot application.

1. Introduction

Before going further in this tutorial we will take a look at the common terminology such as introduction to Spring Boot, Lombok, and Amazon SQS.

1.1 Spring Boot

  • Spring boot is a module that provides rapid application development feature to the spring framework including auto-configuration, standalone-code, and production-ready code
  • It creates applications that are packaged as jar and are directly started using embedded servlet container (such as Tomcat, Jetty or, Undertow). Thus, no need to deploy the war files
  • It simplifies the maven configuration by providing the starter template and helps to resolve the dependency conflicts. It automatically identifies the required dependencies and imports them into the application
  • It helps in removing the boilerplate code, extra annotations, and XML configurations
  • It provides powerful batch processing and manages the rest endpoints
  • It provides an efficient JPA-starter library to effectively connect the application with the relational databases
  • It offers a Microservice architecture and cloud configuration that manages all the application related configuration properties in a centralized manner

1.2 Lombok

  • Lombok is nothing but a small library which reduces the amount of boilerplate Java code from the project
  • Automatically generates the getters and setters for the object by using the Lombok annotations
  • Hooks in via the Annotation processor API
  • Raw source code is passed to Lombok for code generation before the Java Compiler continues. Thus, produces properly compiled Java code in conjunction with the Java Compiler
  • Under the target/classes folder you can view the compiled class files
  • Can be used with Maven, Gradle IDE, etc.

1.2.1 Lombok features

FeatureDetails
valLocal variables are declared as final
varMutable local variables
@Slf4JCreates an SLF4J logger
@CleanupWill call close() on the resource in the finally block
@GetterCreates getter methods for all properties
@SetterCreates setter for all non-final properties
@EqualsAndHashCode
  • Generates implementations of equals(Object other) and hashCode()
  • By default will use all non-static, non-transient properties
  • Can optionally exclude specific properties
@ToString
  • Generates String of class name, and each field separated by commas
  • Optional parameter to include field names
  • Optional parameter to include a call to the super toString method
@NoArgsConstructor
  • Generates no-args constructor
  • Will cause compiler error if there are final fields
  • Can optionally force, which will initialize final fields with 0/false/null var – mutable local variables
@RequiredArgsContructor
  • Generates a constructor for all fields that are final or marked @NonNull
  • The constructor will throw a NullPointerException if any @NonNull fields are null Val – local variables are declared final
@AllArgsConstructor
  • Generates a constructor for all properties of the class
  • Any @NotNull properties will have null checks
@Data
  • Generates typical boilerplate code for POJOs
  • Combines – @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor
  • No constructor is generated if constructors have been explicitly declared
@Builder
  • Implements the Builder pattern for object creation
@Value
  • The immutable variant of @Data
  • All fields are made private and final by default

1.3 What is Amazon SNS?

Amazon Simple Notification Service (SNS) is a service that enables a publisher to send notifications on a specific topic to its consumers (i.e. receivers) through various communication channels like SMS, Email, HTTP, HTTPS, AWS SQS, and AWS Lambda.

  • It supports over 200+ countries for SMS and Email notifications
  • Guarantees message delivery as long as the SMS or the Email address is valid
  • AWS provides excellent and well-written SNS SDK for Java language
Spring Boot SNS email - AWS SNS flow diagram
Fig. 1: AWS SNS flow diagram

Let us go ahead with the tutorial implementation but before going any further I’m assuming that you’re aware of the Spring boot and AWS basics and have an AWS account for testing purposes (i.e. creation of Topic on SNS console).

2. Spring Boot and SNS email Example

2.1 Application Pre-requisite

To start with this tutorial, you need to create a Standard SNS topic and subscribe to it. Sign in to the AWS console with your credentials and navigate to the SNS console. Once you land onto the SNS page click on the Create topic button and something like below will be shown.

Fig. 2: Create a topic

Fill in the topic name and select the Standard topic radio button and leave the rest details as default. Submit the form and on the successful creation of the topic, you will get a green toaster saying topic created successfully.

Fig. 3: Topic created successfully

Once the topic is created remember to store the ARN (Amazon Resource Name) as we’ll need it later. Create a subscription using the Create subscription button. Select the protocol as Email and fill in the endpoint as an Email Address (i.e. Subscriber email address) to which you would like to subscribe. Remember the subscriber needs to confirm the subscription by visiting their email address and clicking on the confirmation email sent by AWS. Once a subscriber is confirmed it will be shown in the topic.

Fig. 4: Subscription confirmation

2.2 Tools Used for Spring boot application and Project Structure

We are using Eclipse Kepler SR2, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.

Fig. 5: Project structure

3. Creating a Spring Boot application

Below are the steps involved in developing the application.

3.1 Maven Dependency

Here, we specify the dependency for the Spring Boot (Web), Spring Cloud (AWS and AWS messaging), and Lombok. Maven will automatically resolve the other dependencies. The updated file will have the following code.

pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
         xmlns="http://maven.apache.org/POM/4.0.0"
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.springboot.sns.email</groupId>
    <artifactId>SpringbootSnsEmail</artifactId>
    <version>0.0.1-SNAPSHOT</version>
 
    <name>Springboot sns email tutorial</name>
 
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>
 
    <!-- spring boot starter parent dependency -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-aws</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-aws-messaging</artifactId>
        </dependency>
        <!-- lombok dependency -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
 
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <build>
        <!-- to make the application as fat jar so that spring boot libraries are
            included -->
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3.2 Application Properties

Create a new properties file at the location: SpringbootSnsEmail/src/main/resources/ and add the following code to it.

application.properties

1
2
3
4
5
6
server.port=10093
spring.application.name=springboot-and-sns
cloud.aws.credentials.access-key=AWS_IAM_ACCOUNT_ACCESS_KEY
cloud.aws.credentials.secret-key=AWS_IAM_ACCOUNT_SECRET_KEY
cloud.aws.region.static=REGION_CODE
cloud.aws.region.auto=false

3.3 Java Classes

Let us write all the java classes involved in this application.

3.3.1 Implementation/Main class

Add the following code to the main class to bootstrap the application from the main method. Always remember, the entry point of the spring boot application is the class containing @SpringBootApplication annotation and the static main method.

SpringbootSnsEmail.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package com.springboot.sns;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
// Lombok annotation
// Causes Lombok to generate a logger field.
@Slf4j
// Spring framework annotation
// Main implementation class which serves two purposes in a spring boot application: Configuration and bootstrapping.
@SpringBootApplication
public class SpringbootSnsEmail {
 
    // Main program to start up the spring boot application.
    public static void main(String[] args) {
        SpringApplication.run(SpringbootSnsEmail.class, args);
        log.info("Spring-boot sns application started successfully.");
    }
}

3.3.2 Model class

Add the following code to the Notification model class where we will define the basic attributes.

Notification.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.springboot.sns.model;
 
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;
 
// Lombok annotations
// Causes Lombok to generate getter() methods.
@Getter
// Causes Lombok to generate the toString() method.
@ToString
// Causes Lombok to generate a constructor with 1 parameter for each field in your class.
@AllArgsConstructor
public class Notification {
 
    @JsonProperty("subject")
    @NonNull
    final String subject;
    @JsonProperty("message")
    final String message;
}

3.3.3 Configuration class

Add the following code to the bean class that will return the bean object for amazonSNSClient.

AwsConfig.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.springboot.sns.config;
 
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
 
// Marker annotation that tells spring to generate bean definitions at runtime for the methods annotated with @Bean annotation.
@Configuration
public class AwsConfig {
 
    // Value is populated with the aws access key.
    @Value("${cloud.aws.credentials.access-key}")
    private String awsAccessKey;
 
    // Value is populated with the aws secret key
    @Value("${cloud.aws.credentials.secret-key}")
    private String awsSecretKey;
 
    // Value is populated with the aws region code
    @Value("${cloud.aws.region.static}")
    private String region;
 
    // @Primary annotation gives a higher preference to a bean (when there are multiple beans of the same type).
    @Primary
    // @Bean annotation tells that a method produces a bean that is to be managed by the spring container.
    @Bean
    public AmazonSNSClient amazonSNSClient() {
        return (AmazonSNSClient) AmazonSNSClientBuilder
                .standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(
                        new BasicAWSCredentials(awsAccessKey, awsSecretKey)))
                .build();
    }
}

3.3.4 Controller class

Add the following code to the controller class designed to handle the incoming requests. The class is annotated with the @RestController annotation was the HTTP POST methods would accept the input and perform the request action(s).

SnsController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.springboot.sns.controller;
 
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.PublishRequest;
import com.amazonaws.services.sns.model.SubscribeRequest;
import com.springboot.sns.model.Notification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
 
// Causes Lombok to generate a logger field.
@Slf4j
@RestController
public class SnsController {
 
    // Topic arn. You are free to choose their topic arn.
    private static final String TOPIC_ARN = "TOPIC_ARN";
 
    @Autowired
    private AmazonSNSClient amazonSNSClient;
 
    // NOTE - In this tutorial, we are skipping the email validation part. Trusting that you'll add a valid email address.
    @PostMapping(value = "/addSubscription/{email}")
    public ResponseEntity<String> addSubscription(@PathVariable final String email) {
        log.info("Adding new email subscription = {} to the topic.", email);
        final SubscribeRequest subscribeRequest = new SubscribeRequest(TOPIC_ARN, "email", email);
        amazonSNSClient.subscribe(subscribeRequest);
        return new ResponseEntity<>(HttpStatus.OK);
    }
 
    // Sample request body -
    //  {
    //      "subject": "Springboot sns demo email",
    //      "message": "Lorem Ipsum is simply dummied text of the printing and typesetting industry."
    //  }
    @PostMapping(value = "/sendNotification")
    public ResponseEntity<String> publishMessageToTopic(@RequestBody final Notification notification) {
        log.info("Publishing the notification = {} to the topic.", notification.toString());
        final PublishRequest publishRequest = new PublishRequest(TOPIC_ARN, notification.getMessage(), notification.getSubject());
        amazonSNSClient.publish(publishRequest);
        return new ResponseEntity<>("Notification sent successfully!!", HttpStatus.OK);
    }
}

4. Run the Application

To execute the application, right-click on the SpringbootSnsEmail.java class, Run As -> Java Application.

Spring Boot and SNS email - Run the Application
Fig. 6: Run the Application

5. Project Demo

Open the Postman tool and hit the following URLs to create a new subscription or send a notification/message to the already subscribed subscribers.

1
2
3
4
5
// HTTP POST - Create a new subscription
 
// HTTP POST - Send a notification

On successfully sending a message to the HTTP POST API the subscribed subscriber will get a notification in their mailbox as shown below.

Spring Boot and SNS email - Successful notification
Fig. 7: Successful notification

That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!

6. Summary

In this section, you learned:

  • Spring Boot, Lombok and it features, and AWS Simple Notification Service (SNS) introduction
  • Steps to create a Standard Topic on Amazon SNS console and subscribed to it
  • Steps to implement SNS in spring boot with a simple application

You can download the sample application as an Eclipse project in the Downloads section.

7. Download the Eclipse Project

That was  Spring Boot and AWS SNS email Example.

Download
You can download the full source code of this example here: Spring Boot and SNS email Example

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button