Send PDF generated with jsPDF to server - javascript

I am generating a PDF client side with jsPDF. I need to send it to my Express server using Axios. At the end I need to send it via email with Nodemailer. Where am I wrong?
Client side code:
//doc creation ....
var res = doc.output('datauristring'); //this line!!!!
axios.post('/mailsender', res).then((res) => {
if(res.status === 'ok') console.log("Yeah!");
else console.log(":(");
});
Server side code:
...
api_router.post('/mailsender', (req, res) => {
mail.send(req.body, (res) => {
res.status(200).json({"status": res ? 'ok' : 'error' });
});
});
mail.js that is:
const nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
host: 'smtp.mail.yahoo.com',
port: 465,
secure: true,
auth: {
user: 'example#yahoo.it',
pass: 'password'
}
});
exports.send = function (data, callback) {
let mailOptions = {
from: '"My application" <example#myapp.com>',
to: "receiverAddress",
subject: "Attachment experiment",
text: "My <3",
attachments: [
{
filename: 'attachment.pdf',
content: data,
contentType: 'application/pdf',
encoding: 'base64' //this line!!!!
}
]
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
callback(false);
}
callback(true);
});
}
All is working fine, except that if I try to open the attachment in the received mail, Preview says that the file is damaged. The same if I try to open it with google chrome or with other PDF readers. Probably, the two lines with a comment has to be changed. Thank you for your attention!

It was very simple: I had only to change the the attachment part in this way:
attachments: [
{
path: data
}
]

Below code worked for me , i used axios in client to post the pdf and nodemailer in server side in node.js to send pdf as attachment
Client :
const out = pdf.output('datauristring');
const response = await axios.post(`/email/sendReport`, {
pdf: out.split('base64,')[1],
});
Server:
let mailOptions = {
from: '"My application" <example#myapp.com>',
to: "receiverAddress",
subject: "Attachment experiment",
text: "My <3",
attachments: [
{
filename: 'attachment.pdf',
content: req.body.pdf,
contentType: 'application/pdf',
encoding: 'base64'
}
]
};

I am saving pdf on the server and also sending pdf in Laravel mail from jsPDF.I'm posting my code.perhaps it helps someone.
sendPdfInMail() {
const doc = new jsPDF()
doc.text('Pdf from jspdf!', 10, 10)
var formData = new FormData()
formData.append('file', doc.output('datauristring').split('base64,')[1])
axiosIns
.post('auth/currency_statement', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then(function (response) {
console.log(response)
})
.catch(function (err) {
console.log(err.response)
alert('error')
})
},
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
PHP Laravel (Server Code)
public function send_currency_statement(Request $request) {
$data["email"] = "text#money.com";
$data["title"] = "Currency statement";
$data["body"] = "Please check your invoice";
$fileName = time().
'.pdf';
$path = public_path('temp/').$fileName;
//Decode pdf content
$pdf_decoded = base64_decode($request - > file);
//Write data back to pdf file
$pdf = fopen('temp/'.$fileName, 'w');
fwrite($pdf, $pdf_decoded);
//close output file
fclose($pdf);
Mail::send('emails.myTestMail', $data, function($message) use($data, $path) {
$message - > to($data["email"], $data["email"]) -
>
subject($data["title"]);
$message - > attach($path);
});
return response() - > json(['message' => 'send successfully']);
}

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 pass a file (PDF, DOC, etc) from Client (react) to server (Node - Express)

Client side
I use input file to get the PDF:
<html>
<body>
<input type="file" id="file_attachments" name="files" onChange=updateAttachments() multiple>
</input>
<script>
function updateAttachments() {
let files = document.getElementById("file_attachments").files;
console.log('attached', files);
}
</script>
</body>
As you can see from the above, I use .files.
I successfully update my react states with the files:
this.setState({
attachments: [...files]
});
Server side
I pass the files (attachments) to my server (node) via a fetch request (POST):
onSend = () => {
const url = config.API_ENDPOINT + "/api/email/send";
const email = {
to: this.state.emails,
subject: this.state.subject,
message: this.state.content,
attachments: this.state.attachments
};
fetch(url, {
method:"POST",
body: JSON.stringify(email),
headers: {
Accept: "application/pdf",
"Content-Type": "application/json"
}})
.then(res => {
if (!res.ok) {
res.json().then(error => {
throw error
})
}
return res.json()
})
.then(data => {
console.log('sent complete');
console.log(data);
})
.catch(err => {
this.setState({
error: err.message
})
})
}
However, on the server side, I receive all the data, except attachments is empty:
emailRouter
.route('/send')
.post(jsonParser, (req, res, next) => {
console.log(req.body); //display what was received
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'myEmail#gmail.com', // generated ethereal user
pass: 'xxxxxx', // generated ethereal password
},
});
transporter.sendMail({
from: 'myEmail#gmail.com',
to: 'All of my Subscribers <myEmail#gmail.com>',
bcc: req.body.to,
subject: req.body.subject,
html: req.body.message,
attachments: req.body.attachments,
}, (err, info) => {
console.log('email sent or was there an error?');
if (err) {
console.log(err);
}
else {
console.log('Email Sent: ', info.response);
}
});
});
First, I'm aware that attachments: req.body.attachments wouldn't work for Nodemailer, I'll cross that bridge when I get there lol.
All the data received except for req.body.attachments?
This is what is logged by the console:
{
to: [email1#gmail.com, email2#yahoo.com, anotherOne#outlook.com],
subject: 'Test email',
message: '<p>This email was received from Nodemailer</p>\n',
attachments: {}
}
My question is this:
Why am I not receiving any file data when I clearly passed it through?
How do I properly pass a file from the front end to the server? If there is a better way please enlighten me. I've seen a lot of different techniques, but none have made complete sense to me yet.
To pass a file from the front end to the server Please use FormData (https://developer.mozilla.org/en-US/docs/Web/API/FormData) from client side. And server side I would recommend you to use the https://www.npmjs.com/package/express-fileupload package to handle incoming files
And dont forget to set your Content-Type header to multipart/form-data

Next.JS and Nodemailer, Sending an email from contact form

I have a problem with my contact form in next.js, I don't have any errors (that are shown), everything worked untill deployment (on Vercel). I fetch my form, and have status 200, but I do not recive my email on Gmail. Also I don't recive any additional information.
I've recived emails, when I tested my app on "dev" and "build".
I've also have "less secure apps" option in Gmail account.
Here's my code in Next.JS:
fetch method in contact.js:
fetch("/api/contact", {
method: "POST",
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: mailName,
email: mailAddress,
text: mailText,
}),
}).then((res) => {
console.log("Fetch: ", res);
res.status === 200
?
router.push("/success")
: router.push("/error");
in api/contact.js
require("dotenv").config();
const nodemailer = require("nodemailer");
export default (req, res) => {
const { name, email, text } = req.body;
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
const mailOption = {
from: `${email}`,
to: `${process.env.EMAIL}`,
subject: `New mail from ${email}`,
text: `
${name} wrote:
${text}
`,
};
transporter.sendMail(mailOption, (err, data) => {
if (err) {
console.log(err);
} else {
console.log("mail send");
}
});
console.log(name, email, text);
res.send("success");
};
Please help
Since your code runs fine in local and not in the deployment environment I have two suggestions.
First, make sure you have all the environment variables set.
Secondly, the way you have written your code it will always return success because transporter.sendMail is asynchronous and res.send is outside of it.
Change like,
transporter.sendMail(mailOption, (err, data) => {
if (err) {
console.log(err);
res.send("error" + JSON.stringify(err));
} else {
console.log("mail send");
res.send("success");
}
});

While sending routes and data to server side from client . I'm not recieving data on server side

I'm trying to upload the file to server. currently I'm uploading images.
This is my client side code
onClickfileupload(){
let data={};
let path="";
let api_url = '/api/uploadFileFromIonicHome';
this.fileChooser.open()
.then(uri =>
{
path= JSON.stringify(uri);
alert(path);
data={
userEmail: this.userEmail,
userName: this.userName,
userRole: this.userRole,
fileComment: this.desc,
type: "file",
fullFileName:'file-'+Date.now()+'.jpg'
}
this.imagesProvider.uploadImage(path, data, api_url).then((res) => {
let dataPassedBackObj = {
reload: true,
pathOfFile: path,
typeOf: "picture",
userName: this.userName,
fileComment: this.desc
}
alert("Successfully uploaded picture...");
this.events.publish('toggleMenu');
}, err => {
alert(err.http_status);
alert("There was error in uploading picture...");
}); })
.catch(e => alert(e));
}
This is my provider what I'm using to upload the file to server side.
This is my providers code
uploadImage(img, data ,api_url) {
alert("Uploading file...");
// Destination URL
let url = SERVER_HOST + api_url;
// File for Upload
var targetPath = img;
console.log("line 28"+targetPath);
var options: FileUploadOptions = {
fileKey: 'image',
chunkedMode: false,
mimeType: 'multipart/form-data',
params: data,
};
const fileTransfer: FileTransferObject = this.transfer.create();
return fileTransfer.upload(targetPath, url, options);
}
This is my server side code where I'm getting the routes. but req. body is coming empty {}.
This is part of my server side code
app.post('/api/uploadFileFromIonicHome', uploadFromHome.single('image'), function(req, res) {
console.log('within /api/uploadFileFromIonicHome');
console.log(req.body.type);
console.log(req.body);
var userName = req.body.userName;
var userEmail = req.body.userEmail;
var userType = req.body.userRole;
var fileName = req.body.fileName;
var type = req.body.type;
var comment = req.body.comment;
var fileComment = req.body.fileComment;
I'm getting empty "req.body"
and "req.body.type is undefined."
This the error I'm getting
typeerror:cannot convert object to primitive value
Use connect-multiparty to read files. Reference link
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
app.post('/upload', multipartMiddleware, function(req, resp) {
console.log(req.body, req.files);
// don't forget to delete all req.files when done
});

Calling NodeJS function from JS function

I am doing a project based on firebase and I need to link a server-side function that sends an email to the client-side script.
This is my server-side index.js file
const functions = require('firebase-functions');
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'xxx#gmail.com',
pass: 'password'
}
});
var mailOptions = {
from: 'xxx#gmail.com',
to: 'xxx#gmail.com',
subject: 'Sending Email using Node.js',
text: 'That was easy!'
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
I am wondering how I could have a button in html call a function in the script that will call the transporter.sendMail. I have never touched node js before so please excuse my lack of knowledge.
If this helps firebase setup my folders to be separated by functions and public for the server-side and client-side files
First initialize your HTML page with jQuery and on submitting the form send an Ajax request to the server as follows
$(document).ready(function() {
$("#formoid").submit(function(event) {
event.preventDefault();
$.ajax({
url: 'http://xxxxxxx.com/contact', // url where to submit the request
type : "POST", // type of action POST || GET
dataType : 'json', // data type
data : $("#formoid").serialize(), // post data || get data
success : function(result) {
$('#formoid')[0].reset();
},
error: function(xhr, resp, text) {
console.log(xhr, resp, text);
}
})
});
});
Create a route called contact in your NodeJS server and listen for the contact request with All parameters required for your need. In the following case am using an express server and body parser to parse the data from incoming request
app.post('/contact', (req, res) => {
var transporter = nodemailer.createTransport({
service: "Gmail",
auth: {
user: "xxxxx",
pass: "xxxxx"
}
});
var mailOptions = {
from: req.body.email,
to: 'xxxxx#xx.com',
subject: 'Contact form',
text: 'From: ' + req.body.name + '\n Email: ' + req.body.email + '\nMessage: ' + req.body.msg
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
res.status(500).json({
message: "Error",
error: error
})
} else {
res.status(200).json({
message: "Its working",
response: info.response
})
}
});
});
In the above request am sending the name:as name, email: as email and message: as msg

Categories

Resources