LocalStack Blog / Tutorial / Local Testing of SES Workflows Using LocalStack & MailHog Extension
Local Testing of SES Workflows Using LocalStack & MailHog Extension
Explore how you can test SES email workflows locally using LocalStack with our MailHog extension. You'll learn how you can configure a Lambda function to handle email delivery via SES, perform local testing with Jest, and enable a fully local development workflow without needing real AWS credentials.
Testing SES locally can be challenging, especially when replicating the cloud infrastructure for sending and receiving emails. New AWS accounts often face SES Sandbox restrictions, where you must request production access to send real emails, slowing down the development process. Other SES simulators or mocks often face issues like API incompatibility, missing parity tests to compare with real AWS behavior or lack of certain features. A better alternative for testing SES workflows is LocalStack, which emulates AWS services and makes cloud development and testing a breeze!
LocalStack’s SES emulation lets you test SES workflows alongside other AWS services like Lambda or ECS, allowing you to fully test and debug without using the real AWS cloud or cluttering your test account with unwanted emails. You can also set up an SMTP server and configure variables to send emails. Additionally, LocalStack’s internal developer endpoints let you track all sent emails for review, saving them as JSON for debugging and analysis.
In this blog, we’ll explore how to build and test a complete Email Feedback Delivery system using SES and SSM Parameter Store, with a frontend served by an S3 website to submit feedback. We’ll also show you how to automate SES testing with Jest and inspect sent emails using the MailHog extension, ensuring all parts of your system work smoothly together.
Email Feedback Delivery with Lambda, SES, S3, and SSM
This demo creates a feedback survey form for users to submit feedback. When new feedback is submitted, a Lambda function is triggered to generate an email and send it through SES. The frontend is deployed using S3 for hosting static assets, and SSM is used for managing secrets like sender and recipient email addresses. The application is developed and tested locally with LocalStack, so no real AWS credentials or SMTP details are needed.
This architecture shows the components we will deploy in this tutorial:
To test email delivery, we’ll use MailHog, an open-source email testing tool with a simple SMTP server and web interface. LocalStack offers a MailHog extension to simplify SES testing locally. We’ll start by installing the MailHog extension.
Install the MailHog extension
To install the MailHog extension, start your LocalStack container with your LOCALSTACK_AUTH_TOKEN:
Then, go to the Extensions manager and click + Install for the MailHog extension. After confirming, the LocalStack container will restart, and the extension will be accessible.
Check the LocalStack logs for MailHog extension output, where you should see logs like:
Before creating the Lambda function, we need to store the sender and recipient email addresses securely in the SSM Parameter Store. The Lambda function will retrieve these parameters dynamically using the AWS SDK at runtime. Run the following commands to create the SSM parameters:
To retrieve these parameters, run:
The expected output will be:
Create the Lambda function
First, create a new project directory and initialize it with npm:
Next, install AWS SDK v3 to interact with LocalStack’s local cloud APIs, specifically for SSM and SES:
The Lambda function will:
Initialize SES and SSM clients
Fetch sender and recipient email addresses from SSM Parameter Store
Build the email content
Send the email using the SES client
The implementation for this Lambda function is as follows:
To deploy this function, zip the index.js file along with its dependencies in the node_modules directory:
You can now create the Lambda function by running the following command:
Since LocalStack does not strictly enforce IAM roles and permissions, we don’t need to specify them here. However, in a production environment, you would need to set up a proper IAM role for the Lambda function to work correctly.
Once the Lambda function is created, you will receive output similar to this:
You can also set up a Function URL, which allows you to invoke the Lambda function directly via HTTP(s) requests. This simplifies the process and allows you to skip using API Gateway in the early stages of development or prototyping. To set up the Function URL, run the following command:
The output will include a URL like this:
You can use this URL to trigger your Lambda function, with the URL being specific to the output you receive.
Test the Lambda function
To test the Lambda function, run the following command:
This will result in an error:
The error occurs because the sender@example.com email address has not been verified by the local SES provider. To resolve this, you need to create a verified identity. You can verify an email identity using the following command:
After verifying the sender email, rerun the previous test command, and you will see the output:
Next, navigate to the MailHog extension user interface, where you will find an email with the subject New Feedback Submission, containing the feedback sent via the POST request.
Additionally, you can use the SES developer endpoint to list the messages sent via SES:
The output will include the details of the message sent:
Implement a frontend web client
Next, we’ll create a simple frontend form that collects feedback from users and submits it to the Lambda function. We’ll use Preact for building the frontend. If you don’t have Preact set up, create a new Preact app by running:
We will use Bootstrap for the UI components, so you can install it via npm:
In the entry file for the frontend, which is index.js, import Bootstrap’s CSS:
Now, create a file named FeedbackForm.js inside the src/components directory and add the following code:
This component captures feedback from the user and submits it to the Lambda function URL, which will be set through an environment variable.
Next, navigate to index.css in the styles directory and add the following styling to enhance the form appearance:
Finally, update the components/app.js file to include the FeedbackForm component:
Build & serve the frontend web client
Before building the web client, you need to create a .env file that contains the PREACT_APP_LAMBDA_URL variable, which points to your Lambda Function URL. To automate this process, you can use a shell script that fetches the Lambda function URL and adds it to the .env file.
Create a file named fetchLambdaURL.sh and add the following code:
Make the script executable by running:
To automate this script during the build process, add the script execution as a prebuild command in your package.json file:
Once the script is set up, you can build the client by running:
You can configure a static website using S3 to serve your feedback survey by running the following commands:
You can submit a response and then navigate to the MailHog extension to view the received email.
Write Unit Tests with Jest
As the last step, you can write a Jest test that verifies the email delivery process automatically. Install the following dependencies to get started:
Create a test file lambda.test.js and add the following code:
To run the tests, add the following script to your package.json:
Now run the test with:
You will see the following output:
Conclusion
With LocalStack, you can perform end-to-end testing of your SES workflows and other AWS services without deploying to the cloud. You can also test these workflows in conjunction with other AWS services, as shown in the example above. LocalStack’s support for SES and SES v2 is extensive, allowing you to test various workflows without the need for simulators or mock tools. Additionally, you can use the SES Resource Browser on the Web Application to create email identities, send emails, and review them, providing more comprehensive insights into your SES workflows.
You can find the complete source code for this tutorial on GitHub.
Develop and test your AWS applications locally to reduce
development time and increase product velocity. Reduce
unnecessary AWS spend and remove the complexity and risk of
maintaining AWS dev accounts.
Get the latest tips, tutorials, and insights on local cloud development.
Harsh Mishra
Engineer at LocalStack
Harsh Mishra is an Engineer at LocalStack and AWS Community Builder. Harsh has previously worked at HackerRank, Red Hat, and Quansight, and specialized in DevOps, Platform Engineering, and CI/CD pipelines.