Firebase functions are a lot of fun, no doubt.

They allow you to uncouple business logic from your app.

Instead of running computationally expensive tasks on your server you can leverage firebase functions.

Here’s a quick and dirty guide to using Firebase functions to send welcome emails.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var functions = require('firebase-functions')
var mailgun = require('mailgun-js')({apiKey, domain})
exports.sendWelcomeEmail = functions.database.ref('users/{uid}').onWrite(event => {
// only trigger for new users [event.data.previous.exists()]
// do not trigger on delete [!event.data.exists()]
if (!event.data.exists() || event.data.previous.exists()) {
return
}
var user = event.data.val()
var {email} = user
var data = {
from: 'app@app.com',
subject: 'Welcome!',
html: `<p>Welcome! ${user.name}</p>`,
'h:Reply-To': 'app@app.com',
to: email
}
mailgun.messages().send(data, function (error, body) {
console.log(body)
})
})

In the above code snippet, we use the transactional service Mailgun to send a welcome email. We’re also using the node package mailgun-js, which is just a wrapper around Mailgun’s API.

Things to note:

  • This function will only execute once per user - which we can change if needed.
  • We might want to add a callback to our firebase server if the email is sent successfully.
  • apiKey - this is your Mailgun API key.
  • domain - this is your domain name registered with Mailgun.

Subscribing new users to receive emails

Let’s say that instead of sending one welcome email, we want to initiate a drip campaign.

In that case, we could write to our firebase database and update a field (like { subscribed: true }).

One thing to be mindful of is cloud functions that write to the same database path that triggers them. If you’re not careful you might induce an infinite loop.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var functions = require('firebase-functions');
var admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase);
var mailgun = require('mailgun-js')({apiKey, domain})
exports.subscribeUser = functions.database.ref('users/{uid}').onWrite(event => {
var user = event.data.val()
var {uid} = event.params
// Exit if the user was deleted or the user is currently subscribed
if (!event.data.exists() || user.subscribed ) {
return
}
let members = {
address: user.email
}
var listId = 'your mailgun list id'
// Add the user to our mailgun list
return mailgun.lists(listId).members().add({members, subscribed: true}, function (err, body) {
if(!err) {
return admin.database().ref('users/' + uid + '/subscribed').set(true)
}
})
})

Here’s what we did in the snippet above:

  • Make sure that the functions doesn’t trigger on delete (!event.data.exists())
  • Make sure that the function doesn’t trigger if the user is already subscribed
  • Subscribe the user to a list using the mailgun API
  • use firebase admin to update the value at users/{uid}/subscribed to true.

Sending Emails With Mailchimp

Instead of using a transactional email service like Mailgun or Sendgrid, you could also use Mailchimp (which is just a user-friendly wrapper around Mailgun).

Here’s how you’d use Mailchimp’s API.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var fetch = require('isomorphic-fetch')
var btoa = require('btoa');
// POST /lists/{list_id}/members
// Add a new list member
function createFetch () {
var MAILCHIMP_API_KEY = ''
// NOTE: mailchimp's API uri differs depending on your location. us6 is the east coast.
var url = 'https://us6.api.mailchimp.com/3.0/lists/' + listId + '/members'
var method = 'POST'
var headers = {
'authorization': "Basic " + btoa('randomstring:' + MAILCHIMP_API_KEY),
'Accept': 'application/json',
'Content-Type': 'application/json'
}
var body = JSON.stringify({email_address: user.email, status: 'subscribed'})
return fetch(url, {
method,
headers,
body
}).then(resp => resp.json())
.then(resp => {
console.log(resp)
})
}

Notes

  • You’ll need to npm i btoa –save for this to work. btoa binary encodes data to base 64-encoded ascii.
  • Mailchimp’s API is really well documented.

Deploying Firebase Functions

1
2
3
4
5
6
npm i firebase-tools -g # install firebase cli
cd my-project
firebase login
firebase init functions

Now add your code to ./functions/index.js:

1
exports.sendEmail = ...

And npm install any required packages. (firebase-functions and firebase-admin should be preinstalled after firebase init functions).

Finally deploy with:

1
firebase deploy --only functions

Gotchas

  • You’ll need to enable billing at https://google.firebase.com for your project to make external API requests. If billing is not enabled you’ll get an opaque error.
  • Remember that if you’re using ES6 syntax you’ll need to transpile it with babel.

Resources