How to send an attachment from an upload button using nodemailer - html

I am trying to create a website with a form that users can fill up as well as uploading an image or a docx file through the input tag. I am using a controller because I am also using an hbs for this.
const output = `<p>You have a new message from the TIPH website<p>
<h3>Contact Details</h3>
<p>Name: ${req.body.contact_name}<p>
<h3>Inquiry</h3>
<p>${req.body.contact_inquiry}</p>
`;
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
var mailOptions = {
from: `${req.body.contact_email}`,
to: '...',
subject: `${req.body.contact_subject}`,
html: output,
attachments: [
{
filename: `${req.body.contact_upload}`,
}
]
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
res.render('contact-us', {
layout: '/layouts/main',
title: 'Contact Us',
contact_active: true,
msg: 'Your message has been sent!'
})
}
});

In order to upload files to a node server, you should set the enctype attribute of the HTML form element to enctype="multipart/form-data"
To work with the files server side you could use multer. This middleware makes the uploaded file availabe from the req.file property.
You can then add this file to the attachments array. You can find what props you need to send to Nodemailer in their documentation.

Related

Error when sending emails using Nodemailer

server.js:
app.post('/game',(req,res,next)=>{
//if(!emailValidator(req.body.email)){
// I would do email validations client side to but if you
// want to do server side send some html saying the email is invalid
//res.sendFile(invalidEmail.html)
//}
//else{
//I assume you have some script for sending email. I'll use nodemailer cuz its the first
//module I found
let sender = 'myemail#gmail.com'
let transporter = nodemailer.createTransport({
service:'gmail',
auth:{
user:sender,
pass:'Mypassword'
}
})
let mailOptions = {
from: sender,
to: req.body.email,
subject:'New sign up',
text:'Thanks for subscribing'
}
transporter.sendMail(mailOptions,function(error,info){
if(error){
// do somehting
console.log(error)
}
else{
console.log('Sent new user email')
req.next()
}
})
}
//}
)
index.html:
<form action="game" method="post" size="30">
<input type="text" name="email"/>
<input type="submit" />
</form>
I'm having this error:
TypeError: Cannot read property 'email' of undefined
So there is this error with my code, I'm trying to send an email with Nodemailer from a form in HTML, can someone help me fix this?
Also there is a part for email validation but I removed it as it says "emailValidator" is undefined.
Inside the main folder, create a public folder, inside it create an index.html file
<!DOCTYPE html>
<html>
<head>
<title>Simple page</title>
</head>
<body>
<form action="game" method="post" size="30">
<input type="text" name="email"/>
<input type="submit" />
</form>
</body>
</html>
Inside the main folder, create a server.js file
const express = require('express')
const app = express()
const path = require('path')
const bodyParser = require('body-parser')
const nodemailer = require('nodemailer')
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/public', express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'))
});
app.post('/game', (req, res) => {
let senderUsername = 'example#gmail.com' // sender email address
let senderPassword = 'password'; // senders password
const transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: senderUsername,
pass: senderPassword
}
});
const mailOptions = {
from: senderUsername, // sender address
to: req.body.email, // list of receivers
subject: 'New sign up', // Subject line
html: '<p>Thanks for subscribing.</p>'// plain text body
};
transporter.sendMail(mailOptions, function (err, info) {
if(err)
console.log(err)
else {
console.log('Sent new user email')
console.log(info);
req.next()
}
});
})
const PORT = 5000;
app.listen(PORT, ()=>{
console.log(`server running on PORT ${PORT}`)
})
Note :
You may also need to follow these steps while using a google account.
Enable the settings to allow less secure apps for the Gmail account that you are using.
Here is the link: Google less secure apps
Allow access for "Display Unlock captcha option" (Allow access to your Google account)
Here is the link: Google unlock captcha
You can also explore MailJet or SendGrid for sending emails.

Send a PDF File with nodemailer via a html form

I have a form in which has an upload file input. I want the user to be able to upload their file and send it via the form. At the moment the PDF file shows attached in the email but doesn't contain any data and won't open etc.
This is what I currently have within the nodemailer options:
let mailOptions = {
from: '"Macwear Clothing" <shop#macwearclothing.com>', // sender address
to: req.body.email, // list of receivers
subject: 'Order Review', // Subject line
text: 'Order Acception', // plain text body
html: output, // html body
attachments: [{'filename': 'needlesheet.pdf', 'content': req.body.needle, 'contentType': 'application/pdf'
}]
};
Client Side index.ejs file
<div class="fileUpload up<%= item.number %>" id="m<%= item.number %>">
<div class="fileUploadContent">
<h2>Customer:
<%= item.email %>
</h2>
<div class="uploadFile">
<input id="needle" type="file" name="needle" value="Upload File >">
</div>
<form method="POST" action="send" name="sendNeedleSheet" enctype="multipart/form-data">
<div class="optionalMessage">
<span>Optional Message:</span>
<textarea class="customTextArea" name="message"></textarea>
<input id="email" name="email" type="hidden" value="<%= item.email %>">
</div>
<div class="modalOptions">
<div class="mButton ok">
<button class="customButton" type="submit">Send</button>
</div>
<div class="mButton cancel">
<span>Cancel</span>
</div>
</div>
</form>
</div>
</div>
app.js
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const chalk = require('chalk');
const nodemailer = require('nodemailer');
const multer = require('multer');
const app = express();
//View Engine
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Body Parser Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
// Set Static Path
app.use(express.static(path.join(__dirname, '/public')));
// Call JSON
//requestLoop();
// var shopifyAPI = require('shopify-node-api');
// var Shopify = new shopifyAPI({
// shop: 'macwear-clothing-embroidery.myshopify.com', // MYSHOP.myshopify.com
// shopify_api_key: '', // Your API key
// access_token: '' // Your API password
// });
var orderData = null;
// Shopify.get('/admin/orders.json', function(err, data, res, headers){
// app.locals.jsonOrderData = data;
// });
// Shopify.get('/admin/orders/count.json', function(err, data, headers) {
// app.locals.jsonOrderCount = data;
// });
var requestLoop = setInterval(function () {
var request = require("request");
var options_orders = {
method: 'GET',
url: 'https://macwear-clothing-embroidery.myshopify.com/admin/orders.json',
headers: {
'Postman-Token': '',
'Cache-Control': 'no-cache',
Authorization: ''
}
};
var options_order_count = {
method: 'GET',
url: 'https://macwear-clothing-embroidery.myshopify.com/admin/orders/count.json',
headers: {
'Postman-Token': '',
'Cache-Control': 'no-cache',
Authorization: ''
}
};
request(options_orders, function (error, response, body) {
if (error) throw new Error(error);
jsonOrderData = JSON.parse(body);
//console.log(body);
});
request(options_order_count, function (error, response, body) {
if (error) throw new Error(error);
jsonOrderCount = JSON.parse(body);
//console.log(body);
});
}, 60000);
app.get('/shopifycall_order_count', function (req, res) {
res.send(jsonOrderCount);
//res.render('dynamic_content');
});
app.get('/shopifycall_orders', function (req, res) {
res.render('dynamic_content');
});
// Multer File Processing
app.post('/send', (req, res) => {
const output = `
<p>Please View & Accpet or Reject the PDF</p>
`;
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: '',
pass: ''
},
tls:{
rejectUnauthorized:false
}
});
// setup email data with unicode symbols
let mailOptions = {
from: '"Macwear Clothing" <shop#macwearclothing.com>', // sender address
to: req.body.email, // list of receivers
subject: 'Order Review', // Subject line
text: 'Order Acception', // plain text body
html: output, // html body
attachments: [{'filename': 'needlesheet.pdf', 'content': req.body.needle, 'contentType': 'application/pdf'
}]
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
// Preview only available when sending through an Ethereal account
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
});
console.log(req.body.needle);
});
app.get('/', (req, res) => {
res.render('index');
});
app.listen(3000, () => {
console.log('Starting MOS.......');
console.log(chalk.green('Loaded on port 3000'));
console.log('Fetching API.......');
console.log('Initial API Request will take 60 Seconds');
});
I simply used Multer to handle the uploading of the file. All that was required was to set the multer upload directory.
var upload = multer({dest: './public/uploads/'});
And then within the /send route add in upload.single('needle') and remove the arrow function:
app.post('/send', upload.single('needle'), function (req, res, next) {
});
Then within the attachments in mailOptions:
attachments: [
{
filename: req.file.originalname,
path: req.file.path
}
]
Lastly it is important to set the enctype on the HTML form to multipart/form-data otherwise the file upload via multer will not work.
you using path for both your attachment and static path so the document will not display its extension
try:
app.use(express.static('public'))

send function parameter values into html template using node js

I'm writing a service in node.js. In that, I used to send the mail to user with the verification link.
For that I used nodemailer, all works perfectly. In that, I directly used the html part, So I access the token variable. Now I need to move that html part into separate folder. Now the issue is accessing the token(ie, the params value) My code is like, modules/users.js
let sendNotification = await mailer.sendMail(userDetail.email, token);
When I create user, the token is sent to the userDetail.email. My previous mailer looks like, mailer/applicationMailer.js
async function sendMail(userMail, token) {
// let htmlTemplate = fs.readFileSync(__dirname + '/templates/mail.html');
let transporter = nodemailer.createTransport(smtpTransport({
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: 'xxx#gmail.com',
pass: '********'
}
}));
let mailOptions = {
from: 'xxx#gmail.com',
to: userMail,
cc: '',
subject: 'Account verification',
// html: htmlTemplate
html: `<p>To verify your account click LINK</p>` +
`<p>This link will be expired in two days.</p>` +
`<p><strong>Note:</strong> Contact your ADMIN, if the link is expired</p>`
};
transporter.sendMail(mailOptions, async function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
};
I need to move the html part into template/mail.html and access the htmlTemplate variable. There I cant access the token. I need to pass the param value to html page. How to do that?
Thanks in Advance.
You are looking for EJS
const ejs = require("ejs");
ejs.renderFile(__dirname + "/test.ejs", { token }, function (err, data) {
if (err) {
console.log(err);
} else {
const mainOptions = {
from: 'xxx#gmail.com',
to: userMail,
cc: '',
subject: 'Account verification',
html: data
};
transporter.sendMail(mainOptions, function (err, info) {
if (err) {
console.log(err);
} else {
console.log('Message sent: ' + info.response);
}
});
}
});

Create dynamic html with ejs and node

I am trying to send dynamic mail to email IDs submitted using a form. Below is my app.js code.
//Importing Packages
var express = require('express');
var nodemailer = require('nodemailer');
var bodyParser = require('body-parser');
//Applying Express,Ejs to Node
app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended:true}));
//Creating Nodemailer Transport
var transporter = nodemailer.createTransport({
host: 'smtp.zoho.com',
port: 465,
secure: true,
auth: {
user: 'noreply#*****.com',
pass: '******'
}
});
//Root Route Setup
app.get('/', function(req, res){
res.render("landing")
});
//Route to send the mail
app.post('/send', function(req,res){
//Setting up Email settings
var mailOptions = {
from: 'noreply#*****.com',
to : req.body.mail,
subject: 'Verify Your Email',
generateTextFromHtml : true,
html: { path: './tmpl.html'}
};
//Execute this to send the mail
transporter.sendMail(mailOptions, function(error, response){
if(error) {
console.log(error);
} else {
console.log(response);
}
});
res.send("Mail succesfully sent!")
});
//Server &Port Settings
app.listen(3333, function(){
console.log("Server is running...")
});
Below is my Form page code, which is an ejs file
<form action="/send" method="POST">
<input type="email" name="mail" placeholder="Enter your email">
<input type="text" name="name" placeholder="Enter your name">
<input type="submit">
</form>
and below is my html template which is being mailed to the ID submitted using the form.
<html>
<body>
<h1>Hello World!</h1>
Link
</body>
</html>
How do I read the Name from the form and then include that in the Email, so that in each email, I can address to that person using a variable, like "Hello Mr {{name}}"
I am not able to figure out how to pass variable to the html file without emails blocking it as I am not able to use Javascript using Script tag inside the HTML file becuase almost all of the mail providers block JS in Email!
Can someone help me out with this please?
You can use the ejs templating engine you've already set up with express. Calling app.render() will render the template you specify as a string and pass it to its callback, plus whatever data you pass into it. So its a little ugly with callbacks, but this is a solution that doesnt add any dependencies.
In short, make your email template an ejs file named verifyEmail.ejs,
use app.render() to render it with data from the POST request body before sending the email from the app.render callback.
// app.js
app.post('/send', function(req,res){
// Use the ejs rendering engine to render your email
// Pass in the 'name' variable that is used in the template file
app.render('verifyEmail', {name: req.body.name}, function(err, html){
if (err) {
console.log('error rendering email template:', err)
return
} else {
//Setting up Email settings
var mailOptions = {
from: 'noreply#*****.com',
to : req.body.mail,
subject: 'Verify Your Email',
generateTextFromHtml : true,
// pass the rendered html string in as your html
html: html
};
//Execute this to send the mail
transporter.sendMail(mailOptions, function(error, response){
if(error) {
console.log(error);
res.send('Mail Error! Try again')
} else {
console.log(response);
res.send("Mail succesfully sent!")
}
});
}
});
});
I added some error handling, and notifying the user if the email is not sent due to a server error. The way you were calling res.send() before would tell the user the email was sent successfully before it was even sent.
Place your template folder in the same directory as your "landing" template, or wherever else your ejs files are.
Insert data into your template by calling a variable between <%= %> tags. Populate it by passing a variable of the same name when rendering the template.
From the ejs docs:
... everything inside <%= %> tags inserts itself into the returned HTML
string.
// views/verifyEmail.ejs
<html>
<body>
<h1>Hello <%= name %></h1>
Link
</body>
</html>

get image file object from url

I am making a django-angularjs webapp.
There is a option for file uploading for the users.
I want to provide users with some sample images to upload.
So it will be like the sample images will be sent by server to client and again send back to the server if the client chooses them as Fresh upload.
angularjs directive:
angular.module('users').directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
my html:
<input type="file" file-model="myFile"/><br><br>
<button ng-click="uploadFile()">Upload</button>
angular-js controller:
$scope.uploadFile = function(){
var file = $scope.myFile;
var uploadUrl = "/multer";
var fd = new FormData();
fd.append('file', file);
$http.post(uploadUrl,fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
console.log("success!!");
})
.error(function(){
console.log("error!!");
});
};
Using the code above the user can select the image from their pc and upload them.
Now if we have the url for the sample images sent by server.
How to code the angular controller to get images for their file object from those urls?
like $scope.myFile=getImageFileObjectFromUrl(url) ??
thanks for help
$http.get("image_url", {responseType: "arraybuffer"}).success((data) => {
fd.append('file', data);
});
It's a general idea, when you get your image url, just make a request as arraybuffer to the URL, then you just have to pass the blob object to your formdata.
Convert a image from the given url into a file object:
$http.get(url,{responseType: "blob"}).success((data) => {
var file = new File([data], "sample.jpg");
$scope.sampleFile=file;
});
It also may help
$http.get(url.path, {responseType: "blob"}).then((res) => {
let fileUrl = (window.URL || window.webkitURL).createObjectURL(res.data);
resolve({file: fileUrl, type: url.type, name: url.name});
});