0
votes

I am adding data to the realtime database with React JS, a contact form and the firebase initialized. That all works.

However, I'm trying to implement an email to be sent to me when a new contact form has been submitted. CURRENT PROBLEM: The cloud function is deployed yet when I submit the form (and realtime db is added to), nothing happens. Not even an error message in the firebase console.

Please can you take a look at my code and offer some advice as to how I can get the automatic emails sent.

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

const email = process.env.REACT_APP_SENDER_EMAIL;
const pass = process.env.REACT_APP_SENDER_PASS;

exports.sendEmailNotification = functions.firestore.document('messages/{id}')
  .onCreate((snap, ctx) => {
    const data = snap.data();
    let authData = nodemailer.createTransport({
      host: 'smtp.gmail.com',
      port: 465,
      secure: true,
      auth: {
        user: email,
        pass: pass
      }
    });
    authData.sendMail({
      from: data.email,
      to: data.to,
      subject: data.name + ' sent a message',
      text: data.text,
    }).then(res => console.log('email sent')).catch(err => console.log(err));
  });
2
console log the snap and ctx params and show that here - Rutvik Bhatt
{"@type":"type.googleapis.com/google.cloud.audit.AuditLog","status":{},"authenticationInfo":{"principalEmail":"[email protected]"},"serviceName":"cloudfunctions.googleapis.com","methodName":"google.cloud.functions.v1.CloudFunctionsService.CreateFunction","resourceName":"projects/react-website-afe39/locations/us-central1/functions/sendEmailNotification"} - James Ross Codes
This is all the info returned, in the console log on firebase - James Ross Codes
What do you console? snap or ctx? - Rutvik Bhatt
I did console.log(snap, ctx); - James Ross Codes

2 Answers

1
votes

Your function needs to return a promise that resolves when all the asynchronous work is complete.

return authData.sendMail({
  from: data.email,
  to: data.to,
  subject: data.name + ' sent a message',
  text: data.text,
})

Returning this promise lets Cloud Functions know when it's safe to clean up and move on.

0
votes

I first attempted creating this as a firebase cloud function as well, but I shifted towards building nodemailer on the server. Working in firebase cloud functions I was using the loophole of downgrading to node: 8 in package.json (which is deprecated) and I was being forced into making a Google firebase paid plan. Both items were driving me into a corner that I didn't want to be in.

This is the result of nodemailer in node.js thanks to https://www.youtube.com/watch?v=nF9g1825mwk

    const express = require('express')
require('dotenv').config()
const bodyParser = require('body-parser')
const exphbs = require('express-handlebars')
const path = require('path')
const nodemailer = require('nodemailer')


const app = express()

const email_from = process.env.EMAIL_FROM;
const sender_pass = process.env.SENDER_PASS;
const email_to = process.env.EMAIL_TO;


// View engine setup
app.engine('handlebars', exphbs())
app.set('view engine', 'handlebars')

//body parser
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());


//static folder
app.use('/public', express.static(path.join(__dirname, 'public')))

app.get('/', (req, res) => {
    res.render('contact', { layout: false })
})

app.post('/send', (req, res) => {
    const output = `
    <p>You have a new submission</p>
    <h3>Contact Details</h3>
    <ul>
    <li>Name: ${req.body.name}</li>
    <li>Company: ${req.body.company}</li>
    <li>Email: ${req.body.email}</li>
    <li>Phone: ${req.body.phone}</li>
   
    </ul>
    <h3>Message</h3>
    <p> ${req.body.message} </p> `;

    async function main() {
        // Generate test SMTP service account from ethereal.email
        // Only needed if you don't have a real mail account for testing
        // let testAccount = await nodemailer.createTestAccount();

        // create reusable transporter object using the default SMTP transport
        let transporter = nodemailer.createTransport({
            host: "smtp.ethereal.email",
            port: 587,
            secure: false, // true for 465, false for other ports
            auth: {
                user: email_from,
                pass: sender_pass
            },
        });

        // send mail with defined transport object
        let info = await transporter.sendMail({
            from: email_from,
            to: email_to,
            subject: 'New Submission from Dean Productions!',
            text: 'new submission',
            html: output,
        });

        console.log("Message sent: %s", info.messageId);
        // Message sent: <[email protected]>

        // Preview only available when sending through an Ethereal account
        console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
        // Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...

        res.render('contact', { layout: false, msg: 'Message has been sent!' })
    }

    main().catch(console.error);
})

app.listen(3000, () => console.log('Server started...'))