How to create a Node bot that sends happy emails throughout the year
Tags: javascript, webdev, programming, tutorial
Published: 2021-11-08 21:08:18

In this tutorial, I will show you how to make your very own email bot using Node, Express, [Nodemailer](https://nodemailer.com/about/) and [node-cron](https://www.npmjs.com/package/node-cron).  

You will learn how to program the bot to send emails throughout the day to friends and family. You will also learn how to send messages for specific dates like a friend's birthday.

## Prerequisites
It would help to have basic working knowledge of JavaScript.   

## Checking to make sure Node is installed
Before we can get started writing code, we need to first check and see if Node is installed on the computer.

If you are using a Mac, then open up the Terminal app.
If you are using Windows, then open up the Command Prompt. 

In the command line, run `node -v`. If installed, it will come back with a version number like `v16.10.0`.

If it is not installed, then you can install Node from the [website](https://nodejs.org/en/download/).

## Creating the project folder
First, go to the location where you want to add the folder. I am going to choose the Desktop as my location.

In the command line, use the `cd` command to change directory.
```
cd Desktop
```
Then use the `mkdir` command to create a new folder in that directory. I am going to name our project `email-bot`. 
```
mkdir email-bot
```
You should see the new folder show up in the computer. 
![project folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sv2q5vdt2dwgcauy9fq3.png)

We will use the `cd` command again to change directories into the `email-bot` folder.
```
 cd email-bot
```
In the command line, you should see that we have successfully changed to the `email-bot` folder.

![email bot folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jql9msbymwkl97ag0cnc.png)

## Creating the package.json file
A `package.json` file contains a lot of important information for our project including name, version, scripts and dependencies.  


Run the command `npm init --yes` or `npm init --y`. That will create a default `package.json` file that you can modify later.

This is what the default `package.json` file will look like.
![default package json](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wlv6co8cpp3v469e2h1e.png)


## Creating the server.js file
This file will contain the bulk of our logic for sending emails. 

In the command line, use the `touch` command to add a `server.js` file. 

```
touch server.js
``` 
## Creating an .env file
The `.env` file will contain all of the information for the email addresses. 

This is a special type of file that contains sensitive information that you don't want getting into the wrong hands. 

That is why it is important to never commit your `.env` file to GitHub.

In the command line, run `touch .env`.
```
touch .env
```
## Creating a .gitignore file
In this file, you will list out the names of files and folder you want Git to ignore when pushing your changes to GitHub. 

Later on, we will be adding the `.env` file to our `.gitignore`.

To add a `.gitignore` file, run the command `touch .gitignore`.
```
touch .gitignore
```

## Installing Express, Nodemailer, dotenv and node-cron
Express is a framework that is used with Node to help create server-side apps.

The `dotenv` package, is used to load our environment variables into the `server.js` file. Our environment variables will be the email addresses from the `.env` file.

[Nodemailer](https://nodemailer.com/about/) will be used to send the emails.

The [node-cron](https://www.npmjs.com/package/node-cron) package, will be used to schedule the dates and times for the email delivery. 

In the command line, we can install all of these packages at once. 

Run this command in the command line.

```
npm i express nodemailer node-cron dotenv
```

Now it is time to move to the code editor and start coding. I will be using Visual Studio Code, but you are free to use another code editor.

Open up the project in your editor and check to make sure you have all of the files we created.
![folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/np8lblhme2d8lywjzuvd.png)
 

The `package-lock.json` file and `node_modules` folder were created when we installed the packages.

## Adding to the .gitignore file
You don't want to push the `node_modules` folder to GitHub because it is a really large folder with many files and subfolders.


You also don't want to push your `.env` file to GitHub because it contains very sensitive information that you want to keep hidden. 

Open up the `.gitignore` file and add the `node_modules` folder and `.env` file.

I am also going to add the `.DS_Store` to the `.gitignore` file. This `.DS_Store` file was created when we created the `email-bot` folder.

This is what your `.gitignore` file should look like.

```
.env
node_modules/
**/.DS_Store
```
## Adding the environment variables to the .env file
The first variable we are going to add is for the port number. The number we will use is 3000.

When naming environment variables, it is common practice to use all caps and underscores to separate words. 

```
PORT = 3000
```
The next variable will be for our personal email address.

```
PERSONAL_EMAIL = your personal email address goes here
```
Then we will add the password for our personal email address.

```
EMAIL_PASSWORD = your personal email password goes here
```
The last variable will be the email address we want to send messages to.

```
FRIEND_EMAIL = friend's email address will go here
```
This is what your `.env` file should look like.
```
PORT = 3000
PERSONAL_EMAIL = your personal email address goes here
EMAIL_PASSWORD = your personal email password goes here
FRIEND_EMAIL = friend's email address will go here
```

## Adding the dotenv module to the server.js
If you want to load modules into your file, then you will need to use the `require()` function.

This is the code to load the dotenv module into the server.js file and configure it.

```js
require('dotenv').config();
```
## Loading the environment variables into the server.js
We now need to load all of the variables from the `.env` file into the `server.js` file. 

To load the variables, we have to use `process.env` followed by the name of the variable.

This is what the code looks like for the `PORT` variable.
```
process.env.PORT
```
This is what the code will look like when we add all of the environment variables to the `server.js` file

```js
require('dotenv').config();
const port = process.env.PORT || 3000;
const personalEmail = process.env.PERSONAL_EMAIL;
const emailPassword = process.env.EMAIL_PASSWORD;
const friendEmail = process.env.FRIEND_EMAIL;
```
For the port variable, it is common to add a  logical OR (||) operator followed by the number for the port. 

The reason why we do this is because if our `process.env.PORT` doesn't work, then we tell the computer to use 3000. 

## Creating an Express server
We first have to add express to our server.js file.

```js
const express = require('express');
```
Then we create a new express application.
```js
const app = express();
```
Then we use the `listen()` method which listens for connections on a given port. 

The `listen()` method will take in a port number and a callback function.

Our callback function will return a `console.log` which displays the message "The server has started at http://localhost:3000".

```js
app.listen(port, () => {
    console.log(`The server has started at http://localhost:${port}`)
});
```
## Starting the server
Before we start the server, we will be adding one more package called [nodemon](https://www.npmjs.com/package/nodemon).

The nodemon package detects changes made to the file and will automatically restart the server for us.

In the command line for the project folder, run `npm i nodemon`.
```
npm i nodemon
```
In the `package.json` file under the `scripts`, change the `"tests"` to `"start"`. Then change the `"echo \"Error: no test specified\" && exit 1"` to `"nodemon server.js"`.

```js
  "scripts": {
    "start": "nodemon server.js"
  },
```

Go back to the command line, and run `npm start`.
You should see this result.
![start server](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iyts7b3wuo5zf2t5kyt1.png)

To stop the server, press `Ctrl-C` on your keyboard.

## Creating the email messages
For our bot, we will create two different messages. One good morning message and one Happy Birthday message.

Inside the `server.js` file, create a variable called `morningMsg` and assign the string `"Good morning! Hope you have a beautiful day!"`

```js
const morningMsg = "Good morning! Hope you have a beautiful day!";
```
We will then create a `birthdayMsg` and assign the string `"Happy Birthday! You rock!!!!"`

```js
const birthdayMsg = "Happy Birthday! You rock!!!!";
```

## Creating the message objects
We will create two message objects which contain the information for the email sender, receiver, subject line and message.

This is what the code looks like for the good morning message.
```js
let sendMorningMsg = {
    from: personalEmail,
    to: personalEmail,
    subject: "It's a beautiful morning",
    text: morningMsg
};
```
This is what the code looks like for the birthday message.
```js
let sendBirthdayMsg = {
    from: personalEmail,
    to: personalEmail,
    subject: "Hooray it's your Birthday",
    text: birthdayMsg
};
```
For now, the messages will be sent to our personal email address since we are still just testing everything.

When we are finished, we can change the `to` field to have the friend's email address.

## Creating the transporter
The transporter in nodemailer is responsible for sending our messages from our email account.

**Please note:**
If you are using Gmail, there are extra steps required for setup because of the authentication and security with Google. 

To setup your Gmail account with Nodemailer, please read through [this detailed tutorial](https://www.freecodecamp.org/news/use-nodemailer-to-send-emails-from-your-node-js-server/).

If you are not using Gmail, then follow along with these steps.

The first step is to add Nodemailer to the server.js file.
You can add it with the rest of the imports at the top of the page.

```js
const nodeMailer = require('nodemailer');
```
We will then use the `createTransport()` method to add all of our information for the email provider. 

```js
let transporter = nodeMailer.createTransport({
    service: 'outlook',
    port: 587,
    secure: false,
    auth: {
        user: personalEmail,
        pass: emailPassword
    }
});
```
## Verify the email address
We can add a condition to test if there was an error connecting to our email address.

I am going to use a ternary operator to check for an error.

```js
transporter.verify((error) => {
    error ? console.log(`There was an error for the email connection: ${error}`) : console.log('Ready to send email')
});
```
## Testing the email function
Let's test out sending an email using the good morning message.

We will first create an async function called `morningMessage`. Inside that function we will use the `sendMail` function to send the good morning message.

We are also going to log a success message along with the `messageId` inside the function.

We will then call the `morningMessage` function and add a catch for errors.

This is what the complete code looks like.
```js
async function morningMessage() {
    let info = await transporter.sendMail(sendMorningMsg)
    console.log(`Message send: ${info.messageId}`)
}
morningMessage().catch(console.error);
```
Now, let's go to the command line and start our server using `npm start`. 

Log into your email provider, and you should see the message in the inbox.

![email message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q7mqrt1oubj82okumgpp.png)
 
 
If you see this message in the console, `There was an error for the email connection`, then that means you need to check the transporter object or the values for your email address and password.

If everything checks out, you can stop the server.

## Adding node-cron to send emails in the morning
We first have to add the [node-cron](https://www.npmjs.com/package/node-cron) module to our `server.js` file. You can add it to the rest of the modules at the top of the page.

```js
const nodeCron = require('node-cron');
```
Go back to our code for the `morningMessage` function and place that inside a node-cron schedule function.

The `schedule()` function takes in a string representation for the scheduled times and a call back function.

```js
nodeCron.schedule("* * * * *", () => {
    async function morningMessage() {
        let info = await transporter.sendMail(sendMorningMsg)
        console.log(`Message send: ${info.messageId}`)
    }
    morningMessage().catch(console.error);
});
```

To better understand this syntax, `"* * * * *"` let's take a look at this diagram.

```js
 # ┌────────────── second (optional)
 # │ ┌──────────── minute
 # │ │ ┌────────── hour
 # │ │ │ ┌──────── day of month
 # │ │ │ │ ┌────── month
 # │ │ │ │ │ ┌──── day of week
 # │ │ │ │ │ │
 # │ │ │ │ │ │
 # * * * * * *
```
There are a total of six `*` you can use.
The first one is optional and represents seconds.

For example, if you wanted your message to be sent every minute, then you would use `* * * * *`.

Go ahead and try to test that and see if your message is sent every minute. Run `npm start` in the command line, and you should see your message show up in your inbox. 

Then stop the server. 

If you want your message to be sent every two minutes then you would use `*/2 * * * *`.

For the morning message, we want to schedule a message to be sent every morning at 9am.

This is the syntax for the scheduled time `"0 9 * * *"`.

The node-cron module uses military time. We are using the number 9 to represent 9am. 

Here is the complete code.

```js
nodeCron.schedule("0 9 * * *", () => {
    async function morningMessage() {
        let info = await transporter.sendMail(sendMorningMsg)
        console.log(`Message send: ${info.messageId}`)
    }
    morningMessage().catch(console.error);
});
```

## Using node-cron to send birthday messages
Underneath the schedule for the `morningMessage`, create a new schedule for the birthday message.

```js
nodeCron.schedule("* * * * *", () => {
    async function birthdayMessage() {
        let info = await transporter.sendMail(sendBirthdayMsg)
        console.log(`Message send: ${info.messageId}`)
    }
    birthdayMessage().catch(console.error);
});
```
For the schedule, we want to see a message once a year on a friends birthday at 11am.

For example, this is the syntax if your friends birthday is April 17th. 
```js
"0 11 17 April *"
```
That will send once a year on their birthday.

This is what the full birthday message looks like.
```js
nodeCron.schedule("0 11 17 April *", () => {
    async function birthdayMessage() {
        let info = await transporter.sendMail(sendBirthdayMsg)
        console.log(`Message send: ${info.messageId}`)
    }
    birthdayMessage().catch(console.error);
});
```
## Changing the recipient field in the message objects
When you are finished testing your bot, remember to change the `to` field to include your friend's email instead of your own.

```js
to: friendEmail,
```
To test it out, make sure to start your local server a few minutes before the scheduled morning time.

Then check in with your friend to see if they received it. 
You can also add a `cc` field to the message object, so you get a copy of the email as well.

```js
cc: personalEmail,
```

## Final code
This is the complete code for our `server.js` file.

```js
//imports for the env variables and packages
require('dotenv').config();
const port = process.env.PORT || 3000;
const personalEmail = process.env.PERSONAL_EMAIL;
const emailPassword = process.env.EMAIL_PASSWORD;
const friendEmail = process.env.FRIEND_EMAIL;
const express = require('express');
const app = express();
const nodeMailer = require('nodemailer');
const nodeCron = require('node-cron');

//messages for bot
const morningMsg = "Good morning! Hope you have a beautiful day!";
const birthdayMsg = "Happy Birthday! You rock!!!!";

//message objects
let sendMorningMsg = {
    from: personalEmail,
    to: friendEmail,
    cc: personalEmail,
    subject: "It's a beautiful morning",
    text: morningMsg
};

let sendBirthdayMsg = {
    from: personalEmail,
    to: friendEmail,
    cc: personalEmail,
    subject: "Hooray it's your Birthday",
    text: birthdayMsg
};

//transporter to send emails from our account 
let transporter = nodeMailer.createTransport({
    service: 'outlook',
    port: 587,
    secure: false,
    auth: {
        user: personalEmail,
        pass: emailPassword
    }
});


//verifies a proper email connection 
transporter.verify((error) => {
    error ? console.log(`There was an error for the email connection: ${error}`) : console.log('Ready to send email')
});


//sends a morning message to our friend at 9am everyday
nodeCron.schedule("0 9 * * *", () => {
    async function morningMessage() {
        let info = await transporter.sendMail(sendMorningMsg)
        console.log(`Message send: ${info.messageId}`)
    }
    morningMessage().catch(console.error);
});

// sends a message once a year to our friend on their birthday 
nodeCron.schedule("0 11 17 April *", () => {
    async function birthdayMessage() {
        let info = await transporter.sendMail(sendBirthdayMsg)
        console.log(`Message send: ${info.messageId}`)
    }
    birthdayMessage().catch(console.error);
});

//listens for connections 
app.listen(port, () => {
    console.log(`The server has started at http://localhost:${port}`)
});

``` 
Thank you so much for making it to the end of the tutorial. :smile:

To learn more about the features for node-cron, please visit the [documentation](https://www.npmjs.com/package/node-cron).

To learn more about the features for Nodemailer, please visit the [documentation](https://nodemailer.com/about/)

[Nodemailer Project GitHub Repo](https://github.com/jdwilkin4/Nodemailer-bot-tutorial/blob/main/README.md)

Happy coding!