Get the path of selected file ( <input type="file"...> ) - email

in my application there is an input field to upload a CV.
What I need to do is when the file is selected, send that CV (pdf) as an attachment with an email to a user.
For that Im using Sendgrid. In sendgrid we have to arrange the email option like below.
const fs = require('fs');
pathToAttachment = `file_path`;
attachment = fs.readFileSync(pathToAttachment).toString('base64');
const email = {
...
attachments: [
{
content: attachment,
filename: 'file_name',
type: 'application/pdf',
disposition: 'attachment'
}
]
...}
So here it is need to insert a file path to attach the pdf into email. I used Bootstrap for the input field. So I need to know, how can I insert the selected file's path. At the moment I can only get the select file using event.
pdfFile = event.target.files[0];

In the example code, the attachment is loaded from the file system, however in this case the attachment is being entered via a web form with a file input. So, you don't need to fetch the file from the file system, but deal with it from the form submission.
When you submit the form with attachments, the attachment is sent to your server when the form is submitted. Attachments are normally sent in the multipart/form-data format. From your code example, it looks like you are using Node.js, so I will also assume your server is an Express server. There are many ways to parse incoming multipart requests, one option is multer. To receive your file upload with multer and then pass it on to SendGrid would look like this:
const express = require('express');
const app = express();
const multer = require('multer');
const memoryStore = multer.memoryStorage();
const upload = multer({ storage: memoryStore });
app.post('/profile', upload.single("cv"), async function (req, res, next) {
// req.file is the "cv" file
const email = {
from: FROM,
to: TO,
text: "This has an attachment",
attachments: [
{
content: req.file.buffer.toString("base64"),
filename: "cv.pdf",
type: "application/pdf",
disposition: "attachment",
}
]
};
await sg.mail(email);
res.send("OK");
})
I chose memory storage for this file as it doesn't necessarily need to be written to disk. You may want to write the file to disk too though, and there are other considerations about using memory for this.
Because the file is in memory, req.file has an object that describes the file and has a buffer property that contains the contents. SendGrid needs you to base64 encode your attachments, so we call req.file.buffer.toString("base64").
This is a quick example, I recommend you read the documentation for multer to understand how your uploads work and how you can apply this to sending email attachments.

Related

uppy.io using to send base64 encoded data rather than specifying a file input

Is there a way to send base64 encoded data using uppy.io? I already have it working for 'soft-copy' document uploads using the Dashboard component, but cant seem to work out a way where I can pass the file bytes and not use an input file tag to provide the data to be uploaded.
Context:
I have a page that uses a JavaScript component to access local scanner hardware. It scans, shows a preview, all working. The user then hits an upload button to push it to the server, the scanning component outputs the scan as base64 encoded data. I can send this up to the server using XMLHttpRequest like so:
var req = new XMLHttpRequest();
var formData = new FormData();
formData.append('fileName', uploadFileName);
formData.append('imageFileAsBase64String', imageFileAsBase64String);
req.open("POST", uploadFormUrl);
req.onreadystatechange = __uploadImages_readyStateChanged;
req.send(formData);
but I would really like to use uppy because scan files can be quite large and I get the resumable uploads, nice progress bar etc, and I already have tusdotnet on the back setup and ready to receive it.
All the examples rely on input tags so I dont really know what approach to take. thanks for any pointers.
I eventually figured this out. here in case its useful to anyone else.
you can use fetch to convert the base64 string, then turn it into a blob and finally add it to uppy files via the addFile api.
I referenced this article:
https://ionicframework.com/blog/converting-a-base64-string-to-a-blob-in-javascript/
code below works with my setup with tusdotnet handling the tus service server side.
var uppy = new Uppy.Core({
autoProceed: true,
debug: true
})
.use(Uppy.Tus, { endpoint: 'https://localhost:44302/files/' })
.use(Uppy.ProgressBar, {
target: '.UppyInput-Progress',
hideAfterFinish: false,
})
uppy.on('upload', (data) => {
uppy.setMeta({ md:'value' })
})
uppy.on('complete', (result) => {
// do completion stuff
})
fetch(`data:image/jpeg;base64,${imageFileAsBase64String}`)
.then((response) => response.blob())
.then((blob) => {
uppy.addFile({
name: 'image.jpg',
type: 'image/jpeg',
data: blob
})
});

adding custom attribute to message not storing message in Archive table on server using stanza.io

I am working on ionic-framework and i'm using stanza.io library to implement chatting with xmpp server, I want to add some custom attributes while sending message, for that i have followed the steps for creating plugin. my code is as follow...
sendMsg() {
console.log("Sending message");
function customMessage(client, stanzas) {
const NS = 'http://www.w3.org/2005/Atom';
var types = stanzas.utils;
const messageAttribute = stanzas.define({
name: 'messageAttribute',
element: 'messageAttribute',
namespace: NS,
fields: {
title: types.textSub(NS, 'title'),
summary: types.textSub(NS, 'summary'),
published: types.textSub(NS, 'published'),
updated: types.textSub(NS, 'updated'),
cont: types.textSub(NS, 'cont')
}
});
stanzas.withMessage((Message) => {
stanzas.extend(Message, messageAttribute);
});
}
this.client.use(customMessage);
this.client.sendMessage({
to: this.recep,
body: "",
messageAttribute: {
'title': "some title",
'summary': "message",
'published': "time stamp here",
'updated': "time stamp here",
'cont': "cht"
}
});
console.log("Message sent " + this.sMsg);
}
but doing this way message are not being stored in Archive table on server. that will create a problem to get the history from the server. if we use the simple code then that messages being stored on Archive table on server. simple code as follow..
this.client.sendMessage({
to: this.recep,
body: this.sMsg
});
in simple code we can only send message as a string inside body. can anyone help me to solve this?
My server is only archiving messages which contain a body element with text, which is a pretty common archiving configuration. One trick would be trying to include a dummy body text to trigger message archiving, but you'd have to check if the server is storing and returning the full stanza or just extracting and saving the body text.
done everything correctly with extending Stanza to include the additional fields, but need to adjust server to get what i want. confirmed from here.
You need to add an extra param store in message stanza which makes the message to store in Archive table by default.
const store = stanzas.define({
name: 'store',
element: 'store',
namespace: 'urn:xmpp:hints'
});
stanzas.withMessage(Message => {
stanzas.extend(Message, store);
});
Sent store attribute as true in message stanza
this.client.sendMessage({
to: this.recep,
body: this.sMsg,
store: true
});
You should see store inside message stanza like
<store xmlns='urn:xmpp:hints'/>

Read Uint8Array buffer from Collection and download as pdf

I saved a pdf file in a collection using this function:
/*** client.js ***/
// asign a change event into input tag
'change input' : function(event,template){
var file = event.target.files[0]; //assuming 1 file only
if (!file) return;
var reader = new FileReader(); //create a reader according to HTML5 File API
reader.onload = function(event){
var buffer = new Uint8Array(reader.result) // convert to binary
Meteor.call('saveFile', buffer);
}
reader.readAsArrayBuffer(file); //read the file as arraybuffer
}
/*** server.js ***/
Files = new Mongo.Collection('files');
Meteor.methods({
'saveFile': function(buffer){
Files.insert({data:buffer})
}
});
How can I read it again from the collection and provide a download link that the user can download the file as a pdf and save it on the local computer?
It depends on what the data type ends up to be on the front-end when you see that document record in your MiniMongo collection. What you want to do is to convert that Uint8Array data to a base64-encoded data URL and provide a Download PDF link after you get the data in the browser.
Meteor does not support serving files from the server out of the box, so you'll likely have to publish that file's blob via mongo->minimongo publication/subscription mechanism and then use the HTML data-uri API to get it like I've just described.

How to send attachments using mailgun?

In my form there is section to upload resume I use mailgun API for my mails to send, I am finding trouble for sending attachments using the form.
How to send the attached file along with other details of my form when user submits.
Please see the below image of my form the attachments should be dynamic but not static.
Example with Node.js
var mailgun = require('mailgun-js')({apiKey: api_key, domain: domain});
var filename = 'mailgun_logo.png';
var filepath = path.join(__dirname, filename);
var file = fs.readFileSync(filepath);
var attch = new mailgun.Attachment({data: file, filename: filename});
var data = {
from: 'Excited User <me#samples.mailgun.org>',
to: 'serobnic#mail.ru',
subject: 'Hello',
text: 'Testing some Mailgun awesomness!',
attachment: attch
};
mailgun.messages().send(data, function (error, body) {
console.log(body);
});

Send multiple attachments with Grails Async Mail Plugin

I am using grails Async Mail plugin to send emails with attachments in my app. to achieve that I have written following code
def sendEmail = {
def documentsInstances = Documents.getAll(params.list('ids[]'))
def s3Service = new AmazonS3Service()
documentsInstances.each(){documentsInstance->
asyncMailService.sendMail {
multipart true
to documentsInstance.author.emailAddress
subject 'Test';
html '<body><u>Test</u></body>';
attachBytes documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid,documentsInstance.filename);
}
}//
}
Now the code above works pretty much correctly but it sends an email per attachment, I am not sure how can I move this loop inside send mail so that I can send multiple attachments in an email.
Also is there a way to send an email so that I don't have to load a whole file in byte[]?
I am using JetS3t for access to Amazon S3 and I tried "attach" method with
new InputStreamResource(s3Obj.getDataInputStream()) ie
attach documentsInstance.filename , 'text/plain', new InputStreamResource(s3Obj.getDataInputStream());
but I am getting
"Passed-in Resource contains an open stream: invalid argument. JavaMail requires an InputStreamSource that creates a fresh stream for every call"
You need your loop inside the email:
def sendEmail = {
def documentsInstances = Documents.getAll(params.list('ids[]'))
def s3Service = new AmazonS3Service()
asyncMailService.sendMail {
multipart true
to documentsInstance.author.emailAddress
subject 'Test';
html '<body><u>Test</u></body>';
// loop over attachments
documentsInstances.each{ documentsInstance->
attachBytes documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid, documentsInstance.filename);
}
}
}
This should attach multiple files.
If it throws an error about not being able to find an attachBytes method, you might need to explicitly call owner.attachBytes instead, which should refer to the outer sendMail closure.
Update based on comments:
The Async plugin looks like it defers to the normal mail plugin. The normal mail plugin's docs describes how to use multiple attachments.
This would look something like:
// loop over attachments
documentsInstances.each{ documentsInstance->
attach documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid, documentsInstance.filename);
//^^^^^^ Notice, just 'attach', not 'attachBytes'
}
I don't know the S3 plugin you are using, but if there is a way to retrieve an InputStreamSource from it, it appears that you can stream the bytes directly to the mail plugin, instead of loading them into memory.