I created my own email server to send emails into my gmail for My Portfolio
Tags: nodemailer, express, cors, gmail
Published: 2021-11-28 02:45:23

I have my portfolio here at [My Portfolio](https://tranminhtri.com/). Date after date, there are peoples send message to me through the contact form.

Initially, I used emailJS to handle sending mails to my gmail for a peace of mind. But their free tier is quite low, only allow 200 requests per months. So I decided to create my own server to send mails to mine gmail so I can have better flexibility and control over it.

This is also a guide on how to use nodemailer to send mail to gmail. There are many things need to sort out before you can use nodemailer to make it works well with gmail. I hope this guide can help you ( and also help myself in the future if I need it 😉 ).

# 1/ Install Packages and set up basic express App

You need to do a `npm init` first then just go along with default configuration

We need a few packages to make sure our server works : 
```
npm install express nodemailer nodemailer-smtp-transport dotenv cors
```
and 
```
npm install --save-dev nodemon
```

Your package.json should look like this now :
```
{
  "name": "my-portfolio-server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon ./index.js",
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "dotenv": "^10.0.0",
    "express": "^4.17.1",
    "nodemailer": "^6.7.2",
    "nodemailer-smtp-transport": "^2.7.4"
  },
  "devDependencies": {
    "nodemon": "^2.0.15"
  }
}
```

I will explain why we need each of them : 
- cors : to resolve CORS when you send a request from your website to this server
- dotenv : to use environment variables in your server
- express : to set up an Express app
- nodemailer and nodemailer-smtp-transport : to send mails to gmail
- nodemon : to test your local server app live

# 2/ Set up local config :
Now you need to create a `.env` file and `.gitignore` file.

We will get to `git` first. You may need to do a `git init` then push your current project on an existing branch ( in my case it's Github ) We will need that so later you can deploy it to Heroku ( I used Heroku but if you don't feel free to skip the deployment step and do it on yourown )

In your `.env` file, make sure they have these : 
```
MY_GMAIL={Your Gmail here}
MY_GMAIL_PASSWORD={Your Gmail Password}
```

Then in your `.gitignore`, also make sure they look like this :
```
.env
node_modules/
```

You don't want to push your credentials to Github to the public. So that's why we need `.gitignore` and also we need credentials of your own gmail so we can use it later to send mails using nodemailer.

# 3/ Set up your gmail account to make sure nodemailer works : 

Log into your Gmail Account then click on this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t0yollvwzub0yd9thgvh.PNG)

You need to enable `less secure app access` and `display unlock captcha` for your gmail account [https://accounts.google.com/b/0/DisplayUnlockCaptcha](https://accounts.google.com/b/0/DisplayUnlockCaptcha)

Then you have to follow this 6 steps at [https://support.google.com/accounts/answer/185833?hl=en](https://support.google.com/accounts/answer/185833?hl=en) to get the password that you can put it in `.env` file or this won't work

I know it's a lengthy process. But trust me, I have to go through my StackOverflow issues and answers to leave them here for you so you can have a peace of mind. Nodemailer doesn't work well with Gmail but once you have set them up, you are good to go for life.

Now you have set up both your gmail config and local config. We can start writting our server.

# 4/ Build out your server 

I just gonna throw them here just because they only have a file and one endpoint. 

```
const express = require('express')
const nodemailer = require('nodemailer');
const smtpTransport = require('nodemailer-smtp-transport');
const cors = require('cors');

// This makes .env file work
require('dotenv').config();

// Env Variables
// You may not see 'PORT' mentioned in .env file above because this is used for HEROKU deployment only
const PORT = process.env.PORT;
const MY_GMAIL = process.env.MY_GMAIL;
const MY_GMAIL_PASSWORD = process.env.MY_GMAIL_PASSWORD;

const app = express()
const port =  PORT || 5000;

// You need this so when you send a request from frontend with a different url like https://tranminhtri.com it won't throw CORS errors
app.use(cors());

// You can choose different endpoint like /email, /mail or anything
app.post('/sendMessage', (req, res) => {
    // I used `name`, `email`, `message` for my Form so I extract them here, feel free to expand them as you need
    const { name, email, message } = req.query;

    const transporter = nodemailer.createTransport(smtpTransport({
        service: 'gmail',
        host: 'smtp.gmail.com',
        auth: {
          user: MY_GMAIL,
          pass: MY_GMAIL_PASSWORD
        }
    }));

    const mailOptions = {
        from: email,
        to: MY_GMAIL,
        subject: `A Message from ${email} (My Portfolio)`,
        text: `
        Email: ${email}

        Name: ${name}

        Message: ${message}
        `
    };
      transporter.sendMail(mailOptions, (error, info) => {
        if (error) {
          console.log(error);
        } else {
          console.log('Email sent: ' + info.response);
        }
      });
      
    res.status(200).send('Send email successfully');
});

app.listen(port, () => {
  console.log(`Example app listening at ${port}`)
})
```

The file need to be named `index.js` just for deployment later on, as mentioned in package.json it's `nodemon ./index.js` as well.

Your file structure should look like this :

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rsqg23bhonqw14xc5ywi.PNG)

The idea behind this is simple, built and endpoint that will take whatever data coming from the frontend and pass them into nodemailer so they will be directed to your gmail. 

The whole part from `transporter `, `mailOptions ` and `transporter.sendMail` is just syntax so if you want to know more feel free to visit [https://nodemailer.com/usage/](https://nodemailer.com/usage/) and [https://nodemailer.com/message/](https://nodemailer.com/message/)

The Source code for the whole server is here if you need to compare code line by line : [https://github.com/Tris-909/My-Portfolio-Server](https://github.com/Tris-909/My-Portfolio-Server)

# 5/ Local test :
You can run 
```
npm start
```
to start your local development 

If you hit the endpoint with a post request like a screen shoot below, it should send a mail to your gmail account : 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/og4a4lwi4t216jzfmhaa.PNG)

Now everything is working fine locally. You can deploy it then integrate it with your websites.

# 6/ Deployment Heroku ( Optional ) :
Different platform have different ways to deploy an app or a server. I used Heroku because it's quick and easy and generous for it free tier. But if you are using a different platform I can't really help you, you have to figure it out on your own.

There are gonna be a few steps through this, and this is quite prone to error so I hope you can stick with it ( Deployment always be a pain 🙂 )

- Step 1 : Create your own heroku account if you haven't gotten one yet
- Step 2 : Run `node -v` to get the version of your current nodejs env then add these to your package.json : 
```
  "engines": {
    "node": "16.13.0"
  }
```
Mine is 16.13.0 so I put it there
- Step 3 : Alter your `scripts` inside package.json to make heroku works :
```
  "scripts": {
    "start": "node ./index.js",
    "dev": "nodemon ./index.js"
  },
```
Heroku runs `npm start` behind the screen for deployment so you need to move your development script into something else like above.
- Step 4 : Install Heroku CLI and create your app through command line, You need to follow this [https://devcenter.heroku.com/articles/heroku-cli](https://devcenter.heroku.com/articles/heroku-cli) until step **Getting Started** to create your app on heroku

Now if you go to heroku dashboard, you will see your app like this, mine is `obscure-brook-87266` 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rl8avnxmbp1hjtv72x0k.PNG)

Now click on the project, and go to `Deploy` tab, then connect your app to your Github Account ( This is why I need you to commit and push it to Github at the start ) before you go to click `deploy`, go to `Settings` tab and click on `Reveal Config Vars`, you need to add env variables under the same name as your `.env` file.

After that you can go to `Deploy` and click on `Manual Deploy` to wait for your app to deploy. And then that's it. You are done.

Try to use POSTMAN again to test it out but replace your URL with the new URL provided by Heroku.

If you follow the whole guide till now everything should work as expected. It's not a smooth process for me I have to read a lot of StackOverflow issues and answers to figure it all out but I hope this will help you in some ways. 

Good bye and have a good day 😙