Email Database Results - node.js

I have a firebase database where onCreate Google Cloud Functions calls nodemailer and sends me an email. It all works fine but now I am trying to also include the data that was added to the database in the email. I can't get it to work, seemingly because it is not in a text format and I've tried converting to text and that doesn't seem to do it. What am I doing wrong?
const functions = require('firebase-functions');
const nodemailer = require('nodemailer');
// Configure the email transport using the default SMTP transport and a GMail account.
// For other types of transports such as Sendgrid see https://nodemailer.com/transports/
// TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables.
const gmailEmail = functions.config().gmail.email;
const gmailPassword = functions.config().gmail.password;
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: gmailEmail,
pass: gmailPassword,
},
});
exports.sendWelcomeEmail = functions.database.ref('/PickupRequests/{pushId}')
.onCreate(async(snapshot, context) => {
const val = snapshot.data;
const mailOptions = {
from: '<noreply#firebase.com>',
to: "mike#puravidalaundry.com",
subject: "New Pickup Request",
text: val //How do i convert this to a text format?
};
try {
await mailTransport.sendMail(mailOptions);
console.log('email sent');
} catch(error) {
console.error('There was an error while sending the email:', error);
}
return null;
});

To get the value from the snapshot, use snapshot.val(). So:
const val = snapshot.val();
Note that this is shown in an example in the documentation on handling event data for Realtime Database triggered Cloud Functions.

figured it out. I had to create a new variable const newvar = JSON.stringify(val) and then i said text: newvar

Related

Firebase doesn't send emails after deploying + no logs

I implemented the code below and it works perfectly fine when I run it in on local machine with npm start
However, when I deploy it on Firebase, the sendOrderEmail function doesn't work.
I don't even get any logs.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const {email, password} = require('./config');
const nodemailer = require('nodemailer');
const htmlToText = require('nodemailer-html-to-text').htmlToText;
admin.initializeApp();
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: email,
pass: password
}
});
mailTransport.use("compile", htmlToText());
const APP_NAME = 'the.Travelest';
exports.sendUserEmail = functions.database
.ref("/lettersRequest/{pushId}")
.onCreate(request => {
return sendOrderEmail(request.val().email);
});
async function sendOrderEmail(email){
const mailOptions = {
from: `${APP_NAME}`,
to: email,
subject: `Your order from ${APP_NAME}`,
html: `
<div>
<strong> Hello </strong>
World
</div>
`
};
return await mailTransport.sendMail(mailOptions);
}
UPDATE
After checking the logic, I believe that I've found the issues in another place.
So, the logic is - when I click on SUBMIT in form, I send the data to Firebase Runtime Database. And this action triggers the function above and send the email.
However, the SUBMIT button doesn't trigger the process it should trigger. I don't see even console.log result in the console, when I click on SUBMIT
Again, it works locally, when I run nom start
Here is the submit handler:
const handleSubmit = event => {
event.preventDefault();
setErrors(validate(values))
setIsSubmitting(true)
try{
const newRequestRef = database.ref('lettersRequest').push();
const newRequest = {
country: values.country,
travelersAmount: values.travelersAmount,
introExtro: values.introExtro,
comments: values.comments,
email: values.email,
phone: values.phone
};
newRequestRef.set({
email: values.email,
request: newRequest
});
console.log("no error")
}catch(e){
console.log("error")
}
}
You are not handling the promise returned by set(). Try this:
const handleSubmit = event => {
event.preventDefault();
setErrors(validate(values))
setIsSubmitting(true)
const newRequestRef = database.ref('lettersRequest').push();
const newRequest = {
country: values.country,
travelersAmount: values.travelersAmount,
introExtro: values.introExtro,
comments: values.comments,
email: values.email,
phone: values.phone
};
newRequestRef.set({
email: values.email,
request: newRequest
}).then(() => {
console.log("Request Added in Database")
}).catch(e => console.log(e));
}
If it logs 'Request Added in Database' then it has been added successfully and your function should trigger.
Additionally, this can also be done by a Callable Function which means you call the function directly from the client, do all the validation, add the data in database and send the email instead of using database triggers.
So, the issue was even more trivial than I could expect :D
I did deploy to firebase, but I've never did commit and build project...
As a result, nothing was updated after each deploy.
Stupid mistake

Add various fields in the text section of nodemailer

I'm sending mail from my angular app using nodemailer. I have a variable which has several attributes like firstname, middlename, email, mobile, address. I'm fetching this data from firebase and each variable can be accessed by writing $data.firstname, $data.email. I was able to send only 1 variable right now. I want to send all the variables to the mail with labels
So mail content should be
Email - abc#123
First Name - ABC
Address - LMN
Mobile - 7777777777
Please help me out.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const nodemailer = require('nodemailer');
admin.initializeApp()
require('dotenv').config()
const {SENDER_EMAIL, SENDER_PASS} = process.env;
exports.sendMailNotification1=functions.firestore.document('submissions/{docID}')
.onCreate((snap, ctx)=> {
const data=snap.data();
let authData=nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure:true,
auth:{
user: SENDER_EMAIL,
pass: SENDER_PASS
}
});
authData.sendMail({
from: 'xxx#gmail.com',
to: 'xyz#gmail.com',
subject: 'Appointment Info ',
text:`${data.fname}`,
html:`${data.email}`,
}).then(res=>console.log('Succesfully Sent')).catch(err=> console.log(err)
);
})
As explained in the NodeMailer doc, you can choose between:
using the message's text element for sending "the plaintext version of the message"
OR
using the message's html element for sending "the HTML version of the message".
So for example, if you use the HTML option you could use an HTML list as follows:
//...
const htmlContent = `<ul><li>Email - ${data.email}</li><li>Address - ${data.address}</li></ul>`;
return authData.sendMail({
from: 'xxx#gmail.com',
to: 'xyz#gmail.com',
subject: 'Appointment Info',
html: htmlContent
})
.then(res => {
console.log('Succesfully Sent');
return null;
})
.catch(err => {
console.log(err);
return null;
});
Note the addition of several returns in the code, see https://firebase.google.com/docs/functions/terminate-functions for more info on this key aspect.

How to send an e-mail using mailgun/mailchimp/etc in an express/node.js app

I want to send automated e-mails like order brief, sign-in e-mail, confirm e-mail, change password e-mail, etc to clients using mailchimp or mailgun or whatever e-mail delivery server because when I used nodemailer, the clients were receiving the e-mails in their spam inbox and sometimes not receiving at all.
Here's the code I used:
automated_emails.js file:
const nodemailer = require('nodemailer');
const ejs = require('ejs');
const user = 'xxx'
const pass = 'xxx';
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: { user, pass }
});
const emailPasswordChange = (email, uuid) => {
ejs.renderFile("./mail/forgot-password.ejs", { uuid }, (err, data) => {
if (err) return console.log(err)
let mailOptions = {
from: 'xxx',
to: email,
subject: "Forgot My Password",
html: data
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) return console.log(error);
});
})
}
module.exports.emailPasswordChange = emailPasswordChange;
The EJS file is a file that contains the template, and I pass to it the user info like e-mail, name, etc.
They are a bunch of functions I call inside the main index.js file.
How do you suggest me to implement this? Is there a way I can put mailchimp/mailgun/etc's email delivery method inside my nodemailer app?
To prevent moving your email to spam folder be sure that send email (from) is same as userEmail account which used by nodemailer.
I'm using gmail account to send emails using 'nodemailer' and it always success, and here is the code which I use:
const nodemailer = require('nodemailer');
var userEmail = 'yourUserName#gmail.com';
var userPassword = 'yourPassword';
var transporter = nodemailer.createTransport(`smtps://${userEmail}:${userPassword}#smtp.gmail.com`);
// setup e-mail data with unicode symbols
var mailOptions = {
from: userEmail, // sender address
to: 'abc1#hotmail.com, abc2#yahoo.com', // list of receivers
subject: 'Demo-1', // Subject line
text: 'Hello world from Node.js', // plaintext body
html: '<b>Hello world from Node.js</b>' // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function(error, info){
if(error){
return console.log(error);
}
console.log('Message sent: ' + info.response);
});

Node Mailer Error

I am using nodemailer in my Firebase Cloud Functions to send a mail when a data is added to the realtime database.
Code:
const functions = require('firebase-functions');
const nodemailer = require('nodemailer');
const gmailEmail = 'myemail.in#gmail.com';
const gmailPassword = 'mypassword';
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: gmailEmail,
password: gmailPassword
}
});
const APP_NAME = 'ABC In'
exports.salonCreatedAccount = functions.database.instance('abc-
in').ref('/abc/{def}').onCreate(event => {
const snapshot = event.data;
const val = snapshot.val()
console.log(val);
const email = val.email;
const displayname = val.name;
return sendconfirmationEmail(email, displayname);
});
function sendconfirmationEmail(email, displayName){
const mailOptions = {
from: `${APP_NAME} <abc.in#gmail.com>`,
to: email
};
mailOptions.subject = `Welcome to ${APP_NAME}!`;
mailOptions.text = `Some Text`;
return mailTransport.sendMail(mailOptions).then(() => {
console.log(`New welcome mail sent to ${email}`);
});
}
I am getting this following error while executing.
NOTE: I have made sure that the email and password is right and there's no mistake there.
Error:
Error: Missing credentials for "PLAIN"
at SMTPConnection._formatError (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:591:19)
at SMTPConnection.login (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:340:38)
at connection.connect (/user_code/node_modules/nodemailer/lib/smtp-transport/index.js:270:32)
at SMTPConnection.once (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:188:17)
at SMTPConnection.g (events.js:292:16)
at emitNone (events.js:86:13)
at SMTPConnection.emit (events.js:185:7)
at SMTPConnection._actionEHLO (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:1113:14)
at SMTPConnection._processResponse (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:747:20)
at SMTPConnection._onData (/user_code/node_modules/nodemailer/lib/smtp-connection/index.js:543:14)
How do I fix this?
Rename password to pass in auth object. for e.g
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: gmailEmail,
pass: gmailPassword
}
});
I had the same problem, and solved it like that.
found out by diving in the code of nodemailer where this message is being logged the code look like this.
if (this._auth.user && this._auth.pass) { // this condition <---
this._auth.credentials = {
user: this._auth.user,
pass: this._auth.pass
};
} else {
return callback(this._formatError('Missing credentials for "' + this._authMethod + '"', 'EAUTH', false, 'API'));
}
Hope this helps :)
Solved same error from a local nodejs test app, by what #Zaheen replied to: Nodemailer with Gmail and NodeJS
, part of his reply is copied here:
var smtpTransport = require('nodemailer-smtp-transport');
var transporter = nodemailer.createTransport(smtpTransport({
service: 'gmail',
host: 'smtp.gmail.com',
auth: {
user: 'somerealemail#gmail.com',
pass: 'realpasswordforaboveaccount'
}
}));
(BTW Accounts with 2FactorAuth cannot enable less secure apps).
I used nodemailer-smpt-transport, xoauth2, and added host to auth{}.
Haven't yet done it with Firebase, that's next ... hopefully.. :)
Using nodemailer, you have to providean email and password of the account you are sending the email from, Firebase stores that for you so you don't have to write it directly on your code.
For that to happen you have to configure the gmail.email and gmail.password Google Cloud environment variables.
In your console, within the path you store your functions /yourProject/functions$ set your variables this way:
firebase functions:config:set gmail.email="senderEmail#gmail.com" gmail.password="yourPassword"
and then you can use it this way:
const gmailEmail = functions.config().gmail.email;
const gmailPassword = functions.config().gmail.password;
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: gmailEmail,
pass: gmailPassword
}
});
I hope this is helpful for you all , it what was causing the 'missing credentialas plain error' in my case
According to the official docs, GMail may disable basic auth in some special cases.
To prevent having login issues you should either use OAuth2 or use another delivery provider and preferably a dedicated one.
Read more here: https://nodemailer.com/usage/using-gmail/
I had this same error and could not find any solution online, until now.
My solution for this exact error "Missing credentials for "PLAIN"":
Go to Authentication in Firebase Console
Click on Sign-In Method
Select Google
Make sure it is enabled
That solved my error. (Same code as you)

Sending emails using Mailgun with NodeMailer package

A couple of days ago I realized that Google has changed the security of gmail accounts, particularly for the possibility of sending emails from applications. After Googling around for a while I couldn't find a fix for it.
So, I resorted to using Mailgun. I created an account and had it enabled with Business verification. However, I still can't send emails. I keep getting an error about the requested URL not being found.
I am suspecting that since I haven't set up a domain yet, it is not picking the mailgun domain it provided by default. Could someone show me how to test sending emails using Mailgun from NodeMailer indicating the sandbox name provided by mailgun.
thanks in advance
José
var nodemailer = require('nodemailer');
// send mail with password confirmation
var transporter = nodemailer.createTransport( {
service: 'Mailgun',
auth: {
user: 'postmaster#sandboxXXXXXXXXXXXXXXXX.mailgun.org',
pass: 'XXXXXXXXXXXXXXXX'
}
});
var mailOpts = {
from: 'office#yourdomain.com',
to: 'user#gmail.com',
subject: 'test subject',
text : 'test message form mailgun',
html : '<b>test message form mailgun</b>'
};
transporter.sendMail(mailOpts, function (err, response) {
if (err) {
//ret.message = "Mail error.";
} else {
//ret.message = "Mail send.";
}
});
I created the Nodemailer transport for mailgun.
Here it how it works.
You install the package with npm install as you would do with any package, then in an empty file:
var nodemailer = require('nodemailer');
var mg = require('nodemailer-mailgun-transport');
// This is your API key that you retrieve from www.mailgun.com/cp (free up to 10K monthly emails)
var auth = {
auth: {
api_key: 'key-1234123412341234',
domain: 'sandbox3249234.mailgun.org'
}
}
var nodemailerMailgun = nodemailer.createTransport(mg(auth));
nodemailerMailgun.sendMail({
from: 'myemail#example.com',
to: 'recipient#domain.com', // An array if you have multiple recipients.
subject: 'Hey you, awesome!',
text: 'Mailgun rocks, pow pow!',
}, function (err, info) {
if (err) {
console.log('Error: ' + err);
}
else {
console.log('Response: ' + info);
}
});
Replace your API key with yours and change the details and you're ready to go!
It worked me, when I added the domain also to the auth object (not only the api_key). Like this:
var auth = {
auth: {
api_key: 'key-12319312391',
domain: 'sandbox3249234.mailgun.org'
}
};

Resources