Skip to main content
Sheelah Brennan

How to Send Email from React Without a Backend

I recently worked on a project where I needed to be able to let users submit feedback via a web form. The goal was to have submitted feedback sent as email to a designated email address. This project was going to be a static site built using React, however, without any backend to handle email. I figured out a way to make this work without introducing any backend or serverless (like AWS Lambda) type of solution. Here's how I did it!

The Problem

The problem with front-end-only applications is that there is no way to securely store an email provider API key. Storing it client-side, where it would be visible in your application's code, is a no-no.  Then anyone would be able to see your key!  I found a way to handle this by using an intermediary service called EmailJS.

Create an Email Provider Account

I created a Mailgun account to serve as the email service. The free tier offers 10,000 emails and 100 email validations a month, which was plenty for my needs. For applications that already have a backend server of some kind, a service like Mailgun can easily be used directly.  Some other email service options are Postmark and Mandrill.

Create an EmailJS Account

I created an EmailJS account to serve as a connector to my email service of choice for this project, Mailgun. This was the only provider I could find in this category.  By having EmailJS as the intermediary, I would be able to send email via Mailgun directly from the end user's browser without exposing my Mailgun API key in my web application.  The free tier of EmailJS 200 emails a month and 3 email templates.

Once my account was set up, I added Mailgun as an email service within my EmailJS account, adding in my Mailgun API key and domain.

Emailjs email setup
Emailjs email setup

Create an EmailJS Email Template

Within my EmailJS account, I added a custom email template that would provide the base email and underlying logic to process form submissions and send them to my designated recipient email address.  Mustache is the underlying templating engine used. Since all template fields other than the template name and ID can contain parameters that are passed in from JavaScript, they are pretty flexible. I ended up needing to set up a few parameters (shown in curly braces) – one for the submitter's email, one for their feedback, and another one for the recipient's email (not shown below), set as the recipient for all feedback emails.

Emailjs template
Emailjs template

Add EmailJS to the Application

Next it was time to set up EmailJS within my React application.

Set Up Environment Variables

Since create react app comes with support for environment variables, I added 3 of them: REACT_APP_EMAILJS_USERID, REACT_APP_EMAILJS_TEMPLATEID, and REACT_APP_EMAILJS_RECEIVER. This way I'd be able to use a different template ID or email recipient on different instances of my application (Ex. development vs staging vs production) if I needed to.

Add EmailJS as a Dependency

My application was built with create react app, I had a public/index.html file already and added EmailJS directly there in the document head. Alternatively, EmailJS can be added as an npm package, as detailed in their documentation.

    <script type="text/javascript" src="https://cdn.emailjs.com/sdk/2.1.0/email.min.js"></script>
    <script type="text/javascript">
       (function(){
          emailjs.init("%REACT_APP_EMAILJS_USERID%");
       })();
    </script>

Build the Form

Next, I added my React feedback form component:

<form className="feedback-form" onSubmit={handleSubmit}>
  <h1>Your Feedback</h1>
  <textarea
    className="text-input"
    id="feedback-entry"
    name="feedback-entry"
    onChange={handleChange}
    placeholder="Enter your feedback here"
    required
    value={feedback}
  />
  <div className="btn-group">
    <button className="btn btn--cancel" onClick={handleClose}>
      Cancel
    </button>
    <input type="submit" value="Submit" className="btn btn--submit" />
  </div>
</form>

Add Email Submit Functionality

Finally, in my form's parent component, I added a handleSubmit() function that would call a separate sendFeedback() function to trigger feedback submissions to be sent via EmailJS:

    handleSubmit (event) {
        event.preventDefault()

        const {
          REACT_APP_EMAILJS_RECEIVER: receiverEmail,
          REACT_APP_EMAILJS_TEMPLATEID: template
        } = this.props.env

        this.sendFeedback(
          template,
          this.props.senderEmail,
          receiverEmail,
          this.state.feedback)

        this.setState({
          formSubmitted: true
        })
      }

      sendFeedback (templateId, senderEmail, receiverEmail, feedback) {
        window.emailjs.send(
          'mailgun',
          templateId,
          {
            senderEmail,
            receiverEmail,
            feedback
          })
          .then(res => {
            this.setState({ formEmailSent: true })
          })
          // Handle errors here however you like, or use a React error boundary
          .catch(err => console.error('Failed to send feedback. Error: ', err))
      }

As shown above, I used EmailJS's send() function, which is covered in their SDK documentation. In that call, I include an object containing the three parameters that my EmailJS template needs – senderEmail, receiverEmail, and feedback. I then proceeded to test the form to check that feedback emails were sent. I liked that I could also see a log of emails sent in my EmailJS dashboard.

I also added a confirmation component that would display after successful feedback form submissions.  And boom – success! Email send functionality from my React application without the need for a backend.  This approach could be used with other front-end applications built with plain ol' JavaScript and HTML or another framework like Vue.js.

To view a completed code example built on top of Create React App, see https://github.com/sheelah/react-form-submission-demo.