Как отправить электронное письмо с HTML-контентом из функций Firebase Cloud

Как вы, наверное, догадались, у нас в DeckDeckGo нет сотрудников, которые проверяют, имеют ли публично опубликованные слайды контент по убыванию. Мы также еще не реализовали робота с машинным обучением, который бы это делал.

Я беру на себя такую ​​задачу вручную. Я должен добавить, что это делает меня счастливым. Все опубликованные презентации всегда интересны.

Тем не менее, я должен быть проинформирован, когда колоды будут опубликованы. Вот почему я реализовал Облачную функцию Firebase, чтобы отправлять себе электронное письмо со всей информацией, необходимой мне для быстрого просмотра нового контента.

Настроить новую облачную функцию

Я предполагаю, что у вас уже есть проект Firebase, а также уже созданы некоторые функции. В противном случае вы можете следовать следующему руководству, чтобы начать работу.

Кроме того, обратите внимание, что я использую TypeScript.

Давайте начнем

Для функции нужен триггер, поэтому мы регистрируем функцию в index.ts в коллекции, называемой, например, demo (конечно, ваша коллекция может иметь другое имя).

import * as functions from 'firebase-functions';
export const watchCreate =
       functions.
       firestore.
       document('demo/{demoId}').onCreate(onCreateSendEmail);

Мы можем использовать любые другие триггеры или жизненный цикл, не обязательно create.

Чтобы реагировать на выполнение триггера, мы объявляем новую функцию, которая извлекает вновь созданное значение (const demo = snap.data()), и пока добавляем TODO, который следует заменить эффективным методом отправки электронной почты.

import { EventContext } from "firebase-functions";
import { DocumentSnapshot } from "firebase-functions/lib/providers/firestore";
interface Demo {
  content: string;
}

async function onCreateSendEmail(
                 snap: DocumentSnapshot, 
                 _context: EventContext) {
  const demo: Demo = snap.data() as Demo;

  try {
    // TODO: send email
  } catch (err) {
    console.error(err);
  }
}

Nodemailer

Чтобы эффективно отправлять электронную почту, мы будем использовать Nodemailer.

Nodemailer - это модуль для приложений Node.js, позволяющий легко отправлять электронные письма. Проект стартовал еще в 2010 году, когда не было разумного варианта отправки сообщений электронной почты, сегодня это решение, к которому по умолчанию обращается большинство пользователей Node.js.

Nodemailer находится под лицензией MIT.

Как видите, Nodemailer совместим не только с облачными функциями Firebase, но и с любыми проектами Node.js.

Чтобы установить его в нашем проекте, мы запускаем следующую команду:

npm install nodemailer --save

Кроме того, мы также устанавливаем его определение типизации.

npm install @types/nodemailer --save-dev

SMTP транспорт

Nodemailer использует SMTP в качестве основного транспорта для доставки сообщений. Следовательно, ваш поставщик услуг доставки электронной почты должен поддерживать такой протокол. Он также поддерживает расширение LTS или STARTTLS. В этом посте мы собираемся использовать STARTTLS и поэтому собираемся установить флаг secure на false, чтобы активировать этот протокол.

Вы можете найти все варианты в библиотеке Документация.

Конфигурация

Если ваш проект имеет открытый исходный код, возможно, вам будет интересно не указывать жестко ваши логин, пароль и хост SMTP в коде, а лучше скрыть их в конфигурации.

Firebase предлагает такую ​​возможность. Мы можем создать сценарий set для этого.

#!/bin/sh
firebase functions:config:set mail.from="[email protected]" mail.pwd="password" mail.to="[email protected]" mail.host="mail.provider.com"

Чтобы получить эту конфигурацию в нашей функции, мы можем получить доступ к конфигурации через functions.config(), за которым следуют ключи, которые мы только что определили выше.

const mailFrom: string = functions.config().mail.from;
const mailPwd: string = functions.config().mail.pwd;
const mailTo: string = functions.config().mail.to;
const mailHost: string = functions.config().mail.host;

Отправить электронное письмо

У нас есть транспорт, у нас есть конфигурация, нам просто нужна последняя часть: сообщение.

Я предпочитаю отправлять собственное электронное письмо в формате HTML, позволяющее включать ссылки в контент, поэтому и здесь мы используем такой формат.

const mailOptions = {
  from: mailFrom,
  to: mailTo,
  subject: 'Hello World',
  html: `<p>${demo.content}</p>`
};

Наконец, мы можем использовать Nodemailer для создания канала и, в конечном итоге, отправки нашего электронного письма.

const transporter: Mail = nodemailer.createTransport({
  host: mailHost,
  port: 587,
  secure: false, // STARTTLS
  auth: {
    type: 'LOGIN',
    user: mailFrom,
    pass: mailPwd
  }
});
await transporter.sendMail(mailOptions);

В целом

В целом наша функция следующая:

import * as functions from 'firebase-functions';

import { EventContext } from "firebase-functions";
import { DocumentSnapshot } from "firebase-functions/lib/providers/firestore";

import * as Mail from "nodemailer/lib/mailer";
import * as nodemailer from "nodemailer";

export const watchCreate =
       functions.
       firestore.
       document('demo/{demoId}').onCreate(onCreateSendEmail);

interface Demo {
  content: string;
}

async function onCreateSendEmail(
                 snap: DocumentSnapshot, 
                 _context: EventContext) {
  const demo: Demo = snap.data() as Demo;

  try {
    const mailFrom: string = functions.config().info.mail.from;
    const mailPwd: string = functions.config().info.mail.pwd;
    const mailTo: string = functions.config().info.mail.to;
    const mailHost: string = functions.config().info.mail.host;

    const mailOptions = {
      from: mailFrom,
      to: mailTo,
      subject: 'Hello World',
      html: `<p>${demo.content}</p>`
    };

    const transporter: Mail = nodemailer.createTransport({
      host: mailHost,
      port: 587,
      secure: false, // STARTTLS
      auth: {
        type: 'LOGIN',
        user: mailFrom,
        pass: mailPwd
      }
    });

    await transporter.sendMail(mailOptions);
  } catch (err) {
    console.error(err);
  }
}

Резюме

С помощью Firebase и Nodemailer можно относительно быстро настроить функцию, запускающую электронную почту. Я надеюсь, что это введение дало вам несколько подсказок о том, как реализовать такую ​​функцию, и что вы собираетесь попробовать DeckDeckGo в своих следующих презентациях.

Я с нетерпением жду сообщения электронной почты о том, что мне нужно проверить опубликованные вами слайды 😉.

Бесконечность не предел!

Дэйвид