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
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
You need to enable less secure app access
and display unlock captcha
for your gmail account 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 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 :
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/ and 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
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 :
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 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
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 😙
Top comments (3)
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.
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.
:) 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.