10 min.

How to send email using Firebase Functions

Three Diverse Serverless Email Sending Solutions Suitable for Serverless, Hosting, and VPS-Deployed Applications

Choose Your Implementation Type

 

When it comes to sending serverless emails with Firebase, there are primarily three options available, regardless of how your app is deployed or plans to be. 

 

Opting to delegate email sending tasks to Firebase offers notable advantages in terms of security, message queuing, and convenience. It's important to first determine which of the following solutions best aligns with your app's needs. Further in this article, I will delve into each option in more detail, specifically focusing on the Node.js environment

 

 

Trigger email

 

This option is a native extension within Google's serverless architecture but is the most challenging in terms of implementation and offers the least flexibility. Utilizing a Firestore database for email dispatch necessitates a subscription to the Blaze plan, which incurs a fee.

 

 

SMTP email service

 

Offering greater flexibility, this method does not require a database for operation and permits continued use of the basic, free Firebase plan. However, a significant drawback is the security risk posed by the need to supply your email's raw credentials to the Firebase function, which could potentially lead to vulnerabilities.

 

 

Cloud email service

 

This option shares the flexibility of the SMTP email service but enhances security. The primary disadvantage is the need for a functional external cloud email service. Conversely, utilizing a service like SendGrid allows the sending of up to 100 emails per day for free, without necessitating a credit card, offering a blend of security and functionality with services such as email delivery tracking and spam filters.

 

 

 

Trigger

Email

SMTP

 Email

 Service

Cloud

Email

Service

Configuration Difficulty

medium; requires FirestoreVery easy; no database neededVery easy; requires a workable cloud email service

 Flexibility

Medium; relies on Firestore databaseHighHigh

Costs

Depends on Firebase quotas; requires Blaze plan upfrontDepends on Firebase quotasDepends on the quotas of both Firebase and the cloud email service provider

Security

High,

but may require raw

email credentials

Medium; requires passing raw email credentials and depends on external package securityHigh; depends on external package security but only requires an API key, eliminating the need to pass raw credentials

Add-ons

Available when used with an email cloud providerNoneOffers email analytics, spam filters, email delivery tracking, and IP blocks

 

 

Still Unsure?

 

In most scenarios, a cloud email service emerges as the superior choice due to its robust security—eliminating the need to transmit your email credentials directly—and its comprehensive suite of features, including email delivery tracking and spam filters. This is why it is highlighted as the foremost option

 

 

Option 1 - Cloud email service

 

 

Requirements

 

  • A Firebase Functions project
  • A cloud email account, such as SendGrid or MailGun

 

 

Setting Up SendGrid

 

Account Setup: Begin by creating a SendGrid account. Then, register a single sender address from which your emails will be sent.

 

SendGrid single sender

 

 

Single Sender Registration: After setting up your account, navigate to the 'Email API' tab and follow the integration guide for the Web API. You will receive a unique API key towards the end of this process. It's advised not to complete the verification process immediately; instead, wait until after you've implemented and deployed your function on Firebase before starting the verification process.

 

 

SendGrid Node.js installation

 

 

Installing SendGrid on Node.js

  1.  

Install Dependencies: In your Firebase project, navigate to the functions directory and install the necessary packages:

 

 

npm install --save @sendgrid/mail cors express

 

 

Configure API Key: Add your SendGrid API key to the Firebase configuration:

 

 

firebase functions:config:set sendgrid.key="YourAPIKey"

 

 

Verify the registration of the key:

 

 

firebase functions:config:get

 

 

Creating an Email Sending Function

 

In the index.js file, create a function to send emails. Ensure CORS is properly handled to only allow requests from your app domains. For testing purposes, you might temporarily allow all origins with the following CORS setup:

 

 

// cors options, only for the testing purposes
const corsOptions = {origin: true}

 

 

Implement your function with CORS enabled to block requests outside your app domains. However, for testing, disabling CORS (allowing all origins) might be more convenient.

 

Here's a template for your email sending function in functions/index.js:

 

 

const functions = require('firebase-functions');
const express = require('express');
const sgMail = require('@sendgrid/mail');
const app = express();
const cors = require('cors');

// Specify your domain(s)
const whitelist = ['https://yourDomain.com', 'yourDomain.com'];

const corsOptions = {
    origin: function (origin, callback) {
        if (whitelist.includes(origin)) {
            callback(null, true);
        } else {
            callback(new Error('Not allowed by CORS'));
        }
    }
};

app.get('/', cors(corsOptions), function (request, response) {
    sgMail.setApiKey(functions.config().sendgrid.key);
    const from = 'yourSingleSenderEmailAddress'; // Your verified sender address
    const { to, subject, text } = request.query;
    const msg = {
        to,
        from,
        subject,
        text,
        html: `<strong>${text}</strong>`,
    };
    sgMail.send(msg).then(() => {
        response.status(200).send('Email sent');
    }).catch((error) => {
        response.status(500).send(error.toString());
    });
});

exports.email = functions.https.onRequest(app);

 

 

Deploying Your Function

 

Deploy your function to the cloud with:

 

 

firebase deploy

 

 

After deployment, note your function's URL from the Firebase console, which should end with the function name, in this case, 'email'

 

 

Completing SendGrid Verification

 

Return to SendGrid to finalize your setup. Using a tool like Postman, submit a test request to your function's URL with the required parameters (subject, to, text) to initiate the verification process. Once successful, you can proceed to accept the verification within SendGrid

 

 

Postman serverless email sending

 

 

Finalizing CORS Settings

 

After testing, adjust your CORS settings to be more restrictive, as outlined in the initial setup. This prevents unauthorized access to your function endpoint, including from tools like Postman."

 

 

Option 2 - SMTP Email Service

 

Implementing serverless email sending via SMTP is straightforward but may present challenges with restrictive email services, such as Gmail, which requires specific permissions to be granted for SMTP access.

 

 

Requirements

 

  • A Firebase Functions project
  • Credentials for an email service (e.g., Gmail)

 

 

Lifting Gmail Restrictions

 

Allow Less Secure Apps: Navigate to your Gmail settings to enable access for less secure apps. This step is necessary to permit email sending via SMTP.

 

Bypass Google Security Warnings: Upon deploying your code and sending the first message, Google may issue a warning about your app accessing Gmail. Follow Google's instructions to allow this connection.

 

 

 

Gmail external apps access restriction

 

Gmail lifting less secure app access restrictions

 

 

Disable CAPTCHA Temporarily: You may also need to disable CAPTCHA for your Gmail account to ensure uninterrupted SMTP access.

 

 

Gmail disable Captcha

 

 

Installing Dependencies

 

In your Firebase project's functions directory, install the required packages:

 

 

npm install --save nodemailer cors express

 

 

Configuring Email Credentials

 

Add your email credentials to Firebase config:

 

 

firebase functions:config:set nodemailer.email="yourEmailAddress@gmail.com"

firebase functions:config:set nodemailer.password="yourEmailPassword"

 

 

Verify that the credentials are correctly registered:

 

 

firebase functions:config:get

 

 

Creating an Email Sending Function

 

In index.js, create a function to send emails, ensuring CORS is handled appropriately. The default setup blocks requests outside your app domains, but you can allow all origins for testing purposes:

 

 

// cors options, only for the testing purposes
const corsOptions = {origin: true}

 

 

Below is a template for an SMTP-based email sending function using Gmail. If using another email provider, replace the service name in the transporter configuration.

 

 

const functions = require('firebase-functions');
const express = require('express');
const nodemailer = require('nodemailer');
const app = express();
const cors = require('cors');

const whitelist = ['https://yourDomain.com', 'yourDomain.com'];
const corsOptions = {
    origin: function (origin, callback) {
        if (whitelist.includes(origin)) {
            callback(null, true);
        } else {
            callback(new Error('Not allowed by CORS'));
        }
    }
};

const transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: functions.config().nodemailer.email,
        pass: functions.config().nodemailer.password
    }
});

app.get('/', cors(corsOptions), function (request, response) {
    const from = 'yourEmailAddress@gmail.com'; // Your email address
    const {to, subject, text} = request.query;
    const msg = {
        to,
        from,
        subject,
        text,
        html: `<strong>${text}</strong>`,
    };
    transporter.sendMail(msg).then(() => {
        response.status(200).send('Email sent');
    }).catch((error) => {
        response.status(500).send(error.toString());
    });
});

exports.email = functions.https.onRequest(app);

 

 

Deploying Your Code

 

Deploy your function to the cloud with:

 

 

firebase deploy

 

 

After deployment, note the function URL from the console, which you can integrate into your app for email sending functionalities.

 

 

Option 3 -Trigger Email

 

Trigger Email is the least flexible option among those presented, as it sends emails only when data is inserted into one of your Firestore collections. This method can be integrated with either SMTP or cloud email services like SendGrid, with the latter recommended for enhanced security and additional features. 

 

For handling potential Gmail SMTP restrictions, please refer to the earlier sections of this article. When using SendGrid, opt for the SMTP Relay feature in the Email API tab to obtain your SMTP credentials.

 

 

Requirements

 

  • A Firebase Functions project

 

  • Credentials for an email or email service provider

 

  • Configured Firestore

 

  • A Firestore collection for emails (automatically created)

 

  • The Blaze plan, which is pay-as-you-go

 

  • Trigger Email extension

 

  • Firebase Admin package

 

  • Optionally, user and template collections (automatically created if needed)

 

 

Installing the Trigger Email Extension

 

In your Firebase project's functions directory, list your projects and their IDs to find the one you'll use:

 

 

firebase projects:list

 

 

Install the Trigger Email extension and grant it access when prompted:

 

 

firebase ext:install firestore-send-email --project=yourProjectId

 

 

Configuring the Extension

 

Function Location

 

Choose the default location, typically closest to your Firestore database.

 

 

SMTP Connection URI:


Use the format smtps://username:password@smtp.hostname.com:port

For Gmail smtps://username:password1234@smtp.gmail.com - refer to official Gmail SMTP information

For SendGrid smtps://apikey:SG.gs4mYklHTq4nSasadads2adfad@smtp.sendgrid.net - refer to SendGrid SMTP setup guide

 

 

Email Documents Collection

 

Name your email collection.

 

 

Default Email Sender

 

Use an email address associated with your SMTP credentials.

 

 

Default REPLY-TO Address

 

Can be any desired address.

 

 

Users Collection (Optional)

 

Name your user collection if used.

 

 

Templates Collection (Optional)

 

Name your templates collection if used.

 

 

Install Required Packages

 

 

 npm install --save firebase-admin cors express

 

 

Create a Basic Email Sending Function

 

In functions/index.js, create a basic function to send emails through Firestore:


 

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

app.get('/', cors(corsOptions), function (request, response) {
    const { to, subject, text } = request.query;
    try {
        admin.firestore().collection('mail').add({
            to,
            message: {
                subject,
                html: `<p>${text}</p>`,
            },
        });
        response.status(200).send('Email sent');
    } catch (err) {
        response.status(500).send(err.toString());
    }
});

exports.email = functions.https.onRequest(app);

 

 

Deploy your code and test the function. The URL will be printed in the console. If using SendGrid, verify your API first, then call the function and accept the verification process:

 

 

firebase deploy

 

 

After confirming everything works, consider tightening CORS settings for enhanced security, following the guidance provided in the earlier sections for SMTP and Cloud Email Service options.