Nodemailer Gmail OAuth2

Sending email using web application is a common thing, espeically for sending automatic emails such as password reset or email confirmation. To send email from your web application, you need to link up the application and the email. If you're using Node.js and you want to use Gmail, you come to the right place. This tutorial shows you how to send email in Node.js, with Gmail as the service and Nodemailer as the module for sending email. As for authentication, we will use OAuth2 technology instead of providing account password as on most other tutorials on other websites.

What is OAuth2 and Why We Should Use It?

OAuth2 is the second version of OAuth protocol. It allows third party applications obtaining limited access to user accounts on an HTTP service. The authentication process is done in the service that hosts the account. Usually, the owner of the account is asked whether or not he's willing to authorize a third-party application. If permitted, the third-party application will get certain access to the user account.

Using nodemailer, actually we can use the account password for authentication and it's very simple (much simpler than setting up OAuth2). So, why using OAuth2 is more recommended. The reason is for security. If your token or secret is stolen, you only need to revoke it and you're safe. In contrast, if you use the account password and someone steals your password, he will get full control of your account and may take over it. Therefore, using OAuth2 is really recommended even though the process of setting up is more complicated.

Getting Client Credentials

First, you need to register your application for Gmail API in Google API Console. Open this link. On that page, you can choose to create a new project or use existing project.

Gmail API - Create Project

Then, click on Continue and the Gmail API will be enabled automatically. Click on Go to credentials and you'll be redirected to a page for setting up a new crdential.

The first section is find out what kind of credentials you need. For question which API are you using, choose Gmail API. For question where will you be calling the API form, choose web server. For question what data will you be accessing, choose user data.

Gmail API - Credentials Step 1

The second section is create an OAuth 2.0 client ID. You can input any name. The Authorized Javascript origins is not used in this tutorial, but it won't be a problem if enter your domain there. For authorized redirect URIs, you should enter your domain.

Gmail API - Credentials Step 2

On the third step, choose the email you want to use and enter the product name.

Gmail API - Credentials Step 3

Lastly, download the credentials file.

Gmail API - Credentials Step 4

Then, you need to copy some values on the downloaded credentials file to your environment variable .env. Open that file and search for client_id, project_id, client_secret and redirect_uris. In your .env file, add the followings:

  GMAIL_ADDRESS=example@gmail.com
  GMAIL_OAUTH_CLIENT_ID=11223344556-abcdefghijklmnopqrstuvwxyz123456.apps.googleusercontent.com # replace with client_id
  GMAIL_OAUTH_PROJECT_ID=abcdef-abcdefg-123456 # replace with project_id
  GMAIL_OAUTH_CLIENT_SECRET=-aBcdEfGHijKlmnoPQRSTuVw # replace with client_secret
  GMAIL_OAUTH_REDIRECT_URL=https://www.woolha.com # replace with the first element of redirect_uris

Dependencies

Before starting to code, add these dependencies on package.json and run npm install.

  "dotenv": "~4.0.0"
  "googleapis": "~32.0.0"
  "nodemailer": "~4.0.1"

Getting Tokens

For using nodemailer, first you need to create a transporter object by calling nodemailer.createTransport(). It requires an object as the parameter. If you want to use OAuth2, the passed object must have the following props:

  • type - The value is 'OAuth2'
  • user - The email address
  • clientId - Value of client_id on the downloaded client_id.json file
  • clientSecret - Value of client_secret on the downloaded client_id.json file
  • refreshToken
  • accessToken
  • expires

The question is how to get the tokens value. You can create an instance of OAuth2Client which has getToken method. It accepts a single parameter named code of type string. In order to get the value of code, you need to generate a URL. To generate the URL, run the following script

helpers/google-oauth2/gmail-generate-auth-url.js

  require('dotenv').config();
  const { google } = require('googleapis');

  const oauth2Client = new google.auth.OAuth2(
    process.env.GMAIL_OAUTH_CLIENT_ID,
    process.env.GMAIL_OAUTH_CLIENT_SECRET,
    process.env.GMAIL_OAUTH_REDIRECT_URL,
  );

  // Generate a url that asks permissions for Gmail scopes
  const GMAIL_SCOPES = [
    'https://mail.google.com/',
    'https://www.googleapis.com/auth/gmail.modify',
    'https://www.googleapis.com/auth/gmail.compose',
    'https://www.googleapis.com/auth/gmail.send',
  ];

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

  console.info(`authUrl: ${url}`);

If it runs successfully, you should get the URL on your console. Open the URL using a web browser. You may need to login or select account if you've multiple accounts. Then you'll be redirected to a page asking do you allow your application to access your Google account.

Gmail API - Ask for Permission

Click on the Allow button and you'll be redirected to a URL which you've set as the value of GMAIL_OAUTH_REDIRECT_URL in .env. The URL should contain a query string named code, copy the value (the # on the end of it must be excluded).

https://www.woolha.com/?code=4/AABBCC-abcdEFGH1-aBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDe#

After getting the code, now it's time to get the tokens. Use this script:

helpers/google-oauth2/gmail-get-tokens.js

  require('dotenv').config();
  const { google } = require('googleapis');

// Replace with the code you've got on const code = '4/AABBCC-abcdEFGH1-aBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDe'; const oauth2Client = new google.auth.OAuth2( process.env.GMAIL_OAUTH_CLIENT_ID, process.env.GMAIL_OAUTH_CLIENT_SECRET, process.env.GMAIL_OAUTH_REDIRECT_URL, ); const getToken = async () => { const { tokens } = await oauth2Client.getToken(code); console.info(tokens); }; getToken();

After you run that script, you should get the tokens.

  {
    access_token: 'abcd.abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCD',
    token_type: 'Bearer',
    refresh_token: '1/abc123abc123abc123abc123abc123abc123abc123a',
    expiry_date: 1529136753542
  }

Now you've got the values for refreshToken, accessToken and expires. Add those values to .env.

  GMAIL_OAUTH_REFRESH_TOKEN=1/abc123abc123abc123abc123abc123abc123abc123a # replace with refresh_token
  GMAIL_OAUTH_ACCESS_TOKEN=abcd.abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCDef12abCD # replace with access_token
  GMAIL_OAUTH_TOKEN_EXPIRE=1529136753542 # replace with expiry_date

and we're ready to use nodemailer. We create a helper for sending email.

helpers/email.js

  require('dotenv').config();
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({ host: 'smtp.gmail.com', port: 465, secure: true, auth: { type: 'OAuth2', user: process.env.GMAIL_ADDRESS, clientId: process.env.GMAIL_OAUTH_CLIENT_ID, clientSecret: process.env.GMAIL_OAUTH_CLIENT_SECRET, refreshToken: process.env.GMAIL_OAUTH_REFRESH_TOKEN, accessToken: process.env.GMAIL_OAUTH_ACCESS_TOKEN, expires: Number.parseInt(process.env.GMAIL_OAUTH_TOKEN_EXPIRE, 10), }, }); exports.sendEmail = mailOptions => new Promise((resolve, reject) => { transporter.sendMail(mailOptions, (error) => { if (error) { console.error(error.stack || error); return reject(error); } resolve(); }); });

Here is the usage example of the sendEmail function above:

  const emailHelpers = require('../helpers/email');

  const options = {
    to: 'test@example.com',
    subject: 'Test',
    html: 'The cutest programming blog is <a href="https://www.woolha.com">Woolha.com</a>',
  };

  emailHelpers.sendEmail(options)

If you want to add attachments, Nodemailer has already provides clear documentation on this page. Now you should be able to send email using your Google account in Node.js using Nodemailer, with OAuth2 authentication.