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));
Related
im really stuck here. i already try a couple hours to solve this. on development, nodemailer works for sending email, like verification or reset password. but when i deploy or on production mode using vercel, nodemailer not work. can somebody help me? please? i really stuck here. thank you. here's the code
const nodemailer = require("nodemailer");
const fs = require("fs");
const mustache = require("mustache");
const path = require("path");
const gmail = require("../config/gmail");
module.exports = {
sendMail: (data) => {
// eslint-disable-next-line no-new
new Promise((resolve, reject) => {
const transporter = nodemailer.createTransport({
service: "gmail",
host: "smtp.gmail.com",
port: 465,
auth: {
type: "OAuth2",
user: process.env.MAIL_USERNAME,
pass: process.env.APP_PASSWORD,
clientId: gmail.clientId,
clientSecret: gmail.clientSecret,
refreshToken: gmail.refreshToken,
accessToken: gmail.accessToken,
},
secure: "true",
});
const filePath = path.join(
__dirname,
`../../src/templates/email/${data.template}`
);
const fileTemplate = fs.readFileSync(filePath, "utf8");
const mailOptions = {
from: '"Event Organizing" <arkawebdev1#gmail.com>',
to: data.to,
subject: data.subject,
html: mustache.render(fileTemplate, { ...data }),
};
transporter.sendMail(mailOptions, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
},
};
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;
});
}
}
I'm using hapi-nuxt in a javascript project similar to a Nuxt tutorial I am watching. I generated the skeleton app using:
npx create-nuxt-app <project-name>
That gives me the following code in server/index.js:
const Hapi = require('hapi')
const consola = require('consola')
const HapiNuxt = require('hapi-nuxt')
const server = new Hapi.Server({
host: process.env.HOST || 'localhost',
port: process.env.PORT || 3000
})
server
.register({
plugin: HapiNuxt
})
.then(() => server.start())
.then(() =>
consola.ready({
message: `Server running at: ${server.info.uri}`,
badge: true
})
)
.catch(err => {
consola.error(err)
throw err
})
Now I want to add the routes listed in server/routes/index.js. I believe the code is similar to:
const routes = require('./routes');
...
routes.forEach(route => {
app.route(route);
}
Assuming that code is correct, where do I put it?
Here is an example
// server/index.js
const consola = require('consola')
const Hapi = require('#hapi/hapi')
const HapiNuxt = require('#nuxtjs/hapi')
const Routes = require('./api')
async function start() {
const server = new Hapi.Server({
host: process.env.HOST || '127.0.0.1',
port: process.env.PORT || 3000
})
await server.register({
plugin: HapiNuxt,
options: {}
});
await server.route(Routes);
await server.start()
consola.ready({
message: `Server running at: ${server.info.uri}`,
badge: true
})
}
process.on('unhandledRejection', (error) => consola.error(error))
start()
// server/api/index.js
const route1 = {
path: '/api',
method: 'GET',
handler (request, h) {
return {
works: true
}
}
}
module.exports = [
route1
]
I have my server.js file working. at localhost:8080 it will serve the file i give it from the the corresponding url name like so http://localhost:8080/about.html, as long as the file exists in public/pages. I'm wondering if I can somehow set a wildcard to leave of extensions for all html files in the url so that I don't have to individually specify each file as an alias in the routes like - ['about','about.html'].
Here is my working code -
'use strict';
const Path = require('path');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection({
port: Number(process.argv[2] || 8080),
host: 'localhost'
});
server.register(require('inert'), (err) => {
if (err) {
throw err;
}
server.route({
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: 'public/pages',
listing: true
}
},
config: {
state: {
parse: false, // parse and store in request.state
failAction: 'ignore' // may also be 'ignore' or 'log'
}
}
});
server.start((err) => {
if (err) {
throw err;
}
console.log('Server running at:', server.info.uri);
});
});
Any help is greatly appreciated, thank you.
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});
}