transacemail
Version:
Transactional Email & Templated Email for NodeJS
196 lines (176 loc) • 4.7 kB
JavaScript
var path = require('path');
var fs = require('fs');
var _ = require('lodash');
var juice = require('juice');
var deepExtend = require('deep-extend');
// Support for Node v0.6
fs.existsSync = fs.existsSync || function existsSync(filePath) {
try {
fs.statSync(filePath);
} catch (err) {
if (err.code === 'ENOENT') {
return false;
}
}
return true;
};
/**
* Mail constructor
* @param {Object} templateEngine Template Engine that will be used to render the mail
* @param {String} metaPath Path to the mail meta file
* @private
*/
function Mail(templateEngine, metaPath) {
if (!templateEngine) {
throw new Error("Mail(templateEngine, metaPath): TemplateEngine is undefined.");
}
this.styles = [];
this._dir = path.dirname(metaPath);
this._name = path.basename(metaPath, Mail.DEFAULT_META_EXT);
this._mailing = null;
this.templateEngine = templateEngine;
this.html = null;
this.text = null;
this.sendIf = function (fn) {
return fn(false);
};
}
/**
* Meta file extension
* @type {String}
*/
Mail.DEFAULT_META_EXT = '.meta.js';
/**
* HTML mail format extension
* @type {String}
*/
Mail.DEFAULT_HTML_EXT = '.html';
/**
* TEXT mail format extension
* @type {String}
*/
Mail.DEFAULT_TEXT_EXT = '.txt';
/**
* _readMeta
* @private
* @return {[type]} [description]
*/
Mail.prototype._readMeta = function () {
var metaPath = path.resolve(this._dir, this._name + Mail.DEFAULT_META_EXT);
if (!fs.existsSync(metaPath)) {
throw new Error("Meta file not found: " + metaPath);
}
deepExtend(this, require(metaPath));
return this;
};
Mail.prototype.getName = function () {
return this._name;
};
Mail.prototype.getMailing = function () {
return this._mailing;
};
/**
* _readHTML
* @private
* @return {[type]} [description]
*/
Mail.prototype._readHTML = function () {
var htmlPath = path.resolve(this._dir, this._name + Mail.DEFAULT_HTML_EXT);
if (!fs.existsSync(htmlPath)) {
return this;
}
this.html = fs.readFileSync(htmlPath).toString('utf8');
return this;
};
Mail.prototype._mergeCssErr = function () {
throw new Error("Aww meeeeen... An error occured while inlining the CSS." +
"\nCheck that your HTML or TEXT version does not contain things like '<%' because Juice use JSDom underneath and it removes them." +
"\nCheck that your css is valid, if you think that is a bug, please report the issue to the Juice library.");
};
Mail.prototype._mergeCss = function () {
var stylesheets = this.styles
.map(function (style_path) {
return path.resolve(this._dir, style_path);
}.bind(this))
.filter(fs.existsSync.bind(fs))
.map(function (path) {
return fs.readFileSync(path).toString('utf8');
});
if (this.html && this.html.length > 0) {
var htmlWithInlinedCss = juice(this.html, {
extraCss: stylesheets.join('\n')
});
if (htmlWithInlinedCss.length === 0) {
this._mergeCssErr();
}
this.html = htmlWithInlinedCss;
}
if (this.text && this.text.length > 0) {
var textWithInlinedCss = juice(this.text, {
extraCss: stylesheets.join('\n')
});
if (textWithInlinedCss.length === 0) {
this._mergeCssErr();
}
this.text = textWithInlinedCss;
}
return this;
};
/**
* _readText
* @private
* @return {[type]} [description]
*/
Mail.prototype._readText = function () {
var textPath = path.resolve(this._dir, this._name + Mail.DEFAULT_TEXT_EXT);
if (!fs.existsSync(textPath)) {
return this;
}
this.text = fs.readFileSync(textPath).toString('utf8');
return this;
};
/**
* Compile the mail with the specified arguments
* @param {[type]} args [description]
* @return {[type]} [description]
* @private
*/
Mail.prototype._compileWith = function (args) {
var mail = _.clone(this);
// Html
if (this.html && !this.tplHTML) {
this.tplHTML = this.templateEngine.compile(this.html);
}
if (this.html) {
mail.html = this.templateEngine.exec(this.tplHTML, args);
}
// Text
if (this.text && !this.tplText) {
this.tplText = this.templateEngine.compile(this.text);
}
if (this.text) {
mail.text = this.templateEngine.exec(this.tplText, args);
}
// Append data
mail.data = args;
return mail;
};
/**
* Mail Factory
* @param {Object} templateEngine Template Engine that will be used to render the mail
* @param {String} metaPath Path to the mail meta file
* @return {Mail} A Mail object
*/
Mail.Factory = function (templateEngine, metaPath) {
return new Mail(templateEngine, metaPath)
._readMeta()
._readHTML()
._mergeCss()
._readText();
};
/**
* Export Mail
* @type {Function}
* @private
*/
module.exports = Mail;