As the last step, let's create a Lambda function that will subscribe to our topic and send a welcome mail. As usual, let's create our module and the package:
$ mkdir -p lambda-userregistration-welcomemail/src/main/
java/com/serverlessbook/lambda/userregistration/welcomemail
Then, let's add the package into the settings.gradle file:
echo "include 'lambda-userregistration-welcomemail'" >>
settings.gradle
Let's first create the build.gradle file in our new module and add the required dependencies:
dependencies { compile group: 'com.amazonaws', name: 'aws-lambda-java-events',
version: '1.3.0' compile group: 'com.amazonaws', name: 'aws-java-sdk-ses',
version: '1.11.+'compile group: 'com.google.inject',
name: 'guice', version: guiceVersion }
Then, let's create our Handler class:
public class Handler implements RequestHandler<SNSEvent, Void> { private static final Injector INJECTOR = Guice.createInjector(); private static final Logger LOGGER = Logger.getLogger(Handler.class); private AmazonSimpleEmailServiceClient simpleEmailServiceClient; @Inject public Handler setSimpleEmailServiceClient( AmazonSimpleEmailServiceClient simpleEmailServiceClient) { this.simpleEmailServiceClient = simpleEmailServiceClient; return this; } public Handler() { INJECTOR.injectMembers(this); Objects.nonNull(simpleEmailServiceClient); } private void sendEmail(final String emailAddress) { Destination destination = new Destination().
withToAddresses(emailAddress); Message message = new Message() .withBody(new Body().withText(new Content("Welcome to our forum!"))) .withSubject(new Content("Welcome!")); try { LOGGER.debug("Sending welcome mail to " + emailAddress); simpleEmailServiceClient.sendEmail(new SendEmailRequest() .withDestination(destination) .withSource(System.getenv("SenderEmail")) .withMessage(message) ); LOGGER.debug("Sending welcome mail to " + emailAddress +
" succeeded"); } catch (Exception anyException) { LOGGER.error("Sending welcome mail to " + emailAddress + " failed: ",
anyException); } } @Override public Void handleRequest(SNSEvent input, Context context) { input.getRecords().forEach(snsMessage ->
sendEmail(snsMessage.getSNS().getMessage())); return null; } }
Here, you should pay attention to a couple of things. First of all, we did not want our custom Lambda handler but the standard one because we do not need any custom JSON deserialization. Here, we used the standard AWS library, aws-lambda-java-events, which includes some POJOs for AWS service events. SNSEvent is one of them, which is created in accordance with SNS' event structure. AWS does not provide this type of library in other platforms, but as we are in Java, we are lucky. So, we do not have to worry about parsing the incoming request, and we can directly consume the incoming Java object.
The last thing to look at is how we build the SES API request. There are a lot of different options here that you can configure. You can check the SES documentation for deeper knowledge, but our configuration just does its job now and sends a raw text mail.
Before we go any further, let's add the required permission to our Lambda's IAM permission:
{ "Effect": "Allow", "Action": [ "ses:*" ], "Resource": "*" }
Then, let's create the Lambda function with the SenderEmail environment variable. You have to change the variable for your configuration, so you can add any email address belonging to the domain you verified on the SES panel:
"UserRegistrationWelcomeMailLambda": { "Type": "AWS::Lambda::Function", "Properties": { "Handler": "com.serverlessbook.lambda.
userregistration.welcomemail.Handler", "Runtime": "java8", "Timeout": "300", "MemorySize": "1024", "Description": "User registration welcome mail Lambda", "Role": { "Fn::GetAtt": [ "LambdaExecutionRole", "Arn" ] }, "Code": { "S3Bucket": { "Ref": "DeploymentBucket" }, "S3Key": { "Fn::Sub": "artifacts/lambda-userregistration-welcomemail/
${ProjectVersion}/${DeploymentTime}.jar" } }, "Environment": { "Variables": { "SenderEmail": "info@example.com" } }
} }, "UserRegistrationWelcomeMailLambdaPermission": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", "FunctionName": { "Ref": "UserRegistrationWelcomeMailLambda" }, "Principal": "sns.amazonaws.com", "SourceArn": { "Fn::Sub": "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:*" } } }
The second part of this block was the Lambda permission to let SNS invoke our function. As you remember from the API Gateway part, we should let AWS services invoke our Lambda functions to achieve execution of them on behalf of us. As we did for the API Gateway, here we allow sns.amazonaws.com to identify to execute our Lambda function.
As the last step, we must add a new subscription to UserRegistrationSnsTopic. Let's add this block to the Subscriptions part of UserRegistrationSnsTopic:
{ "Endpoint": { "Fn::GetAtt": [ "UserRegistrationWelcomeMailLambda", "Arn" ] }, "Protocol": "lambda" }
Everything is ready to be run now.
Just try to register a new user with the following command, changing the domain name to yours:
$ curl -X POST -H "Content-Type: application/json" -d
'{"username": "tester3", email: "success@simulator.amazonses.com"}'
-v https://serverlessbook.example.com/users
You can check the logs of your Lambda function to see that they are triggered via SNS and send the email to the user!