Search code examples
javascriptfirebasegoogle-cloud-platformgoogle-cloud-functionsnodemailer

Firebase Cloud Functions Send Email With Nodemailer


I'm currently facing a problem when integrating Firebase Cloud Functions to Nodemailer, I'm currently using JavaScript to do that and my code is:

const functions = require('firebase-functions');
const admin=require('firebase-admin');
const nodemailer = require('nodemailer');
admin.initializeApp();
require('dotenv').config()

var SUCCESS_CODE = 0;
const {SENDER_EMAIL, SENDER_PASSWORD} = process.env;

exports.sendEmail = functions.database.ref('Contestants/{contestantID}').onCreate((snap, context) =>{
    let contestantID = context.params.contestantID;
    let contestant = snap.val();
    
    let authData = nodemailer.createTransport({
        host:'smtp.gmail.com',
        port:465,
        secure:true,
        auth:{
            user:SENDER_EMAIL,
            pass:SENDER_PASSWORD
        }
    });

    authData.sendMail({
        from: SENDER_EMAIL,
        to:`${contestant.email}`,
        subject:`Subscription nº ${contestant.uid} - Concluded!`,
        text:`This is a test.`,
        html:`${htmlBody}`
    }).then(res=>SUCCESS_CODE=8888).catch(err=>SUCCESS_CODE=1313);

    return SUCCESS_CODE;
});

This functions is to be used when a user completes the subscription on a plan of my website for an event of my company. But, in firebase console I'm receiving the message Function execution took 207 ms, finished with status: 'ok' but the receiver never receives the e-mail, also on the e-mail sender gmail account, nothing show as sent.

I have a custom e-mail with a custom domain, my Google G-Suite account is set to accept less secure apps already, but it doesn't seem to work.

P.S: All my project is on firebase, my database is on Firebase Realtime Database, and my website is hosted with Firebase Hosting.

I need some help to figure out what is wrong with my code or what is missing to make it work. Also, I would appreciate if someone give me a direction on how to send data to my website when this function is executed successfully, an example is, after sending the e-mail, open a new page on my website with a success message.

I apologize about my lack of knowledge in JavaScript, that's the first time I'm trying it, used to work with C# and Kotlin, but had to do some cloud functions to my company and this stuff is really new to me.


Solution

  • You don’t terminate your function correctly. You need to "resolve functions that perform asynchronous processing (also known as "background functions") by returning a JavaScript promise” as explained in the documentation.

    So the following will do the trick, since the sendEmail() method returns a Promise object (if callback argument is not set).

    exports.sendEmail = functions.database.ref('Contestants/{contestantID}').onCreate((snap, context) => {
        let contestantID = context.params.contestantID;
        let contestant = snap.val();
    
        let authData = nodemailer.createTransport({
            host: 'smtp.gmail.com',
            port: 465,
            secure: true,
            auth: {
                user: SENDER_EMAIL,
                pass: SENDER_PASSWORD
            }
        });
    
        return authData.sendMail({
            from: SENDER_EMAIL,
            to: `${contestant.email}`,
            subject: `Subscription nº ${contestant.uid} - Concluded!`,
            text: `This is a test.`,
            html: `${htmlBody}`
        });
    });
    

    I'm not sure to understand what you want to do with then(res=>SUCCESS_CODE=8888).catch(err=>SUCCESS_CODE=1313);. What is res? Maybe you mixup HTTPS Cloud Functions and background Cloud Functions?

    If you want to log something in the Cloud Functions log in case of success and error, you can do as follows:

    exports.sendEmail = functions.database.ref('Contestants/{contestantID}').onCreate((snap, context) => {
    
        let contestant = snap.val();
    
        let authData = nodemailer.createTransport(...);
    
        return authData.sendMail({
            from: SENDER_EMAIL,
            to: `${contestant.email}`,
            subject: `Subscription nº ${contestant.uid} - Concluded!`,
            text: `This is a test.`,
            html: `${htmlBody}`
        })
            .then(info => {
                console.log(info.messageId)  // For example, see the NodeMailer doc referred above
                return null; // Important, see CF doc
            })
            .catch(error => {
                console.log(error)
                return null; // Important
            })
    });