I'm now playing around with this new basic blog template from Next.js examples --> available on Next.js GitHub.

Luciano Lupo Notes.

Send emails with cloud funtions

Cover Image for Send emails with cloud funtions

I was working with a client who had a frontend app that needed to send/receive emails. The client didn't have a backend server and didn't want to have one, but had a SMTP server included in his server provider so I got a good opportunity to try cloud functions ( which are free in firebase ) I personally think is always better to have a robuts backend server but in this case the client didn't want to have one....

Will go thru the code but main idea is that I can hide the nodemailer configs and secerts and in frontend I will have a box to fill text in and a "Send" button, which call the Cloud funtion, construct an email, and send the email with the question from the user to my client,

IMPORTANT: configure correctly your functions panel to allow only your domain to call the function.

Let's start

first of all spin up a project following this Firebase Docs

in the index.js import the required libraries and initialize the firebase app

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const nodemailer = require("nodemailer");
const cors = require("cors");
const express = require("express");
const { defineSecret } = require("firebase-functions/params");

admin.initializeApp();

exports.helloWorld = functions.https.onRequest((request, response) => {
  response.send("Hello from Firebase!");
});

I'm using nodemailer to send emails, so I'm gonna need the email user and password, which can be hardcoded but lets keep it clean and import from enviroment variables, in this case I'm using 2 email accounts, the no-reply one, that will send things, and 2nd one that will receive the emails.

const secretPassword1 = defineSecret("EMAIL_PASSWORD_1");
const secretPassword2 = defineSecret("EMAIL_PASSWORD_2");

let noReplyTransporter = nodemailer.createTransport({
  host: "mail.myAwesomeClient.com",
  port: 587,
  secure: false, // true for 465, false for other ports
  auth: {
    user: "no-reply@myAwesomeClient.com",
    pass: secretPassword1,
  },
  tls: {
    // do not fail on invalid certs
    rejectUnauthorized: false,
  },
});

let helloTransporter = nodemailer.createTransport({
  host: "mail.myAwesomeClient.com",
  port: 587,
  secure: false, // true for 465, false for other ports
  auth: {
    user: "hello@myAwesomeClient.com",
    pass: secretPassword2,
  },
  tls: {
    // do not fail on invalid certs
    rejectUnauthorized: false,
  },
});

Send to backoffice function:

const sendToBackOfficeMail = async (data) => {
  const verification = await helloTransporter.verify((error, success) => {
    if (error) {
      console.log(error);
      return error;
    } else {
      console.log("Server is ready to take our messages", success);
      return "success";
    }
  });

  console.log("verification", verification);
  // getting dest email by query string
  const dest = "hello@myAwesomeClient.com";

  const mailOptions = {
    from: data.mail, // Something like: Jane Doe <janedoe@gmail.com>
    to: dest,
    subject: "Hello - AwesomeClient", // email subject
    html: `<p style="font-size: 16px;"> Nombre: ${data.name}</p>
                <br />
                <p style="font-size: 16px;"> Consulta: ${data.query}</p>
                `, // email content in HTML
  };

  // returning result
  try {
    const info = await helloTransporter.sendMail(mailOptions);
    return info;
  } catch (e) {
    return e;
  }
};

function for the no-replay email:

const sendMailToUser = async () => {
  // verify connection configuration
  noReplyTransporter.verify(function (error, success) {
    if (error) {
      console.log(error);
    } else {
      console.log("Server is ready to take our messages");
      cors(data, res, () => {
        // getting dest email by query string
        const dest = data.query.dest;

        const mailOptions = {
          from: "no-reply@myAwesomeClient.com", // Something like: Jane Doe <janedoe@gmail.com>
          to: dest,
          subject: "No Reply Email", // email subject
          html: `<p style="font-size: 16px;">Hey hey!!</p>
                        <br />
                        <p style="font-size: 16px;">This is a no-reply email, thanks for your interest in bla bla.....</p>
                    `, // email content in HTML
        };

        // returning result
        return transporter.sendMail(mailOptions, (erro, info) => {
          if (erro) {
            return erro.toString();
          }
          return "Sended";
        });
      });
    }
  });
};

Function for sending email to backoffice:

const sendMail = async (data) => {
  const resp = await sendToBackOfficeMail(data.body);
  console.log("Response: ", resp);
};

Finally expose the function:

const app = express();

// Automatically allow cross-origin requests
app.use(cors({ origin: true }));
app.post("/sendMail", async (req, res) => res.send(await sendMail(req)));
// end up not using sendMailToUser but should be here if needed to be exposed

// Expose Express API as a single Cloud Function:
exports.api = functions.https.onRequest(app);