Setting up a site mailer with node mailer, express and Gmail
Tags: node, emailer, express, react
Published: 2020-03-23 22:40:48

_photo from https://stories.wf.com/pony-express-riders-young-fast-fearless/_


In this tutorial, we are going to be setting up a site mailer. 

I think where a lot of devs go wrong with site mailers is trying to make one for an application instead of making a mailing service that thier application can use.

That's why in this tutorial we are going to set up a site mailer that can be used by any application.

This means that the contact form for your portfolio can also be used as the feedback form for your projects.  

Once you have one of these set up you can do amazing things with your website, such as sending payment receipts to a user's email and informing a blogger of new followers. 

__What does this tutorial teach?__

We are going to set up a contact form that sends what users enter into a form to a specific email using express, node mailer, react as a basic front end. 

__Why use react?__  

You can do the major functionality of this app without a front end framework. React is only going to be the form handling portion but it does provide the ability to scale if you want to do something more complex with a site mailer. 


__prerequisite software__

1.[node.js](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) this is a must for every javascript related thing that happens outside a browser. 

2.[create-react-app](https://www.npmjs.com/package/create-react-app) you can only do the back end functionality without this but because this is going to help you to do more robust things with this tutorial, we are using it. 

3.[vscode](https://code.visualstudio.com/download) you can use any text editor you want but I will be using vscode, this means it will be easiest to follow if you are too.

4.[git cli](https://git-scm.com/downloads) for keeping versions and changes.




__Prerequisite knowledge__

1. basic javascript.

2. curiosity about express and node.js

3. how to [install npm packages on the command line.](https://docs.npmjs.com/downloading-and-installing-packages-locally) 

(optional) bash commandline

__getting started__

go to the directory where you keep your projects and begin by making a new folder, called mail-service

```bash
mkdir mail-service
```

cd into the directory

```bash
cd mail-service
```

make a new npm project by initializing a package.json

```bash
npm init -y
```

the -y means we want to create this without asking questions. 

Open the project.

```bash
code .
```

In the package.json we have the basic setup. Let's install the npm packages.


```bash
npm i express morgan dotenv nodemailer
```

[express](https://www.npmjs.com/package/express) is a minimal framework for setting up server-side applications. 

[morgan](https://www.npmjs.com/package/morgan) is an http request logger, this will allow us to see the status of our request without making a function

[dotenv](https://www.npmjs.com/package/dotenv) is a package to save environment wide variables keeping sensitive information off of github. we will use it to hide emails and passwords.

[node-mailer](https://www.npmjs.com/package/nodemailer) this is all the helper methods to make our service send emails. 


Make a server.js file to house our server

```bash
touch server.js
```

at the top add the back-end imports. 

```javascript
const express = require('express')
const app = express()
require('dotenv').config()
const morgan = require('morgan')
const nodemailer = require('nodemailer')
const port = 4444
```

at the bottom add the app.listen to give our back end a definite port. 

```javascript
app.listen(port, () => {
  console.log(`app is live on ${port}`)
})
```

in the middle of those, make our app use morgan so that we get a better idea of how our app is behaving. 

```javascript
app.use(morgan('dev'))
```

Now have our app use express.json() to make sure everything gets to our backend in proper type.

```javascript
app.use(express.json())
```

Start the app on the commandline. 

```bash
nodemon server
```

If everything went right and you have all the packages installed, you should have a file and terminal looking like this. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mkarw11m6rtk8jy7uk6l.png)

Now we want to add git, for brevity I won't do this in writing.

The outline of this app goes like this.

Make one working route to send an email, make a frontend to use that route with a form.

Let's start by making a folder.

```bash
mkdir routes
```

Right click the routes folder we will make a sendToMe.js

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vidtefvwkw1lwqo1cak7.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6ouevql7m5eyqh89b108.png)

Add express and nodemailer to this file like so. 

```javascript
const express = require('express')
const sendToMeRouter = express.Router()
const nodemailer = require('nodemailer')
```

Add a console.log to that file so that we can make sure we are reaching the file from the server.js

```javascript
console.log("from sendToMe")
```
_sendToMe.js_

export the Router() at the bottom of the file. 

```javascript
module.exports = sendToMeRouter

```

in the server.js have the app use that route file like this.


```javascript
app.use('/sendtome', require('./routes/sendToMe'))
```
turn the server back on and see if the console.log shows up. 

```bash
nodemon server
```

Now we can build out the mailer's functionality. 

To do this we need to make an email address that this will use. 

With Gmail, you have to use the __turn on less secure apps to do this.__

You can use an email you already have but please be careful not to publish your password.

Now, in your google account home, in the top left corner, go to security. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/u9gwl9z5h00dznyfk1o4.png)

Scroll down until you reach less secure apps.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2fdn1skxwvntb3w3drf8.png)

The alternative to this is figuring out how to enable your site to use Oauth in your app, that will just be another thing. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bw7njjs2tet4x70iitak.png)

You should receive an email shortly from google saying that you enabled less secure apps. 

Make a .env file

```bash
touch .env
```

Now we need to add the email and password to the .env file and app wide variable. 

```
THE_EMAIL="super secret dont show anyone!!!"

THE_PASSWORD="super secret dont show anyone!!!"
```
_.env_

We are set up to make the transport object and the mailing functions in the sendToMe.js file. 

```javascript
const transport = {
  //all of the configuration for making a site send an email.
  
  host: 'smtp.gmail.com',
  port: 587,
  secure: false,
  auth: {
    user: process.env.THE_EMAIL,
    pass: process.env.THE_PASSWORD
  }
};
```

Now make the transporter function 

```javascript
const transporter = nodemailer.createTransport(transport);
  transporter.verify((error, success) => {
    if(error) {
      //if error happened code ends here
      console.error(error)
    } else {
      //this means success
      console.log('users ready to mail myself')
    }
  });
```

Let's add another function to make this work on a post request.

```javascript
sendToMeRouter.post('/', (req,res, next) => {
    //make mailable object
    const mail = {
      from: process.env.THE_EMAIL,
      to: 'your.email@gmail.com',
      subject: req.body.subject,
      text: `
      from:
      ${req.body.name} 
      
      contact: ${req.body.email}

      message: 

      ${req.body.text}`
    }
// error handling goes here. 
  });
```

finish with some error handling. 

```javascript
transporter.sendMail(mail, (err,data) => {
      if(err) {
        res.json({
          status: 'fail'
        })
      } else {
        res.json({
          status: 'success'
        })
      }
    })

//still inside the .post request the next line should be });
```

You can test this in [post man](https://www.postman.com/downloads/) but remember that you have to have text, email, name, and subject defined in order to get this to work and enable cors app wide.

Ok now we get to my favorite part, the react app.

While still inside the project directory on the command line create-react-app

```bash
create-react-app client
```

Go to the package.json and connect the express app to the react app with a proxy like so.

```json
//dont forget to add the comma after the curly bracket because it's json.
},
  "proxy": "http://localhost:4444/"
```

You will need to run the back and the front end at the same time. 

_on the back end_

```bash
nodemon server
```

_On in the client folder._

```bash
cd client && npm start
```

This should take you to the ordinary boiler-plate react. 

Let's add axios to the client folder. 

_in client directory on the command-line_

```bash
cd client && npm i axios
```

Remove all the code between the div tags. 

Your app function should look like this. 

```javascript
function App() {
  return (
    <div className="App">
      
    </div>
  );
}
```

Now make a form with 3 inputs and a textarea 

```javascript
<form>
        <input type="text" placeholder="" name="" value={} onChange={} />
        <input type="text" placeholder="" name="" value={} onChange={} />
        <input type="text" placeholder="" name="" value={} onChange={} />
        <textarea name="" id="" cols="30" rows="10"></textarea>
      </form>
```

__Dont panic! Our app will run again when we fill in the value and onChange attributes__

We will have the useState hooks keep the string for us. 

We need to import axios.

At the top. 

```javascript
import React, {useState} from 'react';
import axios from 'axios'
```

Inside the app function. 

```javascript
 const [inputs, setInputs] = useState({email: '', name: '', subject: '', description: ''})

```

Now to make the handleChange and the handleSubmit's 

```javascript
const handleChange = e => {
    const {name, value} = e.target
    setInputs(prev => ({...prev, [name]: value }))
  }
  const handleSubmit = e => {
    e.preventDefault()
    // post request goes here. 
  }
```

Add the place holders, name, value and onChange attributes so that our app isn't crashed anymore, add the onSubmit action to the form and a button.  I've also added br tags. 

```javascript
<h1>feed back form. </h1>
      <form onSubmit={handleSubmit}>
        <input type="text" placeholder="email" name="email" value={inputs.email} onChange={handleChange} />
        <br />
        <input type="text" placeholder="name" name="name" value={inputs.name} onChange={handleChange} />
        <br />
        <input type="text" placeholder="subject" name="subject" value={inputs.subject} onChange={handleChange} />
        <br />
        <textarea name="description" placeholder="tell us about your experience" value={inputs.description} onChange={handleChange} cols="30" rows="10"></textarea>
<br />
        <button>submit</button>
      </form>
```

It's time for us to add the axios post request to /sendtome route inside the  handleSubmit and configure the object so that everything is received properly. 

The new handleSubmit will look like this. 

```javascript
const handleSubmit = e => {
    e.preventDefault()
    //destructure from inputs 
    const {email,name,subject,description} = inputs
    axios.post('/sendtome', {
      //make an object to be handled from req.body on the backend. 
      email,
      name,
      subject,
      //change the name to represent text on the backend.
      text: description
    }) 
  }
```

Let's give it a try.

If you copied and pasted all the code snippets it will work.

There you have it. 

I'll be doing one on how to set up mailschimp to start your own news letter which gives much more beautiful emails than the plain text one you see here. 

If you know anyone that this could help or just want to support me as a fellow tech enthusiast, please share and follow my posts.