I have a mail route which is using ejs templates to choose different files. Now I want to check for different files and if the files does not exist or null it should choose default "en.ejs" file
inside ejs.renderFile I want to check for if(selectedLanguage !==null{}) but I am not sure how can I do it.
router.post('/mail', (req, res) => {
const subject = 'Test Mail';
const url = process.env.REPORT_URL;
const selectLanguage = req.body.selectedLang
sgMail.setApiKey(SGAPIKEY);
ejs.renderFile(__dirname + `/../ejs/reports/${selectLanguage}.ejs`, {
url: url
},
function (err, data) {
if (err) {
return err;
} else {
const msg = {
to: req.body.sendTo_email,
from: "test#test.com",
subject: subject,
html: data,
cc: req.body.cc,
attachments: [{
content: req.body.pdfBase64,
filename: 'file.pdf',
type: 'application/pdf',
disposition: 'attachment'
}]
};
sgMail.send(msg, error => {
if (error) {
return res.status(400).send({
sent: false
});
} else {
return res.status(200).send({
sent: true
});
}
});
}
});
});
You can check if the template file for the selected language exists (by using fs.access) and fallback to the en.ejs template before calling ejs.renderFile:
const fs = require('fs');
const getTemplateFileName = (lang, callback) => {
const defaultTemplate = __dirname + '/../ejs/reports/en.ejs';
const selectedLangTemplate = __dirname + `/../ejs/reports/${lang}.ejs`;
fs.access(selectedLangTemplate, fs.constants.F_OK, (err) => {
if (err) {
callback(defaultTemplate);
} else {
callback(selectedLangTemplate)
}
})
};
router.post('/mail', (req, res) => {
const subject = 'Test Mail';
const url = process.env.REPORT_URL;
const selectLanguage = req.body.selectedLang
sgMail.setApiKey(SGAPIKEY);
getTemplateFileName(selectLanguage, (filename) => {
ejs.renderFile(filename, { url }, function (err, data) {
if (err) {
return err;
} else {
const msg = {
to: req.body.sendTo_email,
from: "test#test.com",
subject: subject,
html: data,
cc: req.body.cc,
attachments: [{
content: req.body.pdfBase64,
filename: 'file.pdf',
type: 'application/pdf',
disposition: 'attachment'
}]
};
sgMail.send(msg, error => {
if (error) {
return res.status(400).send({
sent: false
});
} else {
return res.status(200).send({
sent: true
});
}
});
}
})
});
});
Related
I m trying to write form data to a json database file, while also using nodeMailer to either before or after the writeFile, problem is that with my code, only the writeFile appears to be executing while the nodeMailer doesn't execute, however, if i omit the file Write, then the nodeMailer executes and i m able to send email. can any one advice on how I can run both tasks?
const messageDB = {
messages: require('../models/messageDB.json'),
setMessage: function (data) {
this.messages = data
}
}
const { body, validationResult } = require('express-validator')
const fs = require('fs')
const path = require('path')
const nodemailer = require('nodemailer')
exports.message_controller_get = (req, res, next) => {
res.render('index')
}
exports.message_controller_post = [
body('name', 'Full names must be specified').isLength({ min: 2, max: 40 }).trim(),
body('email', 'Email address must be specified').isEmail().isLength({ min: 3, max: 40 }),
body('msg', 'Message must be specified').isLength({ min: 20, max: 1000 }),
(req, res, next) => {
const errors = validationResult(req)
if (!errors.isEmpty()) {
console.log('there are errors: ' + errors.array())
return
}
const message = {
name: req.body.name,
email: req.body.email,
msg: req.body.msg
}
const transporter = nodemailer.createTransport({
host: 'smtp.ethereal.email',
port: 587,
auth: {
user: 'lila.greenfelder71#ethereal.email',
pass: 'DQnhbPkHBRzPU1UkAt'
}
});
const mailOption = {
from: 'Fred Foo 👻" <fred#homexclusiv.com>',
to: 'payiyke#gmail.com',
subject: `Message from ${req.body.email}:`,
text: req.body.msg
}
messageDB.setMessage([...messageDB.messages, message])
fs.writeFile(
path.join(__dirname, '..', 'models', 'messageDB.json'),
JSON.stringify(messageDB.messages),
(err) => {
if (err){
return res.send(err)
} else {
transporter.sendMail(mailOption, (error, info) => {
if (error) {
console.log(error);
res.send('error')
} else {
console.log('Email sent :' + info.response)
res.send('success')
}
})
/* return res.send('success') */
}
}
)
/* console.log(`${message.name}\t${message.email}`) */
}
]
not to worry, password is temporary
It's likely that the writeFile method is completing before the nodemailer code block can execute. You can try to put the nodemailer code block in a separate function and call it after the writeFile method completes.
This way, the writeFile method will be executed first and then the sendEmail function will be called. The sendEmail function will then execute the nodemailer code block to send the email.
You can try something like this
const messageDB = {
messages: require('../models/messageDB.json'),
setMessage: function (data) {
this.messages = data
}
}
const { body, validationResult } = require('express-validator')
const fs = require('fs')
const path = require('path')
const nodemailer = require('nodemailer')
exports.message_controller_get = (req, res, next) => {
res.render('index')
}
exports.message_controller_post = [
body('name', 'Full names must be specified').isLength({ min: 2, max: 40 }).trim(),
body('email', 'Email address must be specified').isEmail().isLength({ min: 3, max: 40 }),
body('msg', 'Message must be specified').isLength({ min: 20, max: 1000 }),
(req, res, next) => {
const errors = validationResult(req)
if (!errors.isEmpty()) {
console.log('there are errors: ' + errors.array())
return
}
const message = {
name: req.body.name,
email: req.body.email,
msg: req.body.msg
}
const transporter = nodemailer.createTransport({
host: 'smtp.ethereal.email',
port: 587,
auth: {
user: 'lila.greenfelder71#ethereal.email',
pass: 'DQnhbPkHBRzPU1UkAt'
}
});
const mailOption = {
from: 'Fred Foo 👻" <fred#homexclusiv.com>',
to: 'payiyke#gmail.com',
subject: `Message from ${req.body.email}:`,
text: req.body.msg
}
messageDB.setMessage([...messageDB.messages, message])
fs.writeFile(
path.join(__dirname, '..', 'models', 'messageDB.json'),
JSON.stringify(messageDB.messages),
(err) => {
if (err){
return res.send(err)
} else {
sendEmail(transporter, mailOption, res);
}
}
)
/* console.log(`${message.name}\t${message.email}`) */
}
]
function sendEmail(transporter, mailOption, res) {
transporter.sendMail(mailOption, (error, info) => {
if (error) {
console.log(error);
res.send('error')
} else {
console.log('Email sent :' + info.response)
res.send('success')
}
})
}
I am trying to get my e-commerce web app to send emails on purchasing but when I try to pay for things I get the mailgun.messages is not a function I've reverted changes and re coded it twice but this is a different error I'm not sure how to resolve this. Is there another way to use mailgun's api? Here is the code below:
orderRoutes.js:
orderRouter.put(
"/:id/pay",
isAuth,
expressAsyncHandler(async (req, res) => {
const order = await Order.findById(req.params.id).populate(
"user",
"email firstName"
);
if (order) {
order.isPaid = true;
order.paidAt = Date.now();
order.paymentResult = {
id: req.body.id,
status: req.body.status,
update_time: req.body.update_time,
email_address: req.body.email_address,
};
const updateOrder = await order.save();
mailgun.messages().send(
{
from: "Sales <sales#cocoTiCosmetics.com>",
to: `${order.user.firstName} <${order.user.email}>`,
subject: `New Order ${order._id}`,
html: payOrderEmailTemplate(order),
},
(error, body) => {
if (error) {
console.log(error);
} else {
console.log(body);
}
}
);
res.send({ message: "Order Paid", order: updateOrder });
} else {
res.status(404).send({ message: "Order Not Found" });
}
})
);
utils.js
export const mailgun = () =>
mg({
apiKey: process.env.MAILGUN_API_KEY,
domain: process.env.MAILGUN_DOMAIN,
});
My CSV file contains 3 columns: first name,last name,email. I want to add all the valid lines of the CSV file in the users table in the database. For example: if the CSV file has 10 lines where line 2 is missing first name and line 3 has invalid email, I want to see 8 users added to database. After adding the users from the CSV file, it should display how many users were added and how many failed.
My model:
const User = sequelize.define(
"users",
{
first_name: {
type: Sequelize.STRING(60),
allowNull: false,
},
last_name: {
type: Sequelize.STRING(60),
allowNull: false,
},
email: {
type: Sequelize.STRING(255),
allowNull: false,
},
My Controller:
const upload = async (req, res) => {
try {
if (req.file == undefined) {
return res.status(400).send("Please upload a CSV file!");
}
let users = [];
console.log(" __basedir", __basedir);
let path = __basedir + "/uploads/" + req.file.filename;
fs.createReadStream(path)
.pipe(csv.parse({ headers: true }))
.on("error", (error) => {
throw error.message;
})
.on("data", (row) => {
users.push(row);
})
.on("end", () => {
User.bulkCreate(users, {
validate: true,
})
.then(() => {
res.status(200).send({
message:
`Uploaded ${users.length} data successfully from ` + req.file.originalname,
});
})
.catch((error) => {
res.status(500).send({
message: `Fail to import ${users.length} into database!`,
error: error.message,
});
});
});
} catch (error) {
res.status(500).send({
message: "Could not upload the file: " + req.file.originalname,
});
}
};
How can I solve this?
I solve it using fast-csv package
import * as csv from 'fast-csv';
const upload = async (req, res) => {
try {
if (req.file == undefined) {
return res.status(400).send("Please upload a CSV file!");
}
let users = [];
console.log(" __basedir", __basedir);
let path = __basedir + "/uploads/" + req.file.filename;
console.log("path", path);
let emailPattern= /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
let successCount = 0;
let errorCount = 0;
fs.createReadStream(path)
.pipe(csv.parse({ headers: [ undefined,'first_name', 'last_name', 'email', undefined ],renameHeaders: true, ignoreEmpty: true }))
.validate(data => data.first_name !== '' && data.last_name !== '' && emailPattern.test(data.email))
.on("error", (error) => {
throw error.message;
})
.on("data", (row) => {
successCount++;
users.push(row);
console.log(`ROW=${JSON.stringify(row)}`)
})
.on('data-invalid', (row, rowNumber) => {
errorCount++;
console.log(`Invalid [rowNumber=${rowNumber}] [row=${JSON.stringify(row)}]`)
})
.on("end", (rowCount) => {
console.log(`Parsed ${rowCount} rows`)
User.bulkCreate(users, {
validate: true,
})
.then(async() => {
res.status(200).json({
error: false,
success:
`Uploaded ${successCount} row successfully from ` + req.file.originalname,
failed:`Uploaded ${errorCount} row failed from ` + req.file.originalname,
});
})
.catch((error) => {
console.log(error);
res.status(500).json({
error: error.message,
failed: `Fail to import ${users.length} row into database!`,
});
});
});
} catch (error) {
console.log(error);
console.log(error.message);
res.status(500).json({
error: error.message,
failed: "Could not upload the file: " + req.file.originalname,
});
}
};
I have created a emailHelper in my project for sending emails.
I wan to get a callback once the email sent successfully
//emailHelper.js
module.exports = {
sendMail: (options) => {
var transporter = nodemailer.createTransport({
service: 'SendGrid',
auth: {
user: keys.sendGridUsername,
pass: keys.sendGridPassword
}
});
const mailOptions = {
from: options.from,
to: options.to,
subject: options.subject,
html: options.content
};
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
return false;
}
else {
console.log('mail sent');
return true;
}
});
}
}
I want to save data to database only if the email is sent
const { sendMail } = require('../helpers/emailHelper');
mail: (req, res, next) => {
const emailOptions = {
from: 'from#email.com',
to: 'to#email.com',
subject: 'subject',
content: 'text'
};
const mailResetLink = sendMail(emailOptions);
if(mailResetLink) {
//success save data
} else {
//failure trrow error
}
}
thank you
Wrap your sendMail in promise and return it:
return new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
reject();
}
else {
console.log('mail sent');
resolve();
}
});
});
Than you would be able to do this:
sendMail(emailOptions).then(() => {
// success save data
}).catch(() => {
// failure trrow error
});
Using async/await you would need to change promise to return some identifier in any case, boolean in this case, and than tweak mail function:
return new Promise((resolve) => {
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
resolve(false);
}
else {
console.log('mail sent');
resolve(true);
}
});
});
mail: async (req, res, next) => {
const emailOptions = {
from: 'from#email.com',
to: 'to#email.com',
subject: 'subject',
content: 'text'
};
const mailResetLink = await sendMail(emailOptions);
if(mailResetLink) {
//success save data
} else {
//failure trrow error
}
}
this is my code: i am getting perfect output in postman.but i want the output to send through my mail.In this code var result i am getting error i cannot able to get the responses.
var startBroadcasting = function (req, res) {
authToken = req.headers.authorization;
userAuthObj = JSON.parse(UserAuthServices.userAuthTokenValidator(authToken));
var todayDate = new Date();
var expireDate = new Date(userAuthObj.expire_date);
tokenOK = TokenValidator.validateToken(userAuthObj.user_id, authToken).then(function (userSessions) {
if (userSessions.length === 1) {
if (expireDate >= todayDate) {
template_id = req.params.id;
image_id = req.params.img_id;
TemplateController.findById(template_id, {
attributes: {
exclude: ['created_by', 'created_on', 'updated_by', 'updated_on']
},
include: [{
attributes: {
exclude: ['created_by', 'created_on', 'updated_by', 'updated_on']
},
model: Broadcasting,
where: {
id: image_id,
}
},
]
}
).then(function (templatefindByid) {
BccSetting.findAll({
where: {
template_id: template_id
}
}).then(bccSettings => {
res.status(200).json({
id: templatefindByid.id,
name: templatefindByid.name,
template_images: templatefindByid.template_images,
bcc_settings: bccSettings,
})
}).catch(err => {
console.log(err);
res.status(404).json({
message: ' not found...'
});
});
}).catch(function (err) {
console.log(err);
res.status(404).json({
message: 'not found...'
});
});
} else {
res.status(401).json({
message: 'Not ...'
});
}
} else {
res.status(401).json({
message: 'Expired...'
});
}
}).catch(function (err) {
res.status(401).json({
message: 'Expired...'
});
});
var result = "Hi " + template_images.client_name + "!We are pleased to inform you that " + template_images.client_name + " newschannel streaming has been stopped sucessfully on " +template_images.destination_type + "" +
"" +
"This email was sent from a notification-only address that cannot accept incoming email. Please do not reply to this message.";
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
auth: true,
active: true,
secure: true,
requireTLS: true,
auth: {
user: 'trans#gmail.com',
pass: 'wertyy'
}
});
let mailOptions = {
from: 'trans#gmail.com',
to: 'wwww#gmail.com',
bcc: bcc_setting.bcc_setting,// here i want bcc setting data
subject: 'yvnuyybymyed',
html: 'result'
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log("mail not sent" + error.message);
}
console.log('success');
});
};