Node.js Sendgrid attaching pdf files upto 7 MB crashes the server

Viewed 86

I have a Node.js + Express application running on EC2 instance. Part of that application is to send mass email to all its users (by the admin) with the ability to attach files (max 5 files allowed).

Recently we tested it by attaching three pdf files roughly the size of 2.5 MB each. When the send button is pressed the application keeps spinning before culminating to 504 Gateway Timeout error. I feel that maybe the sendgrid code is unable to process the attachments and the node server crashes taking down the EC2 with it. When this happens the only way for me is to stop the ec2 instance and then start it again. Rebooting does not help.

Here is the code

router.js

var fs = require('fs');
var multer  = require('multer');
const uploadsDir = './uploads';

// SET STORAGE
var storage = multer.diskStorage({
    destination: function (req, file, cb) {
      if (!fs.existsSync(uploadsDir)){
        fs.mkdirSync(uploadsDir);
      }
      cb(null, uploadsDir);
    },
    filename: function (req, file, cb) {
      cb(null, file.originalname);
  

    }
});
  
var upload = multer({ storage: storage });

router.post('/send', upload.array('files', 5), async (req, res) => {
    let subject = req.body.subject;
    let message = req.body.message;
    let result = message.replace(/(\r\n|\r|\n)/g, '<br>');

    let bccReceiverList = [];

    let whereCondition = {
        isActive: true
    };

    let attachments = [];
    if(req.files && req.files.length > 0) {
        req.files.forEach(file => {
            attachments.push({
                filename: file.originalname,
                type: file.mimetype,
                uploadPath: req.app.get('uploads')
            });
        });
    }

    let receiverUsers = await User.findAll({});

    //find to whom we are sending the email to
    for (let index = 0; index < receiverUsers.length; index++) {
        const user = receiverUsers[index];

        emailHandler.sendEmail(
            {
                receiver: user.email,
                bccReceiver: bccReceiverList,
                templateId: process.env.EMAIL_BLAST_TEMPLATE,
                attachments: attachments.length > 0 ? attachments : []
            },
            {
                subject: subject,
                message: result
            },
            data => {}
        );
    }

    if(req.files && req.files.length > 0) {
        req.files.forEach(file => {
            fs.unlink(req.app.get('uploads') + '/' + file.originalname, function (err) {
                if (err) {
                    console.error(err);
                }
                console.log('File has been Deleted');
                res.send('file was deleted');
            });
        });
    }

    res.redirect('back');
});

then in the actual email handler function

var sg = require('@sendgrid/mail');
var fs = require('fs');
sg.setApiKey(process.env.SENDGRID_API_KEY);

exports.sendEmail = async function(email, payload, callback) {
   
    let msg = {
        to: email.receiver,
        from: {email: 'admin@myapp.com', name: 'My App'},
        subject: email.subject,
        templateId: email.templateId,
        dynamic_template_data: payload
    };

    //Buffer.from(fileContent).toString('base64')
    if(email.attachments != null && email.attachments.length > 0) {
        try {
            let attachmentObjects = [];

            for (let index = 0; index < email.attachments.length; index++) {
                const attachment = email.attachments[index];
                const fileContent = fs.readFileSync(attachment.uploadPath + '/' + attachment.filename);

                attachmentObjects.push({
                    content: Buffer.from(fileContent).toString('base64'),
                    filename: attachment.filename,
                    type: attachment.mimetype,
                    disposition: "attachment"
                });
            }
            msg.attachments = attachmentObjects;
        } catch (error) {
            console.log(error);
            callback({status: 500, message: 'Error while attaching files to email: ' + error.message});
        }
    }

    if(email.hasOwnProperty('ccReceiver')) {
        if(email.ccReceiver != null) {
            msg.cc = email.ccReceiver;
        }
    }

    if(email.hasOwnProperty('bccReceiver')) {
        if(email.bccReceiver.length > 0) {
            msg.bcc = email.bccReceiver;
        }
    }
    
    sg.send(msg).then(() => {
        console.log('---- email sent successfully');

        // delete the attachment files from the uploads folder
        if(email.attachments != null && email.attachments.length > 0) {
            for (let index = 0; index < email.attachments.length; index++) {
                const attachment = email.attachments[index];
                fs.unlink(attachment.uploadPath + '/' + attachment.filename, function (err) {
                    if (err) {
                        console.error(err);
                    }
                    console.log('File has been Deleted');
                });
            }
        }
        callback({status: 200, message: 'Email Sent Successfully'});
    }).catch(error => {
        //Log friendly error
        console.error('error-------- : ' + error.toString());
        //Extract error msg
        const {
            message,
            code,
            response
        } = error;

        //Extract response msg
        const {
            headers,
            body
        } = response;
        callback({status: 500, message: 'Error while sending email: ' + error.message});
    });
};

I even tried just attaching one pdf file (2.5 MB) to the email and it still failed. When I perform this same test with files with lesser size then it works smoothly. I am not really sure how to solve this problem.

0 Answers
Related