Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs send stream via email

I'm trying to send my stream data via email using Nodemailer but for some reason, the attachment is coming up as 0 kb when I download it and look at its info. How can I properly send the stream & it's data as an attachment? The stream should contain a PKPass is it a better option to send the response as an attachment? I'm using passkit-generator to generate the PKPass

const stream = examplePass.generate();

res.set({
    'Content-Type': 'application/vnd.apple.pkpass',
    'Content-disposition': `attachment; filename=${passName}.pkpass`,
});

stream.pipe(res);

//Send the receipt email

stream.on('finish', (attach) => {

    let transporter = nodemailer.createTransport({
        host: 'smtp.gmail.com',
        port: 587,
        secure: false,
        requireTLS: true,
        auth: {
            user: '[email protected]',
            pass: 'password',
        },
    });

    let mailOptions = {
        from: '[email protected]',
        to: '[email protected]',
        subject: 'You\'re on your way to ',
        html: '<h1>Reciept email</h1>',
        attachments: [
            {
                filename: 'Event.pkpass',
                contentType: 'application/vnd.apple.pkpass',
                content: stream,
            },
        ],
    };

    transporter.sendMail(mailOptions, (error, info) => {
        if (error) {
            return console.log(error.message);
        }
        console.log('success ' + info);
    });

});
like image 834
user Avatar asked Jun 11 '20 22:06

user


2 Answers

It seems that in this case, the only way to send the file is to read the entire stream and send it as a string or buffer:

const stream = examplePass.generate();

res.set({
    'Content-Type': 'application/vnd.apple.pkpass',
    'Content-disposition': `attachment; filename=${passName}.pkpass`,
});

stream.pipe(res);

const chunks = [];

stream.on('data', chunk => {
    chunks.push(chunk);
});

stream.on('end', () => {
    const content = Buffer.concat(chunks);

    const transporter = nodemailer.createTransport({
        host: 'smtp.gmail.com',
        port: 587,
        secure: false,
        requireTLS: true,
        auth: {
            user: '[email protected]',
            pass: 'password',
        },
    });

    const mailOptions = {
        from: '[email protected]',
        to: '[email protected]',
        subject: 'You\'re on your way to ',
        html: '<h1>Reciept email</h1>',
        attachments: [
            {
                filename: 'Event.pkpass',
                contentType: 'application/vnd.apple.pkpass',
                content
            },
        ],
    };

    transporter.sendMail(mailOptions, (error, info) => {
        if (error) {
            return console.log(error.message);
        }
        console.log('success:', info);
    });

});

BUT! You need to be careful with this approach if the file is large, as it is fully loaded into RAM.

like image 125
Rustam D9RS Avatar answered Nov 19 '22 21:11

Rustam D9RS


Your problem is that you piped the stream to res which is a "StreamReader" aka consumer, instead you need just to pass it to nodeMailer which it is a StreamReader by itself.

const stream = examplePass.generate();

// res.set({
//   'Content-Type': 'application/vnd.apple.pkpass',
//   'Content-disposition': `attachment; filename=${passName}.pkpass`,
// });

// stream.pipe(res); <- remove this

//Send the receipt email

stream.on('finish', (attach) => {
  let transporter = nodemailer.createTransport({
    host: 'smtp.gmail.com',
    port: 587,
    secure: false,
    requireTLS: true,
    auth: {
      user: '[email protected]',
      pass: 'password',
    },
  });

  let mailOptions = {
    from: '[email protected]',
    to: '[email protected]',
    subject: "You're on your way to ",
    html: '<h1>Reciept email</h1>',
    attachments: [
      {
        filename: 'Event.pkpass',
        contentType: 'application/vnd.apple.pkpass',
        content: stream,
      },
    ],
  };

  transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
      return console.log(error.message);
    }
    console.log('success ' + info);
  });
});

This is how I'm streaming email attachments.

like image 39
felixmosh Avatar answered Nov 19 '22 23:11

felixmosh