Send Emails from NodeJS, Nodemailer, and GMail API
Tags: email, javascript, webdev, tutorial
Published: 2024-04-13 10:31:32

## Introduction

Sending emails from NodeJS with [Nodemailer](https://www.nodemailer.com/) is easy. In this guide, we'll explore how to set up and use Nodemailer with Gmail APIs to send emails effortlessly.

## Essentials

1. A `MERN` stack or a `NextJS` app.
2. A verified Google account that can use Google Developer features.
3. This guide demonstrates using typescript, but the same thing can be built in JavaScript just by removing type declarations.

## Google Application Setup

1. Go to [Google Cloud Console](https://console.cloud.google.com).
 
 ![Cloud Console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mx13grrwi8srrki1nged.png)
   
2. Click on create a new project.

![Create Project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/meksusep4oqm0z09m1k5.png)

3. Select the organization and click on Create Project.
4. Select the recently made project from the above corner.
5. Go to `APIs and Services` and select `Enabled APIs and Services` from the left panel.
6. Search for Gmail API and enable it.


![GMail API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/myycm3949i4pb1g3p3r3.png)

7. Go to the Credentials Screen from the left bar, and click on the `Configure Consent` button.


![Configure Consent Screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1y14qorlr9wyiosxum3.png)

8. Select the Internal user type
9. Fill in the required details.
10. Make sure that you have a `png` of your `120x120` logo.
11. Add the scope for sending emails on your behalf: `auth/gmail.send`
12. In the next screen, click Create and click on Go to Dashboard
   

![Configure Consent](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4v972mmukcg7dv7j30w3.png)
   
13. In credentials screening, click on Create credentials.
14. Select a web application.
  

![OAuth credentials](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0o2qte40ddf8jwosl6l1.png)
  
15. Enter the details.
16. Make sure to add the deployment link and [localhost](http://localhost:3000) link in URIs.
17. For redirect URIs, make sure to add [Google OAuthPlayground](https://developers.google.com/oauthplayground)
18. Click on Create


![Create Credentials](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hodiccpwxl6k1b6kdiyn.png)

19. Make sure to download the JSON for the credentials.
20. Now go to the [Google OAuthPlayground](https://developers.google.com/oauthplayground)
21. In the top right, press the gear icon and check the `Use your own OAuth credentials` button.
22. Paste the client ID and secret in it.
23. Now search for https://mail.google.com in the left search and after selecting that, click on Authorize APIs.
24. Allow the application to access.
25. After redirecting back to the playground, select the `Exchange authorization code for tokens` button.
26. Copy the refresh token for later.


![OAuth Playground](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9oc6zq3uhp6oad3192s.png)

## Writing the code

Install `nodemailer` and `googleapis` packages.
**Note:** While working with typescript, don't forget to install `@types/nodemailer` package too.
Export the credentials stored in `.env` file.

```shell
GOOGLE_CLIENT_ID="your client id"
GOOGLE_CLIENT_SECRET="your client secret"
GOOGLE_REFRESH_TOKEN="your refresh token"
GOOGLE_REDIRECT_URI="https://developers.google.com/oauthplayground"
GOOGLE_EMAIL="your email"
```

```typescript
type GOOGLE_MAIL_SERVICE_KEYS = 
	| "clientId"
	| "clientSecret"
	| "refreshToken"
	| "redirectUri"
	| "email";

export const googleEmailConfig: Record<GOOGLE_MAIL_SERVICE_KEYS, string> = {
	clientId: process.env.GOOGLE_CLIENT_ID || "",
	clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
	refreshToken: process.env.GOOGLE_REFRESH_TOKEN || "",
	redirectUri: process.env.GOOGLE_REDIRECT_URI || "",
	email: process.env.GOOGLE_EMAIL || "",
};
```

### Configuring OAuth client

Create a file `services/gauth.ts` and export the `OAuthClient` from it.

```typescript
import { google } from "googleapis";

const OAuth2 = google.auth.OAuth2;
const id = googleEmailConfig.clientId;
const secret = googleEmailConfig.clientSecret;

const myOAuth2Client = new OAuth2(id, secret);
export default myOAuth2Client;
```

### Creating email service

Create a service (`services/email.ts`) for sending email by configuring SMTP transport with Nodemailer, OAuth client, and your application's configurations.

1. Get the access token from your OAuth client after providing the refresh token.
2. Use the `createTransport` service from `nodemailer` to create your SMTP transport with your Google config.
3. Create an object with `from`, `to`, the `subject` of the mail, and the body of the mail as HTML.
4. Use the `smtpTransport` to send the mail.

```typescript
import { createTransport } from "nodemailer";

export const sendEmailService = async (
	to: string,
	subject: string,
	html: string
) => {
	try {
		myOAuth2Client.setCredentials({
			refresh_token: googleEmailConfig.refreshToken,
		});
		const accessToken = await myOAuth2Client.getAccessToken();
		const transportOptions: any = {
			service: "gmail",
			auth: {
				type: "OAuth2",
				user: googleEmailConfig.email,
				clientId: googleEmailConfig.clientId,
				refreshToken: googleEmailConfig.refreshToken,
				accessToken: accessToken.token,
			},
		};
		const smtpTransport = createTransport(transportOptions);
		const mailOptions = {
			from: {
				name: "Your application name",
				address: googleEmailConfig.email,
			},
			to,
			subject,
			html,
		};
		await smtpTransport.sendMail(mailOptions);
	} catch (error: any) {
		console.error(error);
	}
};
```

Create a utility (`utils/email.ts`) for sending emails with this `sendEmailService`.

```typescript
export const getEmailHTML = (title: string, subtitle: string): string => `<html>
<head>
	<title>${title}</title>
</head>
<body>
	<h1>${title}</h1>
	<p>${subtitle}</p>
</body>
</html>`;

export const sendEmail = async (to: string, subject: string) => {
	const html = getEmailHTML(subject, "This is a test email");
	await sendEmailService(to, subject, html);
};
```

That's it, your email service is configured successfully.

### Testing out

Create a temporary API route and call a controller with another email to check this route.

1. Add the recipient email, in this case, your email (different from the email with which you configured the mailing service).
2. Use the `sendMail` utility with this email and a test subject to send the email.

```typescript
export const sendMailApi = async (req: NextApiRequest, res: NextApiResponse) => {
	try {
		const to = "test@example.com";
		const subject = "Test email";
		await sendEmail(to, subject);
		return res.status(200).json({ message: "Email sent successfully" });
	} catch (error) {
		console.error();
		return res.status(500).json({ error: RESPONSE_MESSAGES.SERVER_ERROR });
	}
};
```

Call this into your API route and test it by hitting the route.

If you are using `ExpressJS`:

```typescript
router.get("/api/v1/email", sendMailApi);
```

For NextJS API routes:

```typescript
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";

const handler: NextApiHandler = async (
	req: NextApiRequest, 
	res: NextApiResponse
) => {
	if (req.method === "GET") {
		return sendMailApi(req, res);
	}
	return res
		.status(405)
		.json({ message: `Method ${method} Not Allowed` });
};

export default handler;
```
## Conclusion

This article demonstrates the use of Google Mailing service and Nodemailer.

Questions and feedback are most welcome.  😊