Ilya Khadykin
Ilya Khadykin

Reputation: 300

How can I attach an image to an email from an URL using nodemailer and request modules in node.js?

I'm new to javascript and node.js and trying to learn it by doing something useful. So, I want to send an email with an image as attachment. The image will be retrieved from a remote server by issuing HTTP GET request and send to an email address using Gmail via nodemailer (SMTP)

By reading the docs and looking through examples, I managed to send an email without attachment, but I can't figure out how to send it by using Streams. I used the following code, but it returns en error which I can't fix myself and need help:

var nodemailer = require('nodemailer');
var request = require('request');
var config = require('../config');
var mailer;

mailer = function (opts) {
    var transporter = nodemailer.createTransport({
        service: 'Gmail',
        auth: {
            user: config.GmailAuth.email,
            pass: config.GmailAuth.password
        }
    });

    var mailOptions = {
        from: opts.from, // sender address
        to: opts.to, // list of receivers
        subject: opts.subject, // Subject line
        html: opts.body,  // html body
        attachments: [
            {
                filename: 'screenshot.png',
                content: request(opts.imageUrl)  // <-- Error here 
            }
        ]
    };

    transporter.sendMail(mailOptions, function(error, info){
        if (error) {
            return console.log(error);
        } else {
            console.log('Message sent: ' + info.response);
        }
    });
}

mailer({
        from: config.GmailAuth.email,
        to: config.sendToAddress, 
        subject: 'TEST SUBJECT',
        body: 'TEST MESSAGE BODY',
        imageUrl: 'URL_to_an_image_for_HTTP_GET_request'
       });

The following error occurs:

stream.js:74
      throw er; // Unhandled stream error in pipe.
      ^

Error: write after end
    at writeAfterEnd (_stream_writable.js:159:12)
    at Encoder.Writable.write (_stream_writable.js:204:5)
    at Encoder.Writable.end (_stream_writable.js:433:10)
    at Request.<anonymous> (C:\Users\user\Desktop\graphite_monitor\node_modules\
buildmail\src\buildmail.js:573:35)
    at Request.g (events.js:260:16)
    at emitOne (events.js:82:20)
    at Request.emit (events.js:169:7)
    at Request.onRequestError (C:\Users\user\Desktop\graphite_monitor\node_modul
es\request\request.js:820:8)
    at emitOne (events.js:77:13)
    at ClientRequest.emit (events.js:169:7)

What is the problem and how can I fix it?

Upvotes: 6

Views: 6151

Answers (2)

Ilya Khadykin
Ilya Khadykin

Reputation: 300

I've managed to make it work using PassThrough Streams (here is somewhat similar question), here is working code (add changes where needed in my initial code):

var PassThrough = require('stream').PassThrough;

var nameOfAttachment = 'screenshot.png';
var imageUrlStream = new PassThrough();
request
     .get({
             proxy: 'http://YOUR_DOMAIN_NAME:3129', // if needed
             url: opts.imageUrl
         })
     .on('error', function(err) {
             // I should consider adding additional logic for handling errors here
             console.log(err);
    })
     .pipe(imageUrlStream);

var mailOptions = {
    from: opts.from, // sender address
    to: opts.to, // list of receivers
    subject: opts.subject, // Subject line
    html: opts.body, // html body
    attachments: [
        {
            filename: nameOfAttachment,
            content: imageUrlStream
        }
    ]
};

I hope it'll help other beginners

Upvotes: 2

Jonatas Walker
Jonatas Walker

Reputation: 14150

Try changing this:

attachments: [
  {
    filename: 'screenshot.png',
    content: request(opts.imageUrl)  // <-- Error here 
  }
]

to:

attachments: [
  {
    filename: "pin-marker.png",
    path: "http://img.mapeando.net/map/pin-marker.png", // <-- should be path instead of content
    cid: "pin-marker.png"
  }
]

Upvotes: 4

Related Questions