Send Email and Spock Spring
Learn how to send emails with AWS SES and SendGrid from a Grails app and leverage Spock Spring integration to verify interaction.
Authors: Sergio del Amo
Grails Version: 4
1 Getting Started
1.1 What you will need
To complete this guide, you will need the following:
-
Some time on your hands
-
A decent text editor or IDE
-
JDK 11 or greater installed with
JAVA_HOMEconfigured appropriately
1.2 How to complete the guide
To get started do the following:
-
Download and unzip the source
or
-
Clone the Git repository:
git clone https://github.com/grails-guides/grails-email.git
The Grails guides repositories contain two folders:
-
initialInitial project. Often a simple Grails app with some additional code to give you a head-start. -
completeA completed example. It is the result of working through the steps presented by the guide and applying those changes to theinitialfolder.
To complete the guide, go to the initial folder
-
cdintograils-guides/grails-email/initial
and follow the instructions in the next sections.
You can go right to the completed example if you cd into grails-guides/grails-email/complete
|
If you want to start from scratch, create a new Grails 3 application using Grails Application Forge.
2 Writing the App
Create an app with the rest-api profile
grails create-app example --profile=rest-api
2.1 Controller
Add an entry to UrlMappings:
package example.grails
class UrlMappings {
static mappings = {
...
..
.
link:../../snippets/grails-app/controllers/example/grails/UrlMappings.groovy[role=include]
}
}
Create MailController which use a collaborator, emailService to send and email.
link:../../snippets/grails-app/controllers/example/grails/MailController.groovy[role=include]
The previous controller uses a command object:
link:../../snippets/grails-app/controllers/example/grails/EmailCmd.groovy[role=include]
| 1 | recipient is required |
| 2 | subject is required |
| 3 | You must specify either textBody or htmlBody |
2.2 Email Service
Create an interface - EmailService. Any email integration present in the application should implement it.
link:../../snippets/src/main/groovy/example/grails/EmailService.groovy[role=include]
link:../../snippets/src/main/groovy/example/grails/Email.groovy[role=include]
2.2.1 AWS SES
Amazon Simple Email Service (Amazon SES) is a cloud-based email sending service designed to help digital marketers and application developers send marketing, notification, and transactional emails. It is a reliable, cost-effective service for businesses of all sizes that use email to keep in contact with their customers.
There is a AWS SDK SES Grails plugin. However, in this guide we are going to integrate AWS SDK SES directly.
Add a dependency to AWS SES SDK:
link:../../../snippets/build.gradle[role=include]
Also, add configuration properties which can be passed via system properties / command line arguments:
link:../../../snippets/grails-app/conf/application.yml[role=include]
Create one service which encapsulates the integration with SES. There are several way to provide programmatic credentials.
The client searches for credentials using the default credentials provider chain, in the following order:
In the Java system properties: aws.accessKeyId and aws.secretKey.
In system environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
In the default credentials file (the location of this file varies by platform).
In the Amazon ECS environment variable: AWS_CONTAINER_CREDENTIALS_RELATIVE_URI.
In the instance profile credentials, which exist within the instance metadata associated with the IAM role for the EC2 instance.
link:../../../snippets/grails-app/services/example/grails/AwsSesMailService.groovy[role=include]
| 1 | Retrieve configuration values with GrailsConfigurationAware |
2.2.2 SendGrid
SendGrid is a transactional email service.
SendGrid is responsible for sending billions of emails for some of the best and brightest companies in the world.
There is a SendGrid Grails Plugin. However, in this guide we are going to integrate AWS SDK SES directly.
Add a dependency to SendGrid SDK:
link:../../../snippets/build.gradle[role=include]
Add configuration properties which can be passed via system properties / command line arguments:
link:../../../snippets/grails-app/conf/application.yml[role=include]
Create a service which encapsulates the integration with SendGrid:
link:../../../snippets/grails-app/services/example/grails/SendGridEmailService.groovy[role=include]
| 1 | Retrieve configuration values with GrailsConfigurationAware |
2.3 Resources
Grails integrates with and builds on the Spring Framework.
You can easily register new (or override existing) beans by configuring them in grails-app/conf/spring/resources.groovy which uses the Grails Spring DSL.
Depending on the presence of the required system properties we are going to enable SendGrid or AWS SES integration.
link:../../snippets/grails-app/conf/spring/resources.groovy[role=include]
Add a logger to get more visibility:
...
..
.
link:../../snippets/grails-app/conf/logback.groovy[role=include]
To use SendGrid, start the app with the necessary system properties:
$ ./gradlew -DSENDGRID_FROM_EMAIL=email@email.com -DSENDGRID_APIKEY=XXXXXX bootRun
To use AWS SES, start the app with the necessary system properties:
$ export AWS_ACCESS_KEY_ID=XXXXXXXX
$ export AWS_SECRET_ACCESS_KEY=XXXXXXXX
$ ./gradlew -DAWS_REGION=eu-west-1 -DAWS_SOURCE=email@email.com bootRun
2.4 Test
In our acceptance test we don’t want bean emailService to be SendGridEmailService or AwsSesMailService. Instead we want it to be a Mock which we can verify interactions against.
The spock-spring module provides support for defining Spock mocks and stubs as Spring beans.
Add a dependency to spock-spring:
link:../../snippets/build.gradle[role=include]
First, you need to annotate Application.groovy with @ComponentScan.
link:../../snippets/grails-app/init/example/grails/Application.groovy[role=include]
In the next test, we use an embedded config annotated with @TestConfiguration. We create an EmailService mock using a DetachedMockFactory.
link:../../snippets/src/integration-test/groovy/example/grails/MailControllerSpec.groovy[role=include]
| 1 | emailService.send method is invoked once. |
Learn more about Spring Spock integration in Spock documentation.
3 Do you need help with Grails?
Help with Apache Grails
Apache Grails is supported by an active community of contributors and the Apache Software Foundation. If you need help working through a guide, want to discuss the framework, or have run into something that looks like a bug, the channels below are the right place to start.
-
Slack - real-time conversation with the Apache Grails community.
-
dev@grails.apache.org">Developer mailing list - design discussions and contributor coordination.
-
users@grails.apache.org">Users mailing list - end-user questions and answers.
-
Issue tracker on GitHub - file a bug or feature request against the framework.
For Grails plugins, see the matching project on the apache org or the plugin’s own GitHub repository.