Send Emails from NodeJS, Nodemailer, and GMail API

Akshat MittalAkshat Mittal
5 min read

Introduction

Sending emails from NodeJS with Nodemailer 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.

Cloud Console

  1. Click on create a new project.

Create Project

  1. Select the organization and click on Create Project.

  2. Select the recently made project from the above corner.

  3. Go to APIs and Services and select Enabled APIs and Services from the left panel.

  4. Search for Gmail API and enable it.

GMail API

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

Configure Consent Screen

  1. Select the Internal user type

  2. Fill in the required details.

  3. Make sure that you have a png of your 120x120 logo.

  4. Add the scope for sending emails on your behalf: auth/gmail.send

  5. In the next screen, click Create and click on Go to Dashboard

Configure Consent

  1. In credentials screening, click on Create credentials.

  2. Select a web application.

OAuth credentials

  1. Enter the details.

  2. Make sure to add the deployment link and localhost link in URIs.

  3. For redirect URIs, make sure to add Google OAuthPlayground

  4. Click on Create

Create Credentials

  1. Make sure to download the JSON for the credentials.

  2. Now go to the Google OAuthPlayground

  3. In the top right, press the gear icon and check the Use your own OAuth credentials button.

  4. Paste the client ID and secret in it.

  5. Now search for https://mail.google.com in the left search and after selecting that, click on Authorize APIs.

  6. Allow the application to access.

  7. After redirecting back to the playground, select the Exchange authorization code for tokens button.

  8. Copy the refresh token for later.

OAuth Playground

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.

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"
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.

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.

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.

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.

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:

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

For NextJS API routes:

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. ๐Ÿ˜Š

0
Subscribe to my newsletter

Read articles from Akshat Mittal directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Akshat Mittal
Akshat Mittal

Passionate about building functional and beautiful web applications that solve real-world problems. I have experience working with various technologies, such as MERN stack, TypeScript, Next.js, Python, and many others.