Sending Email Notifications with Firebase Functions with Sendgrid

firebase

At this time, Firebase functions don’t natively have the functionality for sending custom emails on their own. Google’s own documentation also suggests one of their own partner platforms like Sendgrid for sending emails.

Although you have the option of sending verification emails to your users who sign-up on your Firebase app, the customization there is severely limited.

In this tutorial, we will explore, how you can send a custom email with the subject, body, and attachments of your choice through a triggered Firebase function.

There are mainly two ways of sending an email. You can use a library like nodemailer or a 3rd party service like Sendgrid. In a production app, using nodemailer is not practical. You have a very small limit on how many emails you can send using your Google credentials. Along with this, there are chances that those mails will straightaway go to the spam folder.

Note: I’m skipping the project setup and initialization part. You can read about that in the official docs.

In your project folder, create a file in the following path: /<project_dir>/functions/sendgrid/userOnCreateHandler.js. Add the following code in there.

// functions/sendgrid/userOnCreateHandler.js

const sendgrid = require('@sendgrid/mail');
const templates = require('./templates/welcome');

const userOnCreateHandler = (user) => {
  try {
    sendgrid.setApiKey(process.env.SG_API_KEY);
    const { email, displayName = 'User' } = user;
    const subject = `Welcome to ${process.env.APP_NAME}`;
    const { welcome: body } = templates;

    return sendgrid.send({
      subject,
      html: body,
      attachments: [
        {
          content: Buffer.from(/* file here */),
        },
      ],
      to: {
        name: displayName,
        email,
      },
      from: {
        name: process.env.APP_EMAIL_NAME,
        email: process.env.APP_WELCOME_EMAIL,
      },
    });
  } catch (error) {
    console.error(error);

    if (error.response) {
      console.error('sendgrid_error_response', error.response.body);
    }
  }
};

module.exports = userOnCreateHandler;
// functions/index.js
const functions = require('firebase-functions');
const userOnCreateHandler = require('./sendgrid/userOnCreateHandler');

exports.userOnCreateHandler = functions.auth
  .user()
  .onCreate(userOnCreateHandler);
// functions/sendgrid/templates/welcome.js
const welcome = `<!doctype html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Simple Transactional Email</title>
  </head>
  <body>
    ...your html email content here...
  </body>
</html>`;
 
module.exports = {
  welcome,
};

From the code above, you can see that the majority of the code is in the userOnCreateHandler function. The type of function we have used here is the Firebase authOnCreate function. This function triggers when new user logins into your site/app.

Of course, you will need to enable signup using email and password or google sign in to get the user’s email. Based on the UI that you use in your app, you also have the option to capture the displayName of the user during signup. Since that might not always be the case, I have fallen back to User as the default username that the user will see in the email.

You will also need to set a few environment variables in your app:

process.env.SG_API_KEY;
process.env.APP_NAME;
process.env.APP_EMAIL_NAME;
process.env.APP_WELCOME_EMAIL;

This is just personal preference. You can replace these values in the code as you like. The one which is required for the code to definitely work is SG_API_KEY which you can get from your SendGrid account.

For that, log in to your SendGrid account and navigate to https://app.sendgrid.com/settings/api_keys. You can create a new API key from there using the Create API key button. Use that key in your code by using the environment variable.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.