Sending Emails From Your Firebase App with Nodemailer using Gmail as SMTP
Tags: firebase, node, googlecloud
Published: 2021-07-28 00:34:37

I was recently working on a Firebase [side project](https://dhera-gram.web.app/) where I needed to implement a feature that sends emails to users upon signing up, and I was astonished by how difficult it was to find the resources needed to aid the implementation. I then decided to document the steps I took for posterity's sake. If you are looking for a guide on how to integrate Nodemailer with your Firebase application, then this is the right one for you.

---

### What is Firebase?

If you've been following the world of software development for a while now, you will no doubt, have heard of Firebase. [Firebase](https://firebase.google.com/) is a Google-backed Backend-as-a-Service(BAAS) app development platform that provides hosted backend services such as authentication, hosting, storage and database solutions. You can describe it as an all-in-one backend solution for your apps.

### What is Nodemailer?

[Nodemailer](https://nodemailer.com/about/) is arguably the most popular emailing package for NodeJS. 
> Nodemailer is a module for Node.js applications to allow easy-as-cake email sending. 
It is very easy to settle and integrate into an existing project.

In this article, I'll show you how to integrate Nodemailer into your Firebase project with Cloud Functions. We will be setting up a 3-Legged authentication with OAuth and Gmail to obtain the access tokens needed by Nodemailer and then set those tokens as environment variables for use in our Firebase app and emulator.

---

### Requirements
* [NPM or NodeJS](https://nodejs.org/en/download/).
* A [Google](https://accounts.google.com/SignUp?hl=en) account (who doesn't have one these days?).
* Text editor of your choice (I use [VSCode](https://code.visualstudio.com/download) personally).

### The Setup
[Setting up Firebase](https://firebase.google.com/docs/web/setup) is a very easy process. All you need to do is [sign in to Firebase](https://console.firebase.google.com/) with an existing Google account and then follow the steps listed below;

* [Create a Firebase project](https://firebase.google.com/docs/web/setup#create-firebase-project)
* [Register your app with Firebase](https://firebase.google.com/docs/web/setup#register-app) or use an existing app on your console.
* Add the Firebase SDKs and initialize firebase.

I am working on an already created React app, so I already have a `package.json` file at the root of my project directory. This file contains all the dependencies and config needed for my application. If you don't have one already, run the following command on your terminal while in the project's root directory:

```shell
npm init
```

Next, we need to install the firebase NPM package:

```shell 
npm install --save firebase
```

Lastly, we must to import the required firebase modules into your app and then initialize the project:

```javascript
// Firebase App (the core Firebase SDK) is always required and must be listed first
import firebase from "firebase/app";


// Add the Firebase products that you want to use
import "firebase/auth";
import "firebase/firestore";


const firebaseConfig = {
  // ... paste the config values given when you created the Firebase project on the console.
};

// Initialize Firebase
firebase.initializeApp(firebaseConfig);
```

For this article, we will be requiring the [Firebase CLI](https://firebase.google.com/docs/cli#install_the_firebase_cli) for our [Cloud Functions](https://firebase.google.com/docs/functions) and [Firebase Emulators](https://firebase.google.com/docs/emulator-suite) setup. The Firebase CLI provides us with a set of tools to administer and manage our Firebase projects directly from the terminal. You can read more about that on the [Firebase documentation](https://firebase.google.com/docs/cli).

Before we carry on with the rest of this guide, we must first initialize Cloud Functions for Firebase. This provides us with a Node.js runtime environment required to run Nodemailer. To initialize functions in your Firebase project, run the command below in the root of your project's directory and follow the prompts in line with your project's specifications:

```shell
firebase init functions
```

This command creates a `functions` directory in the root of our project that holds files and modules necessary to write and deploy Cloud Functions successfully.
 
---

### Setting up a Google Cloud Project
The first step in our tasks is to set up a Google Cloud Project.

- Head over to your [Google Developer Console](https://console.cloud.google.com/) page. 
- On your dashboard, click on the dropdown icon on the menu. This opens up a pop-up window.

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

You can either use an existing project or create a new one. Since we already created a project on the Firebase console, we can access it by typing the name we gave to the project on the search bar.

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

---

### Getting OAuth Credentials
Next, we need to retrieve our project's OAuth credentials from the Google Cloud Platform page.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8darh21zfsy74zi5eepj.png)
- On the sidebar of the developer console, click the "APIs and services" menu.
- Then, click the "Credentials" option to go to the "Credentials" page. 

On the "Credentials" page, you will notice that we already have an OAuth 2.0 Client ID autogenerated for us by Google client. This was created when we created our Firebase project on the console. 
- Click on the "Web Client (auto-created by Google Service)" link to show the credentials. 
- Then, copy the Client ID and the Client secret from the list of credentials. These are required to set up the OAuth configuration.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aw25jnl2hv487nvsssc3.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4juwpshg8gktuif2r49.png)

---

### Getting OAuth Tokens
The easiest way to get the required OAuth tokens is to use the OAuth 2.0 playground.

- Head over to the [OAuth 2.0 playground](https://developers.google.com/oauthplayground) page.
- Click on the cog icon (⚙️) at the top right corner of the screen to display the interaction window. Then check the "Use your OAuth credentials" option. 
- Next, paste the Client secret and Client ID gotten from the Google Cloud Platform's "Credentials" page.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5kdmafeztr2bmqtj5394.png)

Now, we need to set the scope of the OAuth credentials by authorizing the Gmail API for our project:

- Head over to the "Select and authorize APIs" section on the left side of the screen. 
- Next, paste the Gmail link — `https://mail.google.com`— into the text field provided to authorize the Gmail API.

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

Then, click on the "Authorize APIs" button. This opens up a Google authentication prompt. 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/56vfb8oi909xf95p8txn.png)

Select the Google account in use and then authorize your app to access your Google account. 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d20cgz6a89kmxwf7yfbi.png)
Click on the "Advanced" button at the bottom.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9wqmzatetirb9l6cmju.png)
Click on the "Continue to project" button at the bottom and then grant the app access to your Google account.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lbjqrvki1yqrt43w0d12.png)

After completing the steps above, you will be redirected back to the OAuth playground. 
- Click on the "Exchange authorization code for tokens" button on the left-hand side of the screen.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7drpzp3txjbwqof7ck6x.png)

When the request completes, it will return an object on the "Response/Request" section of the screen that contains your *access token* and *refresh token*.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8btcmsdgwjdmvqviej37.png)

These values, along with the Client Secret and Client ID from the credentials page, make up our OAuth credentials needed for Nodemailer.

---

### Firebase Environment Variables
You will often need to set up additional environment configurations for your Firebase Functions. These can be third-party API keys, sensitive data, or, in our case, our OAuth credentials. The Firebase SDK for Cloud Functions offers a built-in environment configuration to make it easy to store and retrieve this type of data for your project.

Setting of environment variables in Firebase is done with the command 
```shell
firebase functions:config:set x.key="THE API KEY" x.id="THE CLIENT ID"
```

For this project, we need to set environment variables to store our access and refresh tokens; and our client secret and client ID.

We can do this by running the command in out terminal:

```shell 
firebase functions:config:set gmail.useremail="yourgoogleemail@gmail.com" gmail.clientid="yourclientid.apps.googleusercontent.com" gmail.refreshtoken="1//04zKnDTh1mXdLCgYI-yourrefreshtoken" gmail.clientsecret="mbFQnYOurCLienTSecREt"
```

> *Keep in mind that only lowercase characters are accepted as keys.* 

If your project is running with a Firebase emulator, you must retrieve your custom configuration variables to make them locally accessible. Depending on your operating system, run either of the following commands in the `functions` directory of your project:

For MacOS:
```shell 
firebase functions:config:get > .runtimeconfig.json
```

And for Windows
```shell
firebase functions:config:get | ac .runtimeconfig.json
```

---

### Accessing environment variables on Firebase 
In Firebase, defined environment variables are made available to functions via `functions.config()`. We can access them within our application by following the following syntax:

```javascript
functions.config().envKey.envValue
```

We can destructure these values in our `index.js` file to make it more readable:

```javascript
let { useremail, refreshtoken, clientid, clientsecret } = functions.config().gmail;
```

---

### Installing and Configuring Nodemailer
For this part of the tutorial, you will need to install Nodemailer if you haven't already. To install Nodemailer, run the code below on the terminal within your project's `functions` directory :

```shell
npm install nodemailer
```

Then, copy the code below and paste in your `index.js` file within your `functions` folder:

 ```javascript
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const nodemailer = require("nodemailer");

admin.initializeApp();

/** defining and destructuring environments config for firebase functions */
let { useremail, refreshtoken, clientid, clientsecret } =
	functions.config().gmail;

/**create reusable transporter object using the gmail SMTP transport */
let transporter = nodemailer.createTransport({
	host: "smtp.gmail.com",
	port: 465,
	secure: true,
	auth: {
		type: "OAuth2",
		user: useremail,
		clientId: clientid,
		clientSecret: clientsecret,
		refreshToken: refreshtoken,
	},
});


//our firebase cloud function
exports.userCreate = functions.auth.user().onDelete((user) => {

	// TODO: Replace the `from`, `html` and `subject` values
	const mailOptions = {
		from: "okekechidera97@gmail.com",
		to: user.email,
		subject: "Thanks for Signing up",
		html: `<div
		Hey, I am an HTML template
	</div>`,
		
	};

// send mail with defined transport object
return transporter.sendMail(mailOptions).catch((err)=>{
		console.log(err);
	});
});
```

The code above illustrates a Firebase Auth triggered function that uses Nodemailer to send emails to new users upon signup. Edit the `from`, `subject`, and `html` values in the `mailOptions` object to suit your needs. However, all Cloud Functions must be deployed before usage; therefore, we must deploy our newly created function. To deploy a Cloud Function, run the command below in the terminal:

```shell
firebase deploy --only functions
```

This command bundles all the Cloud Functions code contained in the `index.js` file and deploys them to the Cloud Functions runtime.

---

### Conclusion
We just discussed how to integrate and send emails with Nodemailer in a Firebase project; I hope you found it useful. Thanks for taking the time to read this. 
This article is my first attempt at technical writing; I appreciate any feedback you might have.

The project that inspired this article is available [here](https://dhera-gram.web.app/).