Home > Mobile >  How to send excel file with nodemailer
How to send excel file with nodemailer

Time:10-12

I'm trying to send an email with an excel file attached, but when I open it an error pops up saying that the file is damaged. It also downloads the file (which I actually don't want to) and I can open that with no problem.

I'm using the js-xlsx library to create the file and the nodemailer library to send it.

Function in email.service.ts:

sendEmail(values: any) {
    let message: {from: string, to: string, subject: string, html: string, attachments: {}[] | null} = {
        from: '[email protected]',
        to: values.email,
        subject: values.oggetto,
        html: this.storage.createTable(values.messaggio).outerHTML,
        attachments: null
    }

    if (values.attach) {
        message["attachments"] = [{
            filename: values.fileName   '.xlsx',
            content: this.excel.createExcel(values),
            contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        }]
    }

    return this.http.post('http://localhost:3000/send', message)
}

Function in excel.service.ts:

createExcel(values: any) {
    const fileName = values.fileName   '.xlsx';
    const table = this.storage.createTable('');
    const ws: XLSX.WorkSheet = XLSX.utils.table_to_sheet(table);
    const wb: XLSX.WorkBook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, 'Presenze');
    return XLSX.writeFile(wb, fileName);
}

CodePudding user response:

From the documentation (https://docs.sheetjs.com/docs/api/write-options) I can see the following:

XLSX.writeFile(wb, filename, write_opts) attempts to write wb to filename. In browser-based environments, it will attempt to force a client-side download.

This is the reason a download is triggered on your client.

You probably want to use XLSX.write(workbook, { type: "array", bookType: "xlsx" });, so that an Uint8Array is returned from the function and attached as content to your form data.

CodePudding user response:

I got it to work.

First of all the right method is XLSX.write(wb, {type: 'buffer', bookType: 'xlsx'});, not XLSX.writeFile(...).

But the server was still throwing an error, saying that I was passing an Object. The problem was that I was sending what I thought was an Uint8Array, while the node app was actually receiving an Object.

Why? I don't know.

But knowing this I now convert the content to a Uint8Array directly in the node app.

Here's how I changed the code:

Function in email.service.ts:

sendEmail(values: any) {
    let message: {from: string, to: string, subject: string, html: string, attachments: {}[] | null} = {
        from: '[email protected]',
        to: values.email,
        subject: values.oggetto,
        html: this.storage.createTable(values.messaggio).outerHTML,
        attachments: null
    }

    if (values.attach) {
        message["attachments"] = [{
            filename: values.fileName   '.xlsx',
            content: this.excel.createExcel(values)
        }]
        }

    return this.http.post('http://localhost:3000/send', message)
}

Function in excel.service.ts:

createExcel(values: any) {
    const fileName = values.fileName   '.xlsx';
    const table = this.storage.createTable('');
    const ws: XLSX.WorkSheet = XLSX.utils.table_to_sheet(table);
    const wb: XLSX.WorkBook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, 'Presenze');
    return XLSX.write(wb, {type: 'buffer', bookType: 'xlsx'});
}

Function in the node app to send the email:

fastify.post('/send', (request, reply) => {
    let content = request.body.attachments[0].content;
    let array = new Uint8Array(Object.entries(content).length);

    for (let [key, value] of Object.entries(content)) {
        array[key] = value;
    }

    request.body.attachments[0].content = array;
    const mailOptions = request.body
    
    transporter.sendMail(mailOptions, (error, info) => {
        if (error) {
            console.log(error);
        } else {
            console.log('Sent: '   info.response);
        }
    })
})
  • Related