How to send email with Gmail API and Node.js

Create a Google Cloud Project

This tutorial explains how you can send email from your own Google account using Gmail API and Nodemailer without any UI.

In a previous tutorial, we used a service account to connect to the Google Drive API from a Node.js application. We cannot use a service account to impersonate a Gmail account, but we can use the GMail API with Node.js and Nodemailer to send email from the user’s own Gmail or Google Workspace account.

However you can use external services, such as Amazon’s session or Twilio’s sendgridTo send emails from a service account.

In this tutorial, we will describe how to send email from Gmail account using GMail API and Node.js application. Please note that Gmail implements a sending limit Total limit of 10,000 recipients per day with a total limit of 2,000 messages per day. The email quota is reset automatically at midnight Pacific Time.

1. Create a Google Cloud Project

go for cloud.google.com And create a new Google Cloud Project. Give your project a name, change the project id and click Create switch.


Create a Google Cloud Project

2. Enable Google API

choosing APIs & Services Click on More from the left menu Enable APIs and Services To enable Gmail API. The Gmail API lets you view and manage Gmail mailbox data such as threads, messages, and labels.


Gmail API

Under APIs and Services section, click on OAuth Consent Screen and set the user type as Internal, This will allow the application to access the Gmail API without going through the extensive OAuth verification process that can take several weeks. click on Save and Continue,


OAuth consent screen

4. OAuth 2.0 Workspace

On the consent screen, enter a name for your application and provide your email address where Google can contact you if there are any changes to the consent screen.

On the next screen, you must provide one or more OAuth 2.0 scopes for the Google API. press Add Or Remove Scopes add more button https://www.googleapis.com/auth/gmail.send In the list of scopes because we only want to send email from gmail and don’t want to read any user data. Click Save and Continue,


Gmail API Scopes

4. Create Gmail OAuth Client

in APIs & Services section, click on Credentials and click Create credentials , OAuth Client Id To create a new Client ID that will be used to identify your application on Google’s OAuth servers.


Create OAuth Client ID

4. Application Type

set application type Desktop AppGive your OAuth client a recognizable name and then click Create To generate credentials. The name of your OAuth 2.0 client is only used to identify the client in Google Cloud Console and will not be shown to application users.


node application type

press Download JSON button to download the credentials to your computer. It is recommended that you use node environment variables to store your credentials and do not send this file to your github repository.


OAuth Client ID

{
  "installed": {
    "client_id": "4181097263-eqfdl92e3r.apps.googleusercontent.com",
    "project_id": "developer-playground",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_secret": "GOCSPX-KW_5UbfcvCW9LeNsO-gD7T",
    "redirect_uris": ["http://localhost"]
  }
}

5. Receive authorization code

The OAuth authorization sequence begins when your application redirects the user to a Google URL containing the OAuth client ID and the requested scope. Google handles user authentication and returns an authorization code, which the application can exchange for an access token and refresh token.



const { google } = require('googleapis');
const credentials = require('./credentials.json');

const { client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);

const GMAIL_SCOPES = ['https://www.googleapis.com/auth/gmail.send'];

const url = oAuth2Client.generateAuthUrl({
  access_type: 'offline',
  prompt: 'consent',
  scope: GMAIL_SCOPES,
});

console.log('Authorize this app by visiting this url:', url);

Open your command prompt and run the following command. You will be redirected to the Google Authorization page.

$ node auth.js

Authorize this app by visiting this url:

https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send&response_type=code&client_id=4181097263-eqfdl92e3r.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost

6. Create an Authorized OAuth2 Client

The browser generates an authorization code that you can paste token.js To generate access token and refresh token. The access token will be valid for 1 hour and the application will use the refresh token to obtain a new access token upon termination.



const { google } = require('googleapis');
const path = require('path');
const fs = require('fs');
const credentials = require('./credentials.json');


const code = '4/0AX4XfWjz8e2q81iC9TFzgHCn1tdTmQyMjA';
const { client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);

oAuth2Client.getToken(code).then(({ tokens }) => {
  const tokenPath = path.join(__dirname, 'token.json');
  fs.writeFileSync(tokenPath, JSON.stringify(tokens));
  console.log('Access token and refresh token stored to token.json');
});

Run the following command to generate access token and refresh token.

$ node token.js
Access token and refresh token stored to token.json

this will add a new token.json File in your project directory which has access token and refresh token.

{
  "access_token": "ya29.A0ARrdaM_AaAL3mdEpVZshT-cFfpLkxeMOJz_d1Ok",
  "refresh_token": "1//0gdubhqQhx89VVNBR45_4eipxlYc4Nf5A9J67B8M",
  "scope": "https://www.googleapis.com/auth/gmail.send",
  "token_type": "Bearer",
  "expiry_date": 1649574729833
}

7. Email Sender Library

we are using popular nodemailer Library for generating RFC822 formatted e-mail messages that can be streamed over SMTP. You can also create a mime message manually but the former is easier to use.



const { google } = require('googleapis');
const MailComposer = require('nodemailer/lib/mail-composer');
const credentials = require('./credentials.json');
const tokens = require('./tokens.json');

const getGmailService = () => {
  const { client_secret, client_id, redirect_uris } = credentials.installed;
  const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
  oAuth2Client.setCredentials(tokens);
  const gmail = google.gmail({ version: 'v1', auth: oAuth2Client });
  return gmail;
};

const encodeMessage = (message) => {
  return Buffer.from(message).toString('base64').replace(/+/g, '-').replace(///g, '_').replace(/=+$/, '');
};

const createMail = async (options) => {
  const mailComposer = new MailComposer(options);
  const message = await mailComposer.compile().build();
  return encodeMessage(message);
};

const sendMail = async (options) => {
  const gmail = getGmailService();
  const rawMessage = await createMail(options);
  const { data: { id } = {} } = await gmail.users.messages.send({
    userId: 'me',
    resource: {
      raw: rawMessage,
    },
  });
  return id;
};

module.exports = sendMail;

8. Send Email with Gmail API

This is the last step. Create a MailOptions object that defines the various fields of the message including the sender name, recipient, attachment, HTML body, and subject. You can also add headers to messages and these are useful for adding message tracking information.

For file attachments, you can attach any file from the local file system directly to a Gmail message or even drag an attachment from a remote URL.

const fs = require('fs');
const path = require('path');
const sendMail = require('./gmail');

const main = async () => {
  const fileAttachments = [
    {
      filename: 'attachment1.txt',
      content: 'This is a plain text file sent as an attachment',
    },
    {
      path: path.join(__dirname, './attachment2.txt'),
    },
    {
      filename: 'websites.pdf',
      path: 'https://www.labnol.org/files/cool-websites.pdf',
    },

    {
      filename: 'image.png',
      content: fs.createReadStream(path.join(__dirname, './attach.png')),
    },
  ];

  const options = {
    to: 'amit@labnol.org',
    cc: 'cc1@example.com, cc2@example.com',
    replyTo: 'amit@labnol.org',
    subject: 'Hello Amit 🚀',
    text: 'This email is sent from the command line',
    html: `<p>🙋🏻‍♀️  &mdash; This is a <b>test email</b> from <a href="https://digitalinspiration.com">Digital Inspiration</a>.</p>`,
    attachments: fileAttachments,
    textEncoding: 'base64',
    headers: [
      { key: 'X-Application-Developer', value: 'Amit Agarwal' },
      { key: 'X-Application-Version', value: 'v1.0.0.2' },
    ],
  };

  const messageId = await sendMail(options);
  return messageId;
};

main()
  .then((messageId) => console.log('Message sent successfully:', messageId))
  .catch((err) => console.error(err));

send personalized email

If you want to send personalized email with Gmail and Google Sheets, you can use mail merge for gmail,