DEV Community

Cover image for I created my own email server to send emails into my gmail for My Portfolio
Tran Minh Tri
Tran Minh Tri

Posted on

I created my own email server to send emails into my gmail for My Portfolio

I have my portfolio here at My Portfolio. 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
Enter fullscreen mode Exit fullscreen mode


npm install --save-dev nodemon
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

Then in your .gitignore, also make sure they look like this :

Enter fullscreen mode Exit fullscreen mode

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

You need to enable less secure app access and display unlock captcha for your gmail account

Then you have to follow this 6 steps at 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

// 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 app = express()
const port =  PORT || 5000;

// You need this so when you send a request from frontend with a different url like it won't throw CORS errors

// You can choose different endpoint like /email, /mail or anything'/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: '',
        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) {
        } else {
          console.log('Email sent: ' + info.response);

    res.status(200).send('Send email successfully');

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

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

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 and

The Source code for the whole server is here if you need to compare code line by line :

5/ Local test :

You can run

npm start
Enter fullscreen mode Exit fullscreen mode

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

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Heroku runs npm start behind the screen for deployment so you need to move your development script into something else like above.

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

Image description

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 😙

Discussion (3)

xr0master profile image
Sergey Khomushin

Nice job, but your reasons cannot be taken seriously.

To be honest, you removed the protection of your Google account, spent a few days on a simple implementation, which is quite expensive in terms of salary. You need to maintain your code and so on.

It will be much cheaper to buy a paid subscription with a higher quota.

tris909 profile image
Tran Minh Tri Author • Edited on

I spent a few hours actually and it could work forever ( at least in a very long time that I can forget about it ) and it still works so I don't think there is anything to worry about. Also paying for something you can easily build out just bad. Like why would you ? and the most important thing about this is how to make nodemailer to work with Gmail which is notorious for it hassles.

If I can pay for something and I don't have to do it honestly speaking, I will never code. Like there always products out there that you can pay that easily already has been invested thousand of development hours. Why would I ever code again.

xr0master profile image
Sergey Khomushin

:) You contradict yourself.
In any case, this is everyone's choice, and I have nothing to add to what has already been said. I drew attention to this post only because of the advice to disable protection in order to warn readers how risky it is.

Good luck.