The JMCNet library ported to JS : send email, manage html email template, use .properties files, resource bundle for i18n and add some usefull date methods

Usage no npm install needed!

<script type="module">
  import jmcnet from '';


JMCNet Logo"> JMCNet library !

JMCNet provides a JavaScript implementation of the JMCNet Java library (cf. JMCNet Java Library for more information). It provides utility libraries for :

  • jmcnet-date - date manipulation : adding days, weeks and month to date,
  • jmcnet-config - properties file management : automatic reload of .properties file on change, resources bundle for i18n features,
  • jmcnet-email - email management : add attachment, deals with image attachment, automatically create attachment from html text,
  • jmcnet-emailTemplate - templated email features : cooperate with email features above to send beautiful html templated emails,
  • jmcnet-exception - exception feature : the base exception used with all modules above,
  • jmcnet-resourceBundle - Localized resource bundle : dealing with localized resources bundle for i18n,
  • jmcnet-i18n - Internalization (i18n) format functions helper : format String, date, currency and float values considering a locale


  • Node.js - Download and Install Node.js. You can also follow this gist for a quick and easy way to install Node.js and npm

Tools Prerequisites

  • NPM - Node.js package manage; should be installed when you install node.js.

Optional Built with Gulp

  • Gulp - Download and Install Gulp.
$ npm install -g mocha
$ gulp testu

Additional Packages

  • none yet.


All JMCNet libs have Lodash and Log4js-node dependencies.

Quick Install

The quickest way to get started with JMCNet Library is to fork the Github repo.

$ [sudo] git fork git@github/jmcollin78/jmcnet.git
$ cd jmcnet
$ npm install
$ npm install -g mocha

We recommend using Grunt to start the test :

$ gulp testu

If grunt aborts because of JSHINT errors, these can be overridden with the force flag:

$ gulp -f testu

Alternatively, when not using grunt you can run:

$ npm test


During install some of you may encounter some issues.

Most issues can be solved by one of the following tips, but if are unable to find a solution feel free to contact us via the repository issue tracker or the links provided below.

Update NPM, Bower or Grunt

Sometimes you may find there is a weird error during install like npm's Error: ENOENT. Usually updating those tools to the latest version solves the issue.

  • Updating NPM:
$ npm update -g npm
  • Updating Mocha:
$ npm update -g mocha

Cleaning NPM

NPM has a caching system for holding packages that you already installed. We found that often cleaning the cache solves some troubles this system creates.

  • NPM Clean Cache:
$ npm cache clean

Getting Started with JMCNet library

Include JMCNet lib in the require sections :

var jmcnet = require('jmcnet');

JMCNet Library contains those modules :

Exception (jmcnet-exception)

A base module containing BaseException, FunctionalException and TechnicalException

throw new jmcnet.exception.TechnicalException('The error message', [arg1, arg2]);
throw new jmcnet.exception.FunctionalException('The functional error message', [arg1, arg2]);

Date manipulation (jmcnet-date)

A module containing date helpers functions like :

  • : gives the current date limited to minutes informations (skip seconds and millisec),
  • : gives the current date limited to date informations (skip hours, muinutes, seconds and millisec),
  •, nbDays) : gives back a date which is date in argument with days augmented by nbDays,
  •, nbWeeks) : gives back a date which is date in argument with weeks augmented by nbWeeks,
  •, nbMonths) : gives back a date which is date in argument with month augmented by nbMonths,
  •, nbYears) : gives back a date which is date in argument with year augmented by nbYears,

.properties files manipulations (jmcnet-config)

A module for dealing with configuration files in the .properties style (like in Java) with automatic reload of the properties on file changes.

  • jmcnet.config.loadConfig(path, options) : loads a set of configuration files. Path is the base directory of all configuration files. Options are the following :
   // the base file containing a reference to all subfile
   masterFileName: '',
   // when the master file or a subfile is changed, reloads all
   reloadOnChange: true,
   // period in second between two checks
   checkReloadTimeSec: 10                      
  • jmcnet.config.get(key) : get the value of a key
  • jmcnet.config.getKeys() : get all the properties keys
  • jmcnet.config.addListener(callback) : adds a listener to the configuration reloads. The callbacks are called upon a config reload
  • jmcnet.config.getFirst(key, defaultValue) : get the first properties value declared with the key
  • jmcnet.config.getLast(key, defaultValue) : get the last properties value declared with the key

Resource bundle for i18n .properties files (jmcnet-resourceBundle)

A module for dealing with resource bundle files in the .properties style. A resource bundle is a set of files having the same base name, a .properties file extension. Each file contains key/value set with different translations for a same key.

Examples of resource bundle files:

w1=Hello this is an English sentence
w2=${w1} and I will terminate it.

w1=Bonjour ceci est une phrase en Français
w2=${w1} et je la termine.
templatedString=The templated String with val1=<%= val1 %> and val2=<%= val2 %>.

w1=Bonjour ceci est une phrase en Français de France
w2=${w1} et je la termine.
  • jmcnet.resourceBundle.ResourceBundle(path, baseName, options) : creates a resource bundle (ie. the set of files for each translation). Path is the base directory of all .properties files. BaseName is the base name used for all files. See options below.
var rsc = new jmcnet.resourceBundle.ResourceBundle('./path/to/resources/', 'test1');        
  • jmcnet.resourceBundle.getLocaleFile(bundleBaseName, locale) : gets the previously loaded properties file for bundle with base name 'bundleBaseName' and for locale 'locale'. If no file is provided for locale 'locale' the most approching locale is returned. That is file returned for base name 'test1' and locale 'en_En' could be (in order) '' or' if the first one is not found,
  • jmcnet.resourceBundle.getLocaleString(file, key, context) : get a string from a locale file 'file'. The string is assumed to be a template string (in the form of ejs). Values from template string are replaced with 'context'. See example below,
  • jmcnetResourceBundle.getBundle(bundleBaseName) : retrieve the bundle named bundleBaseName
  • ResourceBundle.load([callback]) : load all resource bundle files. If callback is provided, load is done asynchronously and callback is a function that takes an error in argument.
  • ResourceBundle.getFiles() : get all the properties files loaded. jmcnet.resourceBundle.getFiles().fr gives the property file for locale 'fr',
  • ResourceBundle.setOptions(options) : set the reload options of the resource bundle. Available options are :
   // when one of the locale file is changed, reloads it
   reloadOnChange: true,
   // period in second between two checks
   checkReloadTimeSec: 10                      

Code example using the tests files above :

new jmcnetResourceBundle.ResourceBundle('./test/resources/', 'test1', {
   reloadOnChange: false // don't check for file change
// creates a new ResourceBundle will check for file change every minutes
new jmcnetResourceBundle.ResourceBundle('./test/resources/', 'test2');
// gets the French for France properties file with base name test1
var w2 = jmcnetResourceBundle.getLocaleFile('test1', 'fr_FR').get('w2');
expect(w2).to.equal('Bonjour ceci est une phrase en Français de France et je la termine.');
var w2 = jmcnetResourceBundle.getLocaleFile('test1', 'en_US').get('w2');
expect(w2).to.equal(Hello this is an English sentence and I will terminate it.');
var rsc = new jmcnetResourceBundle.ResourceBundle('./test/resources/', 'test2');
var localeFile = rsc.getLocaleFile('en_EN');
war w2 = localeFile.get('a.key', 'a default value');
    reloadOnChange: true,
    checkReloadTimeSec: 60 // check every minute if file has change and reloads the file

// Templating
var localFile = jmcnetResourceBundle.getLocaleFile('test1', 'fr');
var replacedValue = jmcnetResourceBundle.getLocaleString(
    { val1 : 'val1', val2 : 12});
expect(replacedValue).to.equal('The templated String with val1=val1 and val2=12.');

Email features (jmcnet-email)

A module to manage email and image attachments. You can use like this :

  • Create email
var Email =;
var email = new Email('', '', 'My subject string', 'My text string', '<html>My html string</html>');
  • Create a fake transport (useful for testing)
var fkTp =;
email.sendEmail(function () {
    var sentEmail = fkTp.sentEmails[0];
    // reseting the sent mails
  • or create a real smtp transport
var smtpServer = '';
var port = 465;
var login = 'xxxx';
var pwd = 'xxxx';
var from = 'xxxx';
var to = 'xxxx';, port, login, pwd, 60000); // 60 sec timeout
var email = new Email(from, to, 'Test email fron JmcNetEmail lib', 'My text string', '<html>My html string</html>');
email.sendEmail(function (err, info) {
    log.trace('Send real Email on a real smtp server return. Err="%s", info="%s"', err, util.inspect(info));
    if (err) { // manage error
  • Adding attachment
email.addAttachment('image.png', 'http://url/to/images.png');
  • Replace all image in html with an attachment and corresponding cid:
email = new Email('', '',
       'My subject string',
       'My text string',
       '<html>An image: <img src="./images/test.png"></img></html>');
// This last command parse the html, replace all <img src=> with the corresponding cid: instruction

Email templating features (jmcnet-emailTemplate)

This module provides very easy features to send beautiful html email based on template.

  • Creates a template from Strings
var EmailTemplate = jmcnet.emailTemplate.EmailTemplate;
var template = new EmailTemplate(
       'The subject of the mail with <%= user.lastname %>',
       '<html>The email templated body <%= user.firstname %></html>');

  • Loads a template from a file
var template = jmcnet.emailTemplate.loadEmailTemplateFromFile(
       'subject <%= title %>',
  • Retrieve a previously loaded template
jmcnet.emailTemplate.getLstTemplates(); // list all templates
var template = jmcnet.emailTemplate.getEmailTemplate('templateName');
  • Reset all loaded templates
  • Sends a templated email
email = new Email(from, to);, port, login, pwd, 60000);
template = jmcnet.emailTemplate.loadEmailTemplateFromFile('realTemplate ', '[\u2601 Testu] Création d\'un compte', 'test/emailTemplates/realTemplate.html');
var context={
           mail_commons_header : 'Vous recevez cet e-mail ...',
           headerH1 : 'Création d\'un compte',
           account : {
               email : '',
               pseudo : 'The test man'
           password : 'hyXPyDKx',
           urlAccountApp : ''
var lang='fr';
// Does a 2 pass rendering
template.sendEmail2Pass(email, context, lang, function (err, info) {


// Does a single pass rendering
template.sendEmail(email, context, lang, function (err, info) {
  • Format date String
tpl = new jmcnetEmailTemplate.EmailTemplate('template1', 'The date is <%= date.toLocaleDateString(lang) %>', '...');
subject = tpl.renderSubject({
           date: d,
           body: 'This is the body of the mail'
}, 'fr');
expect(subject).to.equal('The date is 31/08/2014');


subject = tpl.renderSubject({
           date: d,
           body: 'This is the body of the mail',
           lang : 'fr'
expect(subject).to.equal('The date is 31/08/2014');

Internationalization (i18n) features (jmcnet-i18n)

This module provides very easy features to internationalize your template.

  • Set locale
var i18n = jmcnet.jmcnetI18n;

  • Set currency symbol
var i18n = jmcnet.jmcnetI18n;

  • Extract locale from an Http request
var i18n = jmcnet.jmcnetI18n;
i18n.getLocaleFromRequest(req); // req.headers.accept-language = 'fr ...'

  • Format a currency value in cents
var i18n = jmcnet.jmcnetI18n;
expect(jmcnetI18n.formatCurrency(123456, false, false)).to.equal('1.234,56&nbsp;€');
expect(jmcnetI18n.formatCurrency(123456, false, true)).to.equal('1234,56&nbsp;€');
expect(jmcnetI18n.formatCurrency(123456, true, false)).to.equal('1.234,56');
expect(jmcnetI18n.formatCurrency(123456, true, true)).to.equal('1234,56');
expect(jmcnetI18n.formatCurrency(123400, true, false)).to.equal('1.234,00');
expect(jmcnetI18n.formatCurrency(123400, true, true)).to.equal('1234,00');
expect(jmcnetI18n.formatCurrency(1234, false)).to.equal('12,34&nbsp;€');
expect(jmcnetI18n.formatCurrency(1200, true)).to.equal('12,00');

  • Format a float value in cents
var i18n = jmcnet.jmcnetI18n;
expect(jmcnetI18n.formatFloatCent(123456, false)).to.equal('1.234,56');
expect(jmcnetI18n.formatFloatCent(123456, true)).to.equal('1.234,56');
expect(jmcnetI18n.formatFloatCent(123400, false)).to.equal('1.234');
expect(jmcnetI18n.formatFloatCent(123400, true)).to.equal('1.234,00');
expect(jmcnetI18n.formatFloatCent(1234, false)).to.equal('12,34');

  • Format a percent value in cents
var i18n = jmcnet.jmcnetI18n;
expect(jmcnetI18n.formatPercent(1234, false)).to.equal('12,34 %');
expect(jmcnetI18n.formatPercent(1234, true)).to.equal('12,34 %');
expect(jmcnetI18n.formatPercent(1200, false)).to.equal('12 %');
expect(jmcnetI18n.formatPercent(1200, true)).to.equal('12,00 %');

  • Format a date
var i18n = jmcnet.jmcnetI18n;
var d = new Date(Date.parse('2015-04-11'));

Release notes

  • 1.2.9 : add jmcnetResourceBundle.getLocaleString to get a template String replaced with context
  • 1.2.8 : fix some log verbosity
  • 1.3.0 : update dependencies version and migrate to EJS V2
  • 1.3.1 - 1.3.3 : add HtmlTemplate class as base class for EmailTemplate
  • 1.4.0 - 1.4.2 : add i18n format functions
  • 1.4.3 : add jmcnetConfig.getFirst and jmcnetConfig.getLast in case of multivalued properties
  • 1.4.4 : update dependencies
  • 1.4.5 - 1.4.6 : update java-properties from @mattdsteele and nodemailer in 1.8.0
  • 1.4.7 - 1.4.8 : update java-properties and update dependencies
  • 1.4.9 : add flat format for currency numbers in i18n
  • 1.5.0 : add getLastMonday to get the last monday of a date
  • 1.6.0 : add internationalization for date.format()

More Information


This module is distributed under the MIT License.