13

Does anyone know how to tell Node.js´ module nodemailer to use an external HTML file (with links to stylesheets) as email content?

I am able to type in HTML tags as email content but I prefer loading complete HTML files. I´m using nodemailer 1.3.0.

Unfortunately I can´t find any example covering this issue for the actual nodemailer version.

Ideas?

wurstbrotrest
  • 329
  • 1
  • 7
  • 17

3 Answers3

16

Use http://styliner.slaks.net

It is a node.js package that allows you to inline your css, so that you can then use nodemailer to send the complete HTML email.

It can also prepend / update links within your email so that they are not relative links any more. (ie. you could change a link like "coverage/local.html" to "\myhostname\afolder\coverage\local.html"

Here's a rough and ready script that I knocked up to send the output of Istanbul code coverage via email.

/*
 * Use this script to send Istanbul code coverage results via email.
 * 
 * NPM REQUIREMENTS:
 *  The following packages need to be installed:
 *   - npm install styliner
 *   - npm install nodemailer
 *   - npm install nodemailer-smtp-transport
 * 
 * Usage: node sendNodeJSCoverageEmail.js <origfile> <basedir> <receipient>
 * 
 *  <origfile>  : This is the original Istanbul index.html from the code coverage report
 *  <basedir>   : TeamCity directory where the index.html resides. Must contain "DevTC" folder (see below)
 *  <recipient> : Email address to send the results to. 
 * 
 * What it does:
 *  Istanbul creates an html report for code coverage. It is a complete web page, and has an index.html,
 *  some CSS style sheets, and relative links to other coverage.
 *  
 *  This script takes the index.html, reads the referenced .css files, and inlines the css, so that external
 *  files are no longer needed. (this is because you can't send multiple files for an html email).
 *  Also, the relative links are prepended with the UNC path to the files: this means that the recipients 
 *  can click on the links in the html email and they will work. 
 *  
 *  NOTE: it assumes the TeamCity folder where the coverage reports reside is shared, and also contains the 
 *        folder DevTC (it looks for this folder to do the substitution). All build machines have this 
 *        folder structure. 
 *        
 */

var nodemailer = require('nodemailer');
var os = require("os");
var hostname = os.hostname();

var originalFile = process.argv[2].toString();
var baseDir = process.argv[3].toString();
var recipient = process.argv[4].toString();

var Styliner = require('styliner');


var uncDrive = '\\\\' + hostname + '\\DevTC';
var uncPath = baseDir.replace(/.*DevTC/gi, uncDrive);


// prependUNCPath is a function called by Styliner for every
// link that is found in the HTML.
function prependUNCPath(path, type) {
    return uncPath + path;
}

// See http://styliner.slaks.net/#about for Styliner options
var options = { url : prependUNCPath, noCSS : true };
var styliner = new Styliner(baseDir, options);

function sendEmail(source) {

    var nodemailer = require('nodemailer');
    var smtpTransport = require('nodemailer-smtp-transport');

    // create reusable transporter object using SMTP transport
    var transport = nodemailer.createTransport(smtpTransport({
        host: 'your-smtp-server.local',  // FIXME: Change this!
        port: 25,
    }));


    // setup e-mail data with unicode symbols
    var mailOptions = {
        from: 'TeamCity <teamcity@company.com>', // sender address
        to: recipient, // list of receivers
        subject: 'Code Coverage results', // Subject line
        // text: 'Hello world ?', // plaintext body, not used
        html: source // html body
    };

    // send mail with defined transport object
    transport.sendMail(mailOptions, function (error, info) {
        if (error) {
            console.log(error);
        } else {
            console.log('Message sent: ' + info.response);
        }
    });


}


var fs = require('fs')

// Do the reading of the original index.html, and kick everything off.
fs.readFile(originalFile, 'utf8', function (err, data) {
    if (err) {
        return console.log(err);
    }

    styliner.processHTML(data)
    .then(function (source)
         {

        sendEmail(source);

        fs.writeFile("newindex.html", source, function (err) {
            if (err) {
                return console.log(err);
            }

            console.log("The file was saved!");
        });

      }

    );

});
Stretch
  • 3,669
  • 2
  • 28
  • 40
10

You should use inline css, not a separate file since HTML rendering of head elements and such are defined by provider not by nodemailer.

I'd recomend mailChim's css inliner tool, it's pretty handy, just set the

html: '<div style="font - family: verdana; max-width:500px; margin-left">' + 'more string and string'
Gabriel Balsa
  • 141
  • 1
  • 5
0

I would suggest using the fs module's readFile function to read in your HTML file, then send it in an email inside the callback.

Tutorial on readFile: http://docs.nodejitsu.com/articles/file-system/how-to-read-files-in-nodejs

IceMetalPunk
  • 5,476
  • 3
  • 19
  • 26
  • I´m only able to get the HTML file as attachment but not using its content as email-content. – wurstbrotrest Sep 24 '14 at 12:02
  • I tried way you described. Using fs I can store the content of my HTML doc in a variable. But I can´t assign this variable to nodemailer´s mailOptions. html : HTMLContent does not work. What is to do next? – wurstbrotrest Sep 24 '14 at 12:36
  • It should work just fine. Have you double-checked that your HTMLContent variable contains the correct content? And you're putting it in the "html" property of your mailOptions, not the "text" property, right? If you're sure of those and it's still not working, one last-ditch effort is to try setting a header of {"Content-type": "text/html"} in your mailOptions (see the docs for the "headers" option for more info) and see if that helps. – IceMetalPunk Sep 24 '14 at 14:02
  • I have tried many options – without success. However I don´t know what you mean where exactly I should set a header of {"Content-type": "text/html"} in my mailOptions. Do you have a concrete example? BTW where are the docs for the "headers" option you mentioned? Have a link? – wurstbrotrest Sep 24 '14 at 19:24
  • mailOptions is the example name for the object you pass to the sendMail() function containing all its option values, like to, from, subject, html, etc. The official nodemailer docs explain all about it as well as about adding your own headers: https://github.com/andris9/Nodemailer – IceMetalPunk Sep 27 '14 at 12:53