I am trying to send an HTML email using Nodemailer and nodemailer-express-handlebars.
So I created an HTML template and place it under "templates" folder (see below image) and specified its path in my code so that Nodemailer can go and get the template.
However, Nodemailer is checking the path different from the one I specified.
Project structure:
What I tried and what I want to ask
I tested the behavior in pattern 1 and 2 as shown below.
Pattern 1 is the problematic case for me.
In pattern1, how can I make Nodemailer check the viewPath which I specified?
Pattern 1: Not working as expected
The viewPath is "/home/honda/develoment/phaser_projects/test/templates".
I expect nodemailer to check this path for the template file.
const hbs = require("nodemailer-express-handlebars");
const nodemailer = require("nodemailer");
const emailProvider = process.env.EMAIL_PROVIDER;
const emailFrom = process.env.EMAIL_FROM;
const emailTo = process.env.EMAIL_TO;
const pass = process.env.PASSWORD;
const smtpTransport = nodemailer.createTransport({
service: emailProvider,
auth: {
user: emailFrom,
pass: pass
}
});
// Specify the viewPath here
const handlebarsOptions = {
viewEngine: "handlebars",
viewPath: "/home/honda/develoment/phaser_projects/test/templates",
extName: ".html"
};
smtpTransport.use("compile", hbs(handlebarsOptions));
const data = {
to: emailTo,
from: emailFrom,
template: "test-template",
subject: "Test Subject",
};
smtpTransport.sendMail(data)
.catch(error => console.log(error))
Then I got the below error message.
Nodemailer is checking the path "/home/honda/develoment/phaser_projects/test/main.handlebars".
My expectation:
Nodemailer check the path "/home/honda/develoment/phaser_projects/test/templates", which I specified.
[Error: ENOENT: no such file or directory, open '/home/honda/develoment/phaser_projects/test/main.handlebars'] {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/home/honda/develoment/phaser_projects/test/main.handlebars'
}
Pattern 2: Working as expected
The viewPath is replaced with "/home/honda/develoment/phaser_projects/test/templatessss".
This is a wrong path because the directory "templatessss" does not exist.
const handlebarsOptions = {
viewEngine: "handlebars",
viewPath: "/home/honda/develoment/phaser_projects/test/templatessss", // templatessss does not exist
extName: ".html"
};
Then I got the below error message.
In this case, Nodemailer obviously didn't find the template because the path does not exist, but anyway it checked the path I specified, which is expected behavior.
[Error: ENOENT: no such file or directory, open '/home/honda/develoment/phaser_projects/test/templatessss/test-template.html'] {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/home/honda/develoment/phaser_projects/test/templatessss/test-template.html'
}
Related
in this project, I try to upload a file. from frontend to backend, and save that file, the error showing like this,
error
the error
this.$__.validationError = new ValidationError(this);
^
ValidationError: File validation failed: filename: Path `filename` is required., path: Path `path` is required.
at model.Document.invalidate (C:\Users\harsh\Desktop\FILE-SHARING-APP\node_modules\mongoose\lib\document.js:2970:32)
at C:\Users\harsh\Desktop\FILE-SHARING-APP\node_modules\mongoose\lib\document.js:2759:17
at C:\Users\harsh\Desktop\FILE-SHARING-APP\node_modules\mongoose\lib\schematype.js:1333:9
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
errors: {
filename: ValidatorError: Path `filename` is required.
at validate (C:\Users\harsh\Desktop\FILE-SHARING-APP\node_modules\mongoose\lib\schematype.js:1330:13)
at SchemaString.SchemaType.doValidate (C:\Users\harsh\Desktop\FILE-SHARING-APP\node_modules\mongoose\lib\schematype.js:1314:7)
at C:\Users\harsh\Desktop\FILE-SHARING-APP\node_modules\mongoose\lib\document.js:2751:18
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
properties: {
validator: [Function (anonymous)],
message: 'Path `filename` is required.',
type: 'required',
path: 'filename',
value: undefined
},
here , for unique file Name i used uuid and i given storege,
limit:{fileSize:100000*100},
the requirement is I need to upload any file and I generate the link for that file for download that file
fails.js
const router = require ('express').Router();
const multer = require('multer');
const path = require('path');
const File =require('../models/file');
const {v4 : uuid4} =require('uuid')
let storege = multer.diskStorage({
destination:(req,file,cd) =>cd(null,'uploads/'),
// for unique file Name
filename:(req,file,cb)=>{
const uniqueName =`${Date.now()}-${Math.round(Math.random()*1E9)}${this.path.extname(file.originalname)}`;
cb(null,uniqueName);
}
})
let upload =multer({
storege,
limit:{fileSize:100000*100},
}).single('myfiles');
router.post('/' ,(req,res)=>{
//store files:
upload(req,res,async(error)=>{
//validate require
if(!req.file){
return res.json({error:'All files are required.'})
}
if (error){
return res.status(500).send({error:error.message})
}
// store into Database:
const file = new File({
filename: req.file.filename,
uuid:uuid4(),
path:req.file.path,
size:req.file.size,
});
const response = await file.save();
return res.json({file:`${process.env.APP_BASE_URL}/files/${response.uuid}`});
//http://localhost:3000/files/2433r4r4t444r3-3r3r
});
//Respone ->Link
})
module.exports=router;
here is the mongoose. Schema has filename, path, size, uuid, sender and resiver is false
file.js
const mongoose = require ('mongoose');
const Schema =mongoose.Schema;
const filesSchema = new Schema({
filename:{type:String,required:true},
path:{type:String,required:true},
size:{type:Number,required:true},
uuid:{type:String,required:true},
sender:{type:String,required:false},
resiver:{type:String,required:false},
},{ timestamps:true});
module.exports=mongoose.model('File',filesSchema)
the error shows like :
my Requirement needs to upload any file means .jpg, png, or pdf.
this.$__.validationError = new ValidationError(this);
^
ValidationError: File validation failed: path: Path `path` is required.
how to fix this error,
I found out for myself what the error was. This is an error caused by a small mistake. the mistake is in fails.js
// for unique file Name
filename:(req,file,cb)=>{
const uniqueName =`${Date.now()}-${Math.round(Math.random()*1E9)}${this.path.extname(file.originalname)}`;
cb(null,uniqueName);
}
in this Piece of code has a problem. ${this.path.extname(file.originalname)};` here noneed to add this.path
only need to use ${path.extname(file.originalname)} Actually this is a mistake that came to me unknowingly.
I am trying to send email through an HTML template that resides in the same path under a folder named 'view'. The HTML template name is 'index.handlebars'. But it is giving some weird error of path, though I think the path is absolutely proper.
Can anyone please help me to fix this issue?
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type undefined
at validateString (internal/validators.js:125:11)
at Object.resolve (path.js:161:7)
at ExpressHandlebars._resolveLayoutPath (E:\NODE JS EXAMPLES\node-practice-one\node_modules\express-handlebars\lib\express-handlebars.js:342:17)
at ExpressHandlebars. (E:\NODE JS EXAMPLES\node-practice-one\node_modules\express-handlebars\lib\express-handlebars.js:223:35)
const express = require('express');
const path = require('path');
const nodemailer = require('nodemailer');
const hbs = require('nodemailer-handlebars');
const log = console.log;
// Step 1
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL || 'abcd#gmail.com', // TODO: your gmail account
pass: process.env.PASSWORD || 'abcd' // TODO: your gmail password
}
});
router.post('/send_mail', (req, res, next) => {
// Step 2
transporter.use(
'compile',
hbs({
viewEngine: 'express-handlebars',
viewPath: './views/'
})
);
// Step 3
let mailOptions = {
from: 'xxx#gmail.com', // TODO: email sender
to: 'yyy#gmail.com', // TODO: email receiver
subject: 'Nodemailer - Test',
text: 'Wooohooo it works!!',
template: 'index',
context: {
name: 'test user'
} // send extra values to template
};
// Step 4
transporter.sendMail(mailOptions, (err, data) => {
console.log(err);
if (err) {
return log('Error occurs');
}
return log('Email sent!!!');
});
});
Please suggest to me, what should I do to fix the error.
inside hbs options you did not mention layoutsDir which contains layout.hbs
layout.hbs holds the default HTML skeleton and this is the file which will be extended by all the other view files. By default files in “views” folder will use this basic skeleton and then render their specific content in this {{{body}}} part. this is the hook where other views will come in and render their content.
hbs({
defaultLayout: "layout",
extname: ".hbs",
layoutsDir: __dirname + "/views/layouts",
partialsDir: __dirname + "/views/partials"})
then inside views folder create layouts folder and partials folder. create layout.hbs inside layouts directory. inside this file insert a basic html skeleton and inside the body, place this
{{{body}}}
I correctly installed ffmpeg I'm able to check it by writing ffmpeg in cmd which give me this result
Now in my electron app in my index.html I'm geting input from user and sending custom event to electron side of app which lays in index.js entry point
index.html
<script>
const electron = require('electron');
const { ipcRenderer } = electron;
document.querySelector('form').addEventListener('submit', (e) => {
e.preventDefault();
const { path } = document.querySelector('input').files[0];
ipcRenderer.send('video:submit', path);
});
</script>
and using ffmpeg.ffprobe I'm trying to get metadata of video updated to input in electron side like so:
const electron = require('electron');
const ffmpeg = require('fluent-ffmpeg');
const { app, BrowserWindow, ipcMain } = electron;
app.on('ready', () => {
const mainWindow = new BrowserWindow({});
mainWindow.loadURL(`file://${__dirname}/index.html`);
});
ipcMain.on('video:submit', (event, path) => {
ffmpeg.ffprobe(path, (err, metadata) => {
console.log(metadata);
//console.log(metadata.format.duration);
});
});
And it console that metadata is undefined, when I uncomment console.log(metadata.format.duration) it says
typeError: cannot read property
'format' of undefined
What I'm doing wrong?
So I set two new environment variables and now other error occure when I console.log(error):
{ Error: spawn C:\Users\Borys\Documents\videoinfo\ffmpeg\bin ENOENT
at exports._errnoException (util.js:1024:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:192:19)
at onErrorNT (internal/child_process.js:374:16)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
code: 'ENOENT',
errno: 'ENOENT',
syscall: 'spawn C:\\Users\\Borys\\Documents\\videoinfo\\ffmpeg\\bin',
path: 'C:\\Users\\Borys\\Documents\\videoinfo\\ffmpeg\\bin',
spawnargs:
[ '-show_streams',
'-show_format',
'C:\\Users\\Borys\\Documents\\portfolio\\img\\header_video.mp4' ] }`
( I had to paste it as code because it was saying that my post containt code that is not properly formatted)
Alright thanks to #Alexander Leithner and this question I figured it out. So error was my environment variables which should be:
FFMPEG_PATH with value of path to ffmeg.exe
FFPROBE_PATH with value of path to ffprobe.exe
PATH with value of C:.......\ffmpeg\bin
I'm trying to copy an image from a folder to another using fs-extra module .
var fse = require('fs-extra');
function copyimage() {
fse.copy('mainisp.jpg', './test', function (err) {
if (err)
return console.error(err)
});
}
This is my directory
and this is the error I get all the time:
Error {errno: -4058, code: "ENOENT", syscall: "lstat", path:
"E:\mainisp.jpg", message: "ENOENT: no such file or directory, lstat
'E:\mainisp.jpg'"}
and by changing destination to ./test/ I get this error
Error {errno: -4058, code: "ENOENT", syscall: "lstat", path:
"E:\Development\Node apps\Node softwares\Digital_library\mainisp.jpg",
message: "ENOENT: no such file or directory, lstat 'E:\Devel…
apps\Node softwares\Digital_library\mainisp.jpg'"}
Note: I'm not testing this in browser. It's an Nwjs app and the pics of error attached are from Nwjs console.
You can do this using the native fs module easily using streams.
const fs = require('fs');
const path = require('path');
let filename = 'mainisp.jpg';
let src = path.join(__dirname, filename);
let destDir = path.join(__dirname, 'test');
fs.access(destDir, (err) => {
if(err)
fs.mkdirSync(destDir);
copyFile(src, path.join(destDir, filename));
});
function copyFile(src, dest) {
let readStream = fs.createReadStream(src);
readStream.once('error', (err) => {
console.log(err);
});
readStream.once('end', () => {
console.log('done copying');
});
readStream.pipe(fs.createWriteStream(dest));
}
Try:
var fs = require('fs-extra');
fs.copySync(path.resolve(__dirname,'./mainisp.jpg'), './test/mainisp.jpg');
As you can see in the error message, you're trying to read the file from E:\mainisp.jpg instead of the current directory.
You also need to specify the target path with the file, not only the destination folder.
Try:
const fs = require('fs');
fs.copyFileSync(src, dest);
I'm making a node/express app and am querying a test json file using npm request-promise. Node is spitting out the following error in my <title> tags:
Error: <title>Invalid URI "../testJSON/user.json"</title>
I believe my pathing is correct, so am unsure why it's an invalid URI.
I've also provided the entire project path URI with the same issue:
return rp('http://localhost:3000/app/testJSON/user.json');
User Service:
module.exports = {
getUserData: function(){
var options = {
uri : '../testJSON/user.json',
method : 'GET'
}
return rp(options);
}
}
User Controller:
var User = require('../services/User.service');
User.getUserData()
.then(function(data){
res.render('pages/userdata', {
title: 'User Data',
content: JSON.parse(data)
});
})
.catch(function(err){
console.log(err);
});
Pathing:
User Service: projectroot/app/services/userService.js
User json file: projectroot/app/testJSON/user.json
Update: trying with node fs to fetch local file
fs = require('fs');
module.exports.index = function (req, res) {
fs.readFile('../testJSON/user.json', 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
res.render('pages/user', {
title: 'User',
content: JSON.parse(data)
});
});
...
Node error:
{ [Error: ENOENT, open '../testJSON/user.json'] errno: -2, code:
'ENOENT', path: '../testJSON/user.json' }
Relative paths (starting with ../ or ./) are relative to the current working directory. If you want to read a file relative to the current JS source file, you need to prefix the path with __dirname, which is the directory where the current JS source file resides:
fs.readFile(__dirname + '/../testJSON/user.json', ...);
Or the more elaborate (but probably more correct) way:
var path = require('path);
...
fs.readFile(path.join(__dirname, '../testJSON/user.json'), ...);