How to send message with nodemailer and email-templates? - javascript

I try to send email with nodemailer and email-templates. Now I have example from here example email templates. But when I check this code, I have error a promise was rejected with a non-error: [object Undefined]
Help me please. This is my code
var nodemailer = require('nodemailer');
var EmailTemplate = require('email-templates').EmailTemplate;
exports.sendOne = function () {
var templatesDir = config.templatesDir;
var template = new EmailTemplate(path.join(templatesDir, 'hello.jade'))
var transport = nodemailer.createTransport({
service: config.service,
auth: config.auth
});
// An example users object with formatted email function
var locals = {
email: 'example#mail.com',
name: {
first: 'Mamma',
last: 'Mia'
}
}
// Send a single email
template.render(locals, function (err, results) {
if (err) {
return console.error(err)
}
transport.sendMail({
from: 'Spicy Meatball <spicy.meatball#spaghetti.com>',
to: locals.email,
subject: 'Mangia gli spaghetti con polpette!',
html: results.html,
text: results.text
}, function (err, responseStatus) {
if (err) {
return console.error(err)
}
console.log(responseStatus.message)
})
})
}
My error :
Warning: a promise was rejected with a non-error: [object Undefined]
at /home/project/node_modules/email-templates/lib/util.js:31:39
at FSReqWrap.oncomplete (fs.js:82:15)
From previous event: ...
Tell me please how to fix this error? thanks!
UPDATE code
exports.sendOne = function () {
var nodemailer = require("nodemailer");
var transport = nodemailer.createTransport({
service: "gmail",
auth: {
user: "test#gmail.com",
pass: "123456",
},
});
var EmailTemplate = require("email-templates").EmailTemplate;
var path = require("path");
var templateDir = path.join(__dirname, "templates", "hello");
var myTemplate = new EmailTemplate(templateDir);
var locals = {
email: "example#mail.com",
name: {
first: "Mamma",
last: "Mia",
},
};
myTemplate.render(locals, function (err, result) {
// result.html
// result.text
if (err) {
return console.error(err);
}
transport.sendMail(
{
from: "Spicy Meatball <spicy.meatball#spaghetti.com>",
to: locals.email,
subject: "Mangia gli spaghetti con polpette!",
html: results.html,
text: results.text,
},
function (err, responseStatus) {
if (err) {
return console.error(err);
}
console.log(responseStatus.message);
return responseStatus; // return from status or as you need;
}
);
});
};
I updated my code but now i have error { [Error: ENOENT: no such file or directory, stat '/path-to-my-project/templates/hello''] errno: -2, code: 'ENOENT', syscall: 'stat', path: '/path-to-my-project/templates/hello' }

I guess template rendering issue and you should return something from function (err, responseStatus){} for success
Here I assume hello.jade in templates folder and templates folder in root directory and ensure jade is using as template engine
can try it
var EmailTemplate = require('email-templates').EmailTemplate;
var path = require('path');
var templateDir = path.join(__dirname, 'templates', 'hello');
var myTemplate = new EmailTemplate(templateDir);
var locals = {
email: 'example#mail.com',
name: {
first: 'Mamma',
last: 'Mia'
}
}
myTemplate .render(locals , function (err, result) {
// result.html
// result.text
if (err) {
return console.error(err)
}
// check here what is showing in your result
transport.sendMail({
from: 'Spicy Meatball <spicy.meatball#spaghetti.com>',
to: locals.email,
subject: 'Mangia gli spaghetti con polpette!',
html: results.html,
text: results.text
}, function (err, responseStatus) {
if (err) {
return console.error(err)
}
console.log(responseStatus.message)
return responseStatus;// return from status or as you need;
})
})
Updated: As far I guess it's not nodemailer related issue it's may be template rendering issue. can check by directory or by html page.

Thanks to the previous contributions I have been able to adapt Nodemailer with the current version of email-emplates
const nodemailer = require('nodemailer');
const Email = require('email-templates');
const path = require('path');
//Nodemailer Transporter
const transport = nodemailer.createTransport({
host: "mail.mydomain.com",
port: 465,
secure: true,
auth: {
user: "noreply#mydomain.com",
pass: "841%POHYRYK%",
},
tls: {
rejectUnauthorized: false
}
});
//Generate template (Example: templates/emails/demo/index.pug)
var template = path.join(__dirname, 'templates/emails', 'demo');
var email = new Email({views: { root: template }});
var locals = {email:'myemail#gmail.com', username:'CompaCode'};
async function(){
var html = await email.render(template, locals);
//Send Email
await transport.sendMail({from: 'Apolobit <noreply#apolobit.com>', to: locals.email, subject:'Demo Subject', html});
}

Related

Send dynamic zip files using nodemailer [duplicate]

I have code that send email with nodemailer in nodejs but I want to attach file to an email but I can't find way to do that I search on net but I could't find something useful.Is there any way that I can attach files to with that or any resource that can help me to attach file with nodemailer?
var nodemailer = require('nodemailer');
var events = require('events');
var check =1;
var events = new events.EventEmitter();
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "gmail",
auth: {
user: "example#gmail.com",
pass: "pass"
}
});
function inputmail(){
///////Email
const from = 'example<example#gmail.com>';
const to = 'example#yahoo.com';
const subject = 'example';
const text = 'example email';
const html = '<b>example email</b>';
var mailOption = {
from: from,
to: to,
subject: subject,
text: text,
html: html
}
return mailOption;
}
function send(){
smtpTransport.sendMail(inputmail(),function(err,success){
if(err){
events.emit('error', err);
}
if(success){
events.emit('success', success);
}
});
}
///////////////////////////////////
send();
events.on("error", function(err){
console.log("Mail not send");
if(check<10)
send();
check++;
});
events.on("success", function(success){
console.log("Mail send");
});
Include in the var mailOption the key attachments, as follow:
var mailOptions = {
...
attachments: [
{ // utf-8 string as an attachment
filename: 'text1.txt',
content: 'hello world!'
},
{ // binary buffer as an attachment
filename: 'text2.txt',
content: new Buffer('hello world!','utf-8')
},
{ // file on disk as an attachment
filename: 'text3.txt',
path: '/path/to/file.txt' // stream this file
},
{ // filename and content type is derived from path
path: '/path/to/file.txt'
},
{ // stream as an attachment
filename: 'text4.txt',
content: fs.createReadStream('file.txt')
},
{ // define custom content type for the attachment
filename: 'text.bin',
content: 'hello world!',
contentType: 'text/plain'
},
{ // use URL as an attachment
filename: 'license.txt',
path: 'https://raw.github.com/andris9/Nodemailer/master/LICENSE'
},
{ // encoded string as an attachment
filename: 'text1.txt',
content: 'aGVsbG8gd29ybGQh',
encoding: 'base64'
},
{ // data uri as an attachment
path: 'data:text/plain;base64,aGVsbG8gd29ybGQ='
}
]}
Choose the option that adjust to your needs.
Link:Nodemailer Repository GitHub
Good Luck!!
Your code is almost right, just need to add, "attachments" property for attaching the files in your mail,
YOUR mailOption:
var mailOption = {
from: from,
to: to,
subject: subject,
text: text,
html: html
}
Just add attachments like
var mailOption = {
from: from,
to: to,
subject: subject,
text: text,
html: html,
attachments: [{
filename: change with filename,
path: change with file path
}]
}
attachments also provide some other way to attach file for more information check nodemailer community's documentation HERE
If you are passing options object in mail composer constructor and attachment is on http server then it should look like:
const options = {
attachments = [
{ // use URL as an attachment
filename: 'xxx.jpg',
path: 'http:something.com/xxx.jpg'
}
]
}
var express = require('express');
var router = express(),
multer = require('multer'),
upload = multer(),
fs = require('fs'),
path = require('path');
nodemailer = require('nodemailer'),
directory = path.dirname("");
var parent = path.resolve(directory, '..');
// your path to store the files
var uploaddir = parent + (path.sep) + 'emailprj' + (path.sep) + 'public' + (path.sep) + 'images' + (path.sep);
/* GET home page. */
router.get('/', function(req, res) {
res.render('index.ejs', {
title: 'Express'
});
});
router.post('/sendemail', upload.any(), function(req, res) {
var file = req.files;
console.log(file[0].originalname)
fs.writeFile(uploaddir + file[0].originalname, file[0].buffer, function(err) {
//console.log("filewrited")
//console.log(err)
})
var filepath = path.join(uploaddir, file[0].originalname);
console.log(filepath)
//return false;
nodemailer.mail({
from: "yourgmail.com",
to: req.body.emailId, // list of receivers
subject: req.body.subject + " ✔", // Subject line
html: "<b>" + req.body.description + "</b>", // html body
attachments: [{
filename: file[0].originalname,
streamSource: fs.createReadStream(filepath)
}]
});
res.send("Email has been sent successfully");
})
module.exports = router;
attachments: [
{
filename: "inovices_1.pdf", // the file name
path: "https://*************************/invoice/10_9_RMKUns.pdf",// link your file
contentType: "application/pdf", //type of file
},
{
filename: "inovices_2.pdf",
path: "https://**************************/invoice/10_9_RMKUns.pdf",
contentType: "application/pdf",
},
];
var nodemailer = require("nodemailer");
var all_transporter = nodemailer.createTransport({
host: process.env.MAIL_SERVICE,
port: 587,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS,
},
maxConnections: 3,
pool: true,
});
exports.send_email = function (email, subject, html, extra_cc = [], attachments = []) {
return new Promise(async (resolve, reject) => {
var mailOptions = {
from: process.env.MAIL_FROM_ADDRESS,
to: email,
subject: subject,
html: html,
cc: [],
};
mailOptions["cc"] = mailOptions["cc"].concat(extra_cc);
if (attachments.length > 0) mailOptions["attachments"] = attachments;
all_transporter.sendMail(mailOptions, function (error, info) {
// console.log(error);
// console.log(info);
if (error) {
resolve({ failed: true, err: error });
} else {
resolve({ failed: false, data: info.response });
}
});
});
};
The alternative solution is to host your images online using a CDN and link to the online image source in your HTML, eg. <img src="list_image_url_here">.
(I had problems with nodemailer's image embedding using nodemailer version 2.6.0, which is why I figured out this workaround.)
An added benefit of this solution is that you're sending no attachments to nodemailer, so the sending process is more streamlined.
var mailer = require('nodemailer');
mailer.SMTP = {
host: 'host.com',
port:587,
use_authentication: true,
user: 'you#example.com',
pass: 'xxxxxx'
};
Then read a file and send an email :
fs.readFile("./attachment.txt", function (err, data) {
mailer.send_mail({
sender: 'sender#sender.com',
to: 'dest#dest.com',
subject: 'Attachment!',
body: 'mail content...',
attachments: [{'filename': 'attachment.txt', 'content': data}]
}), function(err, success) {
if (err) {
// Handle error
}
}
});
Just look at here. Nodemailer > Message configuration > Attachments
The code snippet is below (pdfkit gets the stream):
// in async func
pdf.end();
const stream = pdf;
const attachments = [{ filename: 'fromFile.pdf', path: './output.pdf',
contentType: 'application/pdf' }, { filename: 'fromStream.pdf', content: stream, contentType: 'application/pdf' }];
await sendMail('"Sender" <sender#test.com>', 'reciver#test.com', 'Test Send Files', '<h1>Hello</h1>', attachments);
Stream uses content not streamSource This bothered me before, share with everyone :)
Reference = https://nodemailer.com/message/attachments/
var mailOption = {
from: from,
to: to,
subject: subject,
text: text,
html: html,
attachments: [
{
filename: filename,
path: filePath
},
]
}

How to make Nodemailer trigger a seperate .js script

So i have the main nodejs server file (myserver.js)
const express = require("express");
const app = express();
const nodemailer = require("nodemailer");
const port = 80;
const vectorExpress = require("./node_modules/#smidyo/vectorexpress-nodejs/index");
const fs = require("fs");
var cors = require("cors");
app.use(cors());
app.use(express.json())
var randomnum = require('./randomnum.js');
var number = randomnum.number;
app.post('/mail', (req, res)=>{
console.log(req.body)
let transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: '',
pass: ''
}
});
const mailOptions = {
from: req.body.email,
to: 'naizeylines.info#gmail.com',
subject: `Order from ${req.body.name}`,
text:
`${req.body.name}
${req.body.street}
${req.body.postcode} ${req.body.town}
${req.body.country}
Quantity: ${req.body.quantity}
Additional information:
${req.body.message}
Shipping address:
${req.body.name2}
${req.body.street2}
${req.body.postcode2} ${req.body.town2}
${req.body.country2}
${req.body.phone2}
Email: ${req.body.email}
Phone number: ${req.body.phone}
File number: ${number}
`,
attachments: [{ // utf-8 string as an attachment
path: `${number}.svg`,
},
{
path: `${number}.dxf`,
},
]
}
transporter.sendMail(mailOptions, (error, info)=>{
if(error){
console.log(error);
res.send('error');
}else{
console.log('Email sent:' + info.response);
res.send('success');
}
})
})
var bodyParser = require("body-parser");
and a seperate script file (randomnum.js)
function randomnumber() {
return Math.floor(100000 + Math.random() * 900000);
}
var number = randomnumber();
exports.number = number;
console.log(number);
i would like to have it so that everytime nodemailer sends an email the main script would run the randomnum.js so that i would get a new random number generated. been trying for a few days now but i think im in over my head with my limited knowledge.
Based on code you provided, I see one obvious issue. You are defining randomnum out of the POST request. Also If i were you I'd generate random number inside of the myserver.js file.
Try this bit of code:
app.post('/mail', (req, res)=>{
var number = Math.floor(100000 + Math.random() * 900000)
let transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: '',
pass: ''
}
}); REST OF YOUR POST REQUEST LOGIC.....
Put Nodemailer code in separate file and export in main.js file and use with pass your data from main.js file
Hope this code will help to you
const nodemailer = require("nodemailer");
import * as dotenv from "dotenv";
dotenv.config({});
export class SendEmail {
public static send(data) {
const transport = nodemailer.createTransport({
name: process.env.SMTP_HOST,
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
auth: {
user: process.env.SMTP_USER_NAME,
pass: process.env.SMTP_PASSWORD,
},
pool: true, // use pooled connection
rateLimit: true, // enable to make sure we are limiting
maxConnections: 1, // set limit to 1 connection only
maxMessages: 3, // send 3 emails per second
});
var mailOptions = {
from: process.env.FROM,
html: data.html,
replyTo: process.env.REPLY_TO,
to: data.to,
subject: data.subject,
text: data.text,
};
transport.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log("Message sent: %s", info.messageId);
return;
});
}
}

Using nodemailer with handlebars for dynamic emails

I'm having an issue and I can't seem to narrow down what exactly I'm doing wrong. When I run my code, this is the error I get:
[Error: ENOENT: no such file or directory, open 'C:\Users\Alex\Desktop\emailtest\main.handlebars'] { errno: -4058, code: 'ENOENT', syscall: 'open', path: 'C:\\Users\\Alex\\Desktop\\emailtest\\main.handlebars' }
Here is my code:
const nodemailer = require("nodemailer");
const hbs = require("nodemailer-express-handlebars");
const express = require("express");
const app = express();
const port = 3000;
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: "useremail",
pass: "userpassword",
},
// tls: {
// rejectUnauthorized: false,
// },
});
transporter.use(
"compile",
hbs({
viewEngine: "express-handlebars",
viewPath: "views",
})
);
const mailOptions = {
from: "myemailhere",
to: "receiverpassword",
subject: "Automated Email",
template: "index",
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log("Email sent: " + info.response);
}
});
app.listen(port, () => {
console.log(
`Listening at http://localhost:${port}`
);
});
Folder structure:
server.js
views
-index.handlebars
Without using Handlebars, I can send emails just fine, but being that I need a way to fill in HTML dynamically, I think Handlebars would be the best option if I can just get it working. Any insight would be great, thanks in advance!
const path = require('path');
const handlebarOptions = {
viewEngine: {
extName: ".handlebars",
partialsDir: path.resolve(__dirname, "views"),
defaultLayout: false,
},
viewPath: path.resolve(__dirname, "views"),
extName: ".handlebars",
};
trasnporter.use('compile', hbs(handlebarOptions));

How to add image in my email, nodemailer and handlebars?

I am using nodemailer along with handlebars in my node project. The email is working fine but I am not able to attach image in the html template created by handlebars. I tried giving it in img src tag directly in the html but still not working. What i have is that the image is in svg form and in my assets folder of the project.
I also tried the example on the official nodemailer site which did not work as well. Please help me out!
https://nodemailer.com/message/embedded-images/
This is my function which will be called when I get the request from the client.
sendEmail.js
var nodemailer = require("nodemailer");
const emailConfig = require("../readEmailConfigFile");
//reading username and password from json file
let fromemail = emailConfig.readFromEmail();
let password = emailConfig.readFromPassword();
var handlebars = require("handlebars");
var fs = require("fs");
const readHTMLFile = function(path, callback) {
fs.readFile(path, { encoding: "utf-8" }, function(err, html) {
if (err) {
throw err;
callback(err);
} else {
callback(null, html);
}
});
};
/* Method for sending Email */
const sendEmail = (details) => {
var transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: fromemail,
pass: password
}
});
readHTMLFile(
__dirname + "/../emailTemplates/EmailTemplate.html",
function(err, html) {
var template = handlebars.compile(html);
var replacements = {
firstName: details.firstName,
lastName: details.lastName,
address: details.address,
};
var htmlToSend = template(replacements);
var mailOptions = {
from: fromemail,
to: details.email,
subject: "ABC",
html: htmlToSend
};
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(error);
callback(error);
} else {
console.log("Email Sent : " + info.response);
}
});
}
);
};
This is my html-template file
EmailTemplate.html
<html>
<head>
<title> </title>
</head>
<body>
<p>
Dear {{{firstName}}} {{{lastName}}}, your address is {{{address}}}</span
>
</p>
</body>
</html>
I want to embed an svg image in this html!
just add attachments parameter to your mailoptions object :
var mailOptions = {
from: fromemail,
to: details.email,
subject: "ABC",
attachments: [{
filename: 'imagename.svg',
path: __dirname +'/assets/imagename.svg',
cid: 'imagename'
}],
html: htmlToSend
};
then add the img tag in your HTML <img src="cid:imagename">

How to authenticate the URLs that serves Static files in Hapi JS

I have a route as below which serves the static pages:
{
method: 'GET',
path: '/webapp/{param*}',
config: {
handler: {
directory :{
path : Path.join(__dirname, '../../webapp/'),
index: true
}
}
}
}
So, I want to check if the user is logged in or not before it takes user to that url "/webapp/#blabla".
User Can only access that url if user is logged in.
I tried to add pre option with a function in the above route but no luck.
{
method: 'GET',
path: '/webapp/{param*}',
pre:[{method:checkUrl, assign:'m1'}],
config: {
handler: {
directory :{
path : Path.join(__dirname, '../../webapp/'),
index: true
}
}
}
}
And the checkUrl function is as:
var checkUrl = function(request, reply) {
if (!request.auth.isAuthenticated) {
// redirect to login page
reply.redirect('/login');
}
return true;
}
Why is that i cannot get redirected to login page?
It depends slightly on which auth scheme you're using but the same principle applies. Here's an example using hapi-auth-basic (adapted from the example in the README):
var Bcrypt = require('bcrypt');
var Hapi = require('hapi');
var Path = require('path');
var Inert = require('inert');
var server = new Hapi.Server();
server.connection({ port: 4000});
var users = {
john: {
username: 'john',
password: '$2a$10$iqJSHD.BGr0E2IxQwYgJmeP3NvhPrXAeLSaGCj6IR/XU5QtjVu5Tm', // 'secret'
name: 'John Doe',
id: '2133d32a'
}
};
var validate = function (request, username, password, callback) {
var user = users[username];
if (!user) {
return callback(null, false);
}
Bcrypt.compare(password, user.password, function (err, isValid) {
callback(err, isValid, { id: user.id, name: user.name });
});
};
server.register([
require('inert'),
require('hapi-auth-basic')
], function (err) {
server.auth.strategy('simple', 'basic', { validateFunc: validate });
server.route({
method: 'GET',
path: '/webapp/{param*}',
config: {
auth: 'simple', // THIS IS THE IMPORTANT BIT
handler: {
directory :{
path : Path.join(__dirname, 'files'),
index: true
}
}
}
});
server.start(function (err) {
if (err) {
throw err;
}
console.log('Server started!');
})
});
The important point is just to add an auth property to the route config with the strategy name. It's the same as you would do for any routes. Have a read of this tutorial, it might clear it up for you.
Are you able to adapt that to your needs?

Categories

Resources