0

I'm trying to send multiple attachments with Sendgrid with a new promise as below. I want to return an array of objects but I don't understand how to do so. emailAttachments contains my 3 objects, but how can I return the array? Can you tell me what's wrong in my code?

const emailAttachments = []

return new Promise(function(resolve, reject){

    pdfList.map(item => {

        fs.readFile((item.frDoc), (err, data) => {
            if (err) {
              return { handled: false }
            }

            if (data) {
                
                emailAttachments.push({
                    content: data.toString('base64'),
                    filename: `document.pdf`,
                    type: 'application/pdf',
                    disposition: 'attachment'
                })

            }
        });
    })

    resolve(emailAttachments)
})
Nat Riddle
  • 928
  • 1
  • 10
  • 24
taurOan
  • 187
  • 3
  • 16
  • 2
    `map` returns a new array so there's no need to `push` elements into an empty array. [This may also give you some clues](https://stackoverflow.com/questions/34628305/using-promises-with-fs-readfile-in-a-loop) as to using `readFile` with promises. – Andy Oct 10 '21 at 14:26

2 Answers2

3

You are mixing callback functions and promises. That won't work. I'd suggest to use the promise API of the fs module supported since node 10.

Furthermore, you need to await the filereading before resolving promise, which you currently don't do.

import { promises as fsp} from "fs"; //use the Promise API from fs

async function getAttachments(pdffiles) {
  return Promise.all(pdffiles.map(pdf => fsp.readFile(pdf.frDoc)))
    .then(files => files.map(f => ({
       content: f.toString("base64"),
       filename: "document.pdf",
       type: "application/pdf",
       disposition: "attachment"
     })));

}
derpirscher
  • 14,418
  • 3
  • 18
  • 35
2

I think you need something like this:

async function getEmailAttachments(pdfList) {
    const emailAttachments = await Promise.all(pdfList.map((item) => {
        return new Promise(function (resolve, reject) {
            fs.readFile((item.frDoc), (err, data) => {
                if (err) {
                    reject({ handled: false });
                }
                if (data) {
                    resolve({
                        content: data.toString('base64'),
                        filename: `document.pdf`,
                        type: 'application/pdf',
                        disposition: 'attachment'
                    });
                }
            });
        });
    }));
    return emailAttachments;
}

[EDIT] Or using the promise version of readFile (sugestion of @derpirscher):

async function getEmailAttachments(pdfList) {
    const emailAttachments = await Promise.all(pdfList.map(async (item) => {
        const data = await fs.promises.readFile(item.frDoc);
        return {
            content: data.toString('base64'),
            filename: `document.pdf`,
            type: 'application/pdf',
            disposition: 'attachment'
        };
    }));
    return emailAttachments;
}
cj-2307
  • 259
  • 3
  • 14