Handling Files over a Node JS server

Series 4/5 of Building an Email Application using Node JS Express JS with Gmail and Nodemailer.

Handling Files over a Node JS server

This is the fourth series of the Building an Email Application using Node JS Express JS with Gmail and Nodemailer. You can check out the third series Here where we retrieved data from our HTML form to the Node JS server.

In this article series, we will look into how we can handle files sent from the client-side to our project Node JS backend application.

In other to handle files coming from the frontend, we need to install a package called multer

Multer is a Node.js middleware, which is responsible for handling multipart/form-data in a form, which is primarily used for uploading files.

Multer also has a rule, which is that multer will not process any form which is not multipart (multipart/form-data).

In other to make multer work in our project we need to add an encryption attribute to our form tag like below.

    <form
      action="/send_email"
      method="POST"
      enctype="multipart/form-data"
      style="max-width: 500px; margin: auto"
    >

Ensure to update your form tag with the new attribute, after that, we need to create a new folder called attachments in our project root directory

Your project structure and index.js should look like this

image.png


Configuring Multer

To configure our project to use multer, we need to first install it using the command below

yarn add multer

Once it is installed, we need to configure it in our index.js file.

Setting up multer diskStorage

Multer allows us to specify where we want to store the attachments coming from the frontend and also define their unique names through its method called diskStorage.

require multer below where we required the express js

// Import express into our project
const express = require("express");

// Import multer
const multer = require("multer");

...

Copy-paste the following code, below the body-parser.

// Multer file storage
const Storage = multer.diskStorage({
  destination: function (req, file, callback) {
    callback(null, "./attachments");
  },
  filename: function (req, file, callback) {
    callback(null, `${file.fieldname}_${Date.now()}_${file.originalname}`);
  },
});

Explanation

multer.diskStorage

1. destination

This multer method allows us to set the destination of our attachment through a callback function, and as you can see we passed our attachment folder as the second argument of the callback function, this is where the attachment of a mail will be store (example coming up).

2. filename

The second property we can set using the diskStorage is the file name of the incoming attachment, we do this so that every attachment will have a unique file name, we concatenate the field name (from, input name=" attachment") with underscore _ and current date that the file is been attached in milliseconds with another underscore _ and finally the attachment original name.

That is super unique ๐Ÿ˜


Let's proceed to write middleware to actually get the attachment from the request body.

// Middleware to get a single attachment
const attachmentUpload = multer({
  storage: Storage,
}).single("attachment");

What we are doing here is that we are passing the attachment storage logic we created into the multer object and also telling multer that we are only targeting a single attachment with the .single("attachment").

Applying Multer Middleware to our Post Route

Now that we have set up a middleware with multer, which will help us retrieve attachments from the frontend form, let's proceed to apply it within our Post route.

Update the application post route with the following code

// Post route to handle retrieving data from HTML form to server
app.post("/send_email", (req, res) => {
  if (error) {
      console.log(err);
      return res.send("Error uploading file");
    } else {
      const recipient = req.body.email;
      const subject = req.body.subject;
      const message = req.body.message;
      const attachmentPath = req.file.path;
      console.log("recipient:", recipient);
      console.log("subject:", subject);
      console.log("message:", message);
      console.log("attachmentPath:", attachmentPath);
    }

});

Explanation

1. We invoked (call/execute) the attachmentUpload middleware function and extend (pass) the req and res parameter from the post route function to it. This will allow the middleware to have access to any file in the request body.
2. The attachmentUpload also takes in a callback function which will check for any error while attachmentUpload processes the files from the request body.
3. In the callback function, we are checking whether there is an error in the process, if any error occurs, we want to display the error in the terminal and send back a message which says Error uploading file as a response (res).

A call-back function is any function that is been passed as an argument to another function, which will be executed (call-back) later in time (any point in time).

4. Finally, we included an alternative statement with the else block which is executed if the previous statement is not satisfied. This implies that the else statement block will only run if there is no error when the middleware is trying to upload any attachments from the HTML form to the "attachment" folder.

Storing Files from HTML Form to our Storage Folder

Let's proceed to test our implementation so far.

Save your script and refresh your browser (if you're not using a live server) to get updated with our node script.

Fill the form inputs and attach any file of your choice as shown below ๐Ÿ‘‡ and hit the send button.

frame_generic_light (13).png

Output 1 ๐Ÿ‘‡

If all goes well, your terminal should have the following output ๐Ÿ‘‡

frame_generic_light (12).png

You should also notice that the attachment name has changed to the naming convention logic we created earlier ๐Ÿ‘‡.

frame_generic_light (14).png

Output 2 ๐Ÿ‘‡

The fun part is, if you expand the attachment folder, you will see your attached file there ๐Ÿ’ƒ, thanks to multer, you can also check the folder directory in the file explorer.

image.png

Check your File Explorer ๐Ÿ‘‡

image.png

You can check the complete code to this point from my GitHub gist Here โœ‹


In the next article, we will be setting up the Nodemailer package in our project.

Next ๐Ÿ‘‡

Let me know in the comment section if you have any difficulties.