Add various fields in the text section of nodemailer - node.js

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.

Related

Nodemailer - massive delay or missing emails in production

I currently have a site using Nodemailer & Gmail that works fine in my local development environment - any email sends instantly to the desired address.
Sadly, in production, only the admin notifications are being sent and the user ones are taking a very long time to deliver or not delivering at all. Ones that have arrived successfully took around 1 hour. The receiving email for admin emails is of the same domain as the URL of the website which makes me consider whether it's a domain verification issue. Only external recipients seem to get the delay.
My code is as follows:
const nodemailer = require('nodemailer')
const gmailUser = process.env.GMAIL_USER
const gmailPass = process.env.GMAIL_PASS
const appTitle = process.env.APP_TITLE
const receivingEmail = process.env.MAIL_RECEIVE
const smtpTransporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: gmailUser,
pass: gmailPass
}
})
const emailConfirmation = (userEmail) => {
const userMailOptions = {
from: appTitle,
to: userEmail,
subject: `${appTitle} - User Confirmation`
text: 'User Confirmation'
}
const adminMailOptions = {
from: appTitle,
to: receivingEmail,
subject: `${appTitle} - Admin Confirmation`,
text: 'Admin Confirmation'
}
Promise.all([
smtpTransporter.sendMail(userMailOptions),
smtpTransporter.sendMail(adminMailOptions)
])
.then((res) => { return true })
.catch((err) => { console.log("Failed to send email confirmations: ", err); return false })
}
I then call the function in a POST handler as follows:
emailConfirmation(user.email)
Am I doing something wrong in my code, or is this likely to be some sort of domain verification error?
I ended up deciding to switch to a different mail provider and have since had no issues.

How to Resolve Error Sending Email Using nodemailer googleapi?

Last week I initially posted this asking for help using nodemailer and googleapi. I'm trying to use nodemailer and googleapis to send an email. I have set up my project in https://console.cloud.google.com/ and have set my CLIENT_ID, CLIENT_SECRET, CLIENT_REDIRECT_URI and REFRESH_TOKEN in a .env and have confirmed that the values are being populated. In debug mode I have noticed the following error stack when I send the error:
'Error: invalid_grant\n at Gaxios._request (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/gaxios/build/src/gaxios.js:130:23)\n at processTicksAndRejections
(node:internal/process/task_queues:96:5)\n
at async OAuth2Client.refreshTokenNoCache (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:174:21)\n
at async OAuth2Client.refreshAccessTokenAsync (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:198:19)\n
at async OAuth2Client.getAccessTokenAsync (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:227:23)\n
at async sendMail (/Users/ENV/Tutoring-Invoice-Management-System/service/send-email.js:17:29)'
The code is below. I have edited it based on an answer to the question already. My question now is, why am I getting the invalid_grant error? Based on the formal documentation I have set everything up correctly in https://console.cloud.google.com/apis/credentials/oauthclient. But perhaps there is an issue there?
const nodemailer = require('nodemailer');
const { google } = require('googleapis');
require('dotenv').config();
console.log("CLIENT_ID: " + process.env.CLIENT_ID);
console.log("CLIENT_SECRET: " + process.env.CLIENT_SECRET);
console.log("CLIENT_REDIRECT_URI: " + process.env.REDIRECT_URI);
console.log("REFRESH_TOKEN: " + process.env.REFRESH_TOKEN);
const oAuth2Client = new google.auth.OAuth2(process.env.CLIENT_ID, process.env.CLIENT_SECRET, process.env.REDIRECT_URI);
console.log("oAuth2Client: " + oAuth2Client);
oAuth2Client.setCredentials({refresh_token: process.env.REFRESH_TOKEN})
async function sendMail() {
try {
const accessToken = await oAuth2Client.getAccessToken()
const transport = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: 'OAuth2'
}
});
const mailOptions = {
from: 'envolonakis#gmail.com',
to: 'envolonakis#gmail.com',
subject: "Test Email API Subject",
text: "Test Email API Text",
html: "<h1> Test Email API HTML </h1>",
auth: {
user: process.env.OWNER_EMAIL,
accessToken: accessToken.token
}
}
const result = await transport.sendMail(mailOptions);
return result;
} catch (error) {
console.log(error.stack);
return error;
}
}
sendMail()
From the official documentation, this is what you need to use:
try {
const accessToken = await oAuth2Client.getAccessToken()
const transport = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: 'OAuth2'
}
});
const mailOptions = {
from: process.env.OWNER_EMAIL,
to: process.env.RECIPIENT,
subject: "Test Email API Subject",
text: "Test Email API Text",
html: "<h1> Test Email API HTML </h1>",
auth: {
user: process.env.OWNER_EMAIL,
accessToken: accessToken.token
}
}
const result = await transport.sendMail(mailOptions);
return result;
} catch (error) {
return error;
}
One error that you have whilst using the google api authentication library is with the token. You were passing the complete token object to the auth configuration of nodemailer instead of just the access token string. Another thing to keep in mind, adding or removing parameters to the auth configuration of nodemailer will lead to different errors.
Using #Morfinismo 's solution in addition to creating a new oAuth on https://developers.google.com/oauthplayground resolved my issue.

Email Database Results

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

How to send customize e-mail with Firebase cloud functions

I want to send a mail once a user is created with a firebase cloud functions, using nodemail and postmark.
I followed this tutorial : Tutorial link from Dave Martin
But keep getting this error:
There was an error while sending the welcome email: { status: 422, message: 'Zero recipients specified', code: 300 }
Here is my code to send a mail from cloud functions:
//Mail
const nodemailer = require('nodemailer')
const postmarkTransport = require('nodemailer-postmark-transport')
// Google Cloud environment variable used:
// firebase functions:config:set postmark.key="API-KEY-HERE"
const postmarkKey = functions.config().postmark.key
const mailTransport = nodemailer.createTransport(postmarkTransport({
auth: {
apiKey: postmarkKey
}
}))
exports.OnUserCreation = functions.auth.user().onCreate((user) =>
{
console.log("user created: " + user.data.uid);
console.log("user email: " + user.data.email);
sendEmail(user);
})
function sendEmail(user)
{
// Send welcome email to new users
const mailOptions =
{
from: '"test" <test#test.com>',
to: user.email,
subject: 'Welcome!',
html: 'hello'
}
// Process the sending of this email via nodemailer
return mailTransport.sendMail(mailOptions)
.then(() => console.log('Welcome confirmation email sent'))
.catch((error) => console.error('There was an error while sending the welcome email:', error))
}
My postmark.key is already setup in the firebase config... The API tell me the problem is the format I use to send the mail informations.. How could I fix it ?
Update
I also tried to modify the mailOptions as follow and still the same error:
const mailOptions = {
from: 'test#test.com',
to: user.email,
subject: 'Welcome!',
textBody: 'hello'
}
Decided to restart from scratch by following only postmark documentation (wich is really good by the way).
So here are the very simple steps to send mail from events in firebase cloud functions:
1- download packages:
Run: npm install postmark
2- register to postmark
Register to PostMark
- then find your API key.
3- setup firebase environment config:
Run : firebase functions:config:set postmark.key="API-KEY-HERE"
4 index.js code to be added:
//Mail
const postmark = require('postmark')
const postmarkKey = functions.config().postmark.key;
const mailerClient = new postmark.ServerClient(postmarkKey);
exports.OnUserCreation = functions.auth.user().onCreate((user) => {
console.log("user created: " + user.data.uid);
console.log("user email: " + user.data.email);
return sendEmail(user);
})
// Send welcome email to new users
function sendEmail(user) {
const mailOptions = {
"From": "XYZ#YOURDOMAIN.com",
"To": user.data.email,
"Subject": "Test",
"TextBody": "Hello from Postmark!"
}
return mailerClient.sendEmail(mailOptions)
.then(() => console.log('Welcome confirmation email sent'))
.catch((error) => console.error('There was an error while sending the welcome email:', error))
}
That's it.
No need to download nodemailer nor use a transporter.

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);
});

Resources