DEV Community

Cover image for Send Emails from NodeJS, Nodemailer, and GMail API
Akshat Mittal
Akshat Mittal

Posted on

Send Emails from NodeJS, Nodemailer, and GMail API

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"
Enter fullscreen mode Exit fullscreen mode
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 || "",
};
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
    }
};
Enter fullscreen mode Exit fullscreen mode

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);
};
Enter fullscreen mode Exit fullscreen mode

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 });
    }
};
Enter fullscreen mode Exit fullscreen mode

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

If you are using ExpressJS:

router.get("/api/v1/email", sendMailApi);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

Conclusion

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

Questions and feedback are most welcome.  😊

Top comments (1)

Collapse
 
jvarness profile image
Jake Varness

This is a really great way to add emailing to a website: I was doing this using the OAuth playground for some time. However, recently I learned that Google has the ability to create app passwords for an email account. If you have 2-Step Verification enabled on the email account you're sending from, you can use an app password without having to setup anything in Google Cloud!