How To Send Automated E-Mails In A Full-Stack React App

We only need 99 lines of code!

Frank Zickert
Jan 28 · 7 min read
Photo by on Unsplash

Emails may no longer be your favorite tool when you chat with your friends or colleagues. But emails remain important to get in touch with your users.

Emails enable you to send push messages to your users. Even at times when the user is not online. You have created something new? Let your users know!

Emails persist. Your user can decide on keeping the information you’ve sent. She does not have to keep a browser tab open.

You can verify email addresses. Send a confirmation request to an entered email address. Your user needs access to the inbox to confirm it!

Emails are private. You decide whom to send an email to. You decide on the content of the email.

Most of these emails, you don’t want to send manually. It is too much effort to send the same email over and over again. And you don’t want your user to wait for you.

Let’s create a React app that sends emails automatically!

Sending emails requires a back-end for your React app. Because you need an SMTP-server. And you don’t want to put your own email account credentials into a frontend React app.

Before we get into the technical details, let’s have a look at the architecture of the app, we’re about to build

The architecture of a full-stack React app

We create a simple React web app as our front-end. Our back-end is an AWS Lambda service that calls AWS SES (Simple Email Service) to send an email to us.

We use Infrastructure-Components to create our full-stack app. These React-Components let us define our infrastructure architecture as part of our React-app. We don’t need any other configuration like Webpack, Babel, or Serverless anymore.

In fact, the whole source code is less than 100 lines of code! … 99 actually ;-)

Let’s start with our source code. Don’t worry. I’ll explain the details right afterward.


In Infrastructure-Components-based projects, the top-level-component defines the overall architecture of our app. This is a <ServiceOrientedApp/> we export as default (line 35). Its properties and children add and configure all the infrastructure we need.

Our React app serves a simple input form at the base-route (“/”). The <Route/>-component connects the path (/) to the rendered <InputForm/>-component (lines 46–50).

The <InputForm/>-component (lines 8–32) renders an <input/> and a <button/>. We control the content of the <input/> by a React state-hook. Whenever the user changes the content of the <input/>, we update the local state (line 17). The email contains the new value that we provide as the current value of the <input/> (line 14).

When the user clicks the “send”-<button/> (line 21) we call our back-end. We use the callService function for convenience. It takes the id of the service, the payload, and callback-functions.

The id is an arbitrary string that identifies our service (see line 52). We’ll come to the <Service/>-definition in a second.

The payload is an arbitrary Javascript object. We provide the content of the <input/> (line 24).

The callback functions get called when the service call is successful (line 25) or returns with an error (line 26). We don’t provide any error handling here. We only keep the current state of whether we’re currently sending an email in another useState-hook (lines 10, 25–30).

As long as we’re sending an email, we disable the button (line 20). We also disable the button if the user has not entered a valid email address. We use a simple regex to verify that the format is correct.

Let’s have a small break! This InputForm is a functional React component with a local state. It looks like this. … Nothing fancy…

Let’s continue with our back-end. We define it by a <Service/>-component we provide as a child to our top-level <ServiceOrientedApp/> (line 51).

Our <Service/> requires an id that is unique across our app (line 52). It must be the same id we use to call the service (line 23). The <Service/> further takes the local path (like a route’s path) (line 53) and the HTTP-method (line 54). We use a POST-service because we want the callService-function to provide the payload in the request’s body.

The <Service/> takes a <Middleware/>-component as a child (line 56). This has a callback-property (line 57). We can provide any Express.js-middleware as the callback.

An Express.js middleware is a function with two parameters: req (the browser request) and res (the prepared server response).

We start by parsing the request body and obtaining the emailAddress from it (line 58).

Sending emails may take some time. Therefore, we wrap it into a Promise (line 60) and await until it resolves. AWS provides access to its Simple Email Service SES through the AWS SDK we import at line 61.

At line 62, we configure the AWS.SES object with its current apiVersion and call the sendMail-function. This takes all the data required of an email, like Destination-addresses, the Message with its Body and Subject, and the Source. That is our own email address we want to send the email from.

We transform the AWS.SES().sendEmail()-result in a Promise (line 86). This lets us attach a success-handler (then(), lines 86–88) and an error handler (catch, lines 89–92).

Depending on the success of sending the email, we send the status 200 (ok) or 500 (failed) as a response to the browser.

It’s time for a second small break. Our back-end consists of a single service. It takes the recipient’s email address and sends a simple “Hello” message.

Let’s have a look at our app in action! The following snippet depicts the package.json of our app. The most important part is the build script. It runs the scripts command, takes the .env file and builds the src/index.tsx. This is the local path to our main application source code file.

Before you can build the project, you need to install all the dependencies. Simply run npm install.

The library infrastructure-scripts (see in the devDependency) provides the scripts command.

You can now build your project with npm run build.

The build script adds more scripts to the package.json:

  • npm run {your-project-name} starts your React-app locally (hot-dev mode, without backend)
  • npm run deploy-{your-env-name} deploys your whole app to AWS. {your-env-name} is the value of the name-property we provide to the <Environment/>-component (line 97).

Let’s first start the app locally and have a look at the front-end. You can stop it by ctrl+c.

Before we deploy our app, we need to do some one-time preparations of our AWS account.

1. Of course, you need an AWS account that you can create at

Note: Currently, Amazon provides generous free tiers of its resources. However, Amazon may charge you for the resources you use. Please make sure to control the AWS resources you use.

2. You need a technical user (with programmatic access / API-key)

In your AWS-console, open the IAM menu and create a new user with the following policy:


3. Put these into the.env-file in your project root.


4. You need to verify the email address you want to send your emails from. In your AWS-console, open the SES menu. Then select “Verify a New Email Address” and submit your email address. You get an email from AWS with a link. Clicking the button completes the verification. … Isn’t that a good example of how to use an email…?

Look at the details of the new entry in the list of email addresses. There you can see the ARN that looks like this:

Enter this ARN in the Resource-part of the iamRoleStatements that we provide as a property to <ServiceOrientedApp/>. And make sure to specify your SENDER_EMAIL at line 6.

We’re good to go! Run npm run deploy-{your-env-name}.

The deployment script takes a little while. Once it completes, it shows a message like this with the URL of your deployed app:

Your deployment is complete!           
Your React-App is now available at:

Enter an email address into the input field and click the send mail button!

You can find the full source code of this app at GitHub.

This post is part of my new book. Get the first chapter for free at

JavaScript news and opinion.

Frank Zickert

Written by

I have been working as an IT professional for 17 years. I studied Information Systems Development and earned my PhD in 2012 at Goethe University of Frankfurt.


JavaScript news and opinion.

More from DailyJS

More from DailyJS

Samantha Ming
Feb 4 · 4 min read


More from DailyJS

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade