9

Basically I have an image created using Canvas and it's in base64 encoded data URI. This data URI is then attached to email.

...,
 attachments:[{
 filename: "cat.jpg",
 contents: new Buffer(cat, 'base64')
}],

The email is received but the attachment is not viewable. Running $ file cat.jpg in linux returns:

cat.jpg: ASCII text, with very long lines, with no line terminators

Why is this ASCII? I had already mentioned base64. How may I fix this problem? Thank you.

Developerium
  • 7,155
  • 5
  • 36
  • 56

4 Answers4

15

A buffer is not needed. You can just put the string starting from behind the base64 encoding prefix into it:

var cat = "...base64 encoded image...";
var mailOptions = {
  ...
  attachments: [
    {   // encoded string as an attachment
      filename: 'cat.jpg',
      content: cat.split("base64,")[1],
      encoding: 'base64'
    }
  ]
};

More Details you find here: https://github.com/nodemailer/nodemailer#attachments

lohsie
  • 181
  • 1
  • 7
9

The variable cat probably includes the 'data:image/jpeg;base64,' part. You shouldn't pass that bit to Buffer.from.

It seems that if you pass in invalid data, Buffer.from() doesn't complain:

var pixel = "data:image/gif;base64,"
    + "R0lGODlhAQABAIABAP///wAAACH5"
    + "BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
var buffer = Buffer.from(pixel, "base64"); // does not throw an error.

You even get back a valid Buffer. The buffer is a corrupt image (or rather, it doesn't begin with an image header).

You have to strip the first part of the data URI yourself:

var buffer = Buffer.from(pixel.split("base64,")[1], "base64");

Edit (may 2021): Changed new Buffer to Buffer.from, as the former is deprecated.

RickN
  • 12,537
  • 4
  • 24
  • 28
  • It works now. I'm just curious, did you know this or you tested it? – Ильич Ленин Jun 12 '14 at 02:36
  • 1
    Not sure if I'm interpreting your question correctly, but: I *know* Nodemailer wants a valid image buffer and I *tested* that `new Buffer(stringWithPrefix)` creates a broken image and `new Buffer(stringWithoutPrefix)` does not. I could see that the constructor doesn't cause an error and that the two buffers don't start with the same bytes (as expected). Wrote the files to disk and checked their integrity. Does that answer your question? – RickN Jun 12 '14 at 09:10
2

You can simply use the package nodemailer-base64-to-s3.

Install the package:

npm install -s nodemailer-base64-to-s3

Configure it with nodemailer:

var base64ToS3 = require('nodemailer-base64-to-s3');
var nodemailer = require('nodemailer');

var transport = nodemailer.createTransport({});
transport.use('compile', base64ToS3(opts));

https://github.com/ladjs/nodemailer-base64-to-s3

2

You can just use path for that without any additional manipulations:

    let attachments = [
        {
            filename: "image.gif",
            path: "data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
        }
    ]

Here the link to the related documentation

vir us
  • 9,920
  • 6
  • 57
  • 66