Search Lessons, Code Snippets, and Videos
search by algolia
X
#native_cta# #native_desc# Sponsored by #native_company#

SendGrid V3 Transactional Email Cloud Function

Episode 71 written by Jeff Delaney
full courses and content on fireship.io

Health Check: This lesson was last reviewed on and tested with these packages:

  • Sendgrid v3
  • Cloud Functions v1

Update Notes: This lesson has been updated for Angular 6, Firestore, and the new SendGrid v3 NodeJS packages. Get the latest Sendgrid v3 Angular Lesson

Find an issue? Let's fix it

Source code for SendGrid V3 Transactional Email Cloud Function on Github

In this lesson, we are going to use SendGrid’s transactional templates to send email via Firebase Cloud Functions. I will show you how to trigger emails both via HTTP and via Firestore database triggers. The frontend for this tutorial is Angular 5, but this code works for any app powered by Firebase.

sendgrid email sent for Firebase cloud functions

Initial Setup

To get started, you need to have a SendGrid and Firebase account.

Initialize Cloud Functions

If you’ve never used functions, initialize them.

firebase init functions
cd functions

Install SendGrid Packages

There are several different NPM packages in the SendGrid monorepo, but the @sendgrid/mail package should handle most basic use cases. To facilitate an HTTP trigger, I am also installing CORS, but this is not required if only using a database/firestore trigger.

npm install @sendgrid/mail --save
npm install cors --save

Add your API Keys to the Environment

You can find your API key on the SendGrid console. This is a sensitive API key, so be careful not to include it in your Angular code or push it to a public github repo.

get your sendgrid API key and add it to the firebase cloud functions environment

Then save it to the cloud functions environment with the following command.

firebase functions:config:set sendgrid.key=SG.YOUR_API_KEY

Transactional Templates in SendGrid

A powerful way to organize transactional email is with SendGrid’s templating web app. This allows you to easily send out a wide variety of emails with a single cloud function. All of the presentational logic is kept with SendGrid, then you pass the variable data to the function to interpolate it into the function. No messy HTML/CSS email templates for you to manage manually.

Create a Template

Templates can be used to re-create a transactional email by just passing some configuration variables. Create a new template, then create a new version.

sendgrid email sent for Firebase cloud functions

Add Template Variables

SendGrid has a drag-and-drop editor that makes building an email template is very simple. It can also generate dynamic data with variables that use double-curly-brackets similar to Angular (you can also customize the templating syntax). I will show you how to pass this data from the cloud function to SendGrid in the next step.

Example syntax of a SendGrid email template:

Hello {{userName}}

You now have {{followerCount}} followers. Good work!

sendgrid email sent for Firebase cloud functions

Transactional Email Cloud Function via Firestore Trigger

It most cases, you will likely want to trigger a transactional email when some data changes the in the database - a user gets a new follower, somebody comments on a post, a subscription to a topic is updated, etc.

Keep in mind, there are many ways you can customize this code to do things like send emails to multiple recipients, add BBC recipients, etc.

index.js

Let’s assume we have a users collection, with each document having a nested followers collection. Here’s a step-by-step breakdown of the function.

  1. A new follower document is created, invoking the function.
  2. Read the parent user document, which has the user’s email address and display name.
  3. Format the email. All dynamic data is included in the substitutions object, which cooresponds to anything in double curly brackets in the SendGrid template. Also, notice how I included the templateId, which you will find on SendGrid console.
  4. Finanally, tell SendGrid to send it and catch any errors.

const functions = require('firebase-functions');

const admin = require('firebase-admin');
admin.initializeApp();

const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG);
const SENDGRID_API_KEY = firebaseConfig.sendgrid.key;

const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);

exports.firestoreEmail = functions.firestore
.document('users/{userId}/followers/{followerId}')
.onCreate(event => {

const userId = event.params.userId;

const db = admin.firestore()

return db.collection('users').doc(userId)
.get()
.then(doc => {

const user = doc.data()

const msg = {
to: user.email,
from: '[email protected]',
subject: 'New Follower',
// text: `Hey ${toName}. You have a new follower!!! `,
// html: `<strong>Hey ${toName}. You have a new follower!!!</strong>`,

// custom templates
templateId: 'your-template-id-1234',
substitutionWrappers: ['{{', '}}'],
substitutions: {
name: user.displayName
// and other custom properties here
}
};

return sgMail.send(msg)
})
.then(() => console.log('email sent!') )
.catch(err => console.log(err) )


});

Triggering the Function

The function defined above will be triggered whenever a new follower document is created. You can test it out by creating a follower document nested under the user document in the Firestore web console.

Alternative - HTTP Trigger

You don’t necessarily need to send HTTP requests from your app to send transactional email. It is often a better alternative to send email with a Realtime Database or Firebase trigger. Here’s how your function would be modified to use this trigger, assuming you have an Firebase authentication system with custom user data.

index.js


const functions = require('firebase-functions');

const admin = require('firebase-admin');
admin.initializeApp();
const cors = require('cors')({ origin: true });

const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG);
const SENDGRID_API_KEY = firebaseConfig.sendgrid.key


const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);


exports.httpEmail = functions.https.onRequest((req, res) => {
// ...pro only
}





const functions = require('firebase-functions');

const admin = require('firebase-admin');
admin.initializeApp();
const cors = require('cors')({ origin: true });

const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG);
const SENDGRID_API_KEY = firebaseConfig.sendgrid.key


const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);


exports.httpEmail = functions.https.onRequest((req, res) => {

cors( req, res, () => {

const toName = req.body.toName;
const toEmail = req.body.toEmail;

const msg = {
to: toEmail,
from: '[email protected]',
subject: 'New Follower',
// text: `Hey ${toName}. You have a new follower!!! `,
// html: `<strong>Hey ${toName}. You have a new follower!!!</strong>`,

// custom templates
templateId: '300e1045-5b30-4f15-8c43-41754b73fe4f',
substitutionWrappers: ['{{', '}}'],
substitutions: {
name: toName
// and other custom properties here
}
};

return sgMail.send(msg)

.then(() => res.status(200).send('email sent!') )
.catch(err => res.status(400).send(err) )

});

});


Making Requests via Angular

Trigger an HTTP cloud function can be accomplished with the Angular 5 HTTP Client. Send a POST request the cloud function endpoint, with the user data inlcuded in the request body.

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.sass']
})
export class AppComponent implements OnInit {

endpoint = 'https://your-project.cloudfunctions.net/httpEmail';

constructor(private http: HttpClient) { }


sendEmail() {
const data = {
toEmail: '[email protected]',
toName: 'Jeff Delaney'
}

this.http.post(this.endpoint, data).subscribe()
}
}

Then trigger the email with a button click or some other mechanism.

<button (click)="sendEmail()">Send Email</button>

The End

Hopefully this gives you a solid foundation for sending transactional email with SendGrid and Firebase Cloud Functions. You can use these patterns to manage a complex collection of email templates and keep your users informed about exciting news coming from your app.