[
  {
    "path": "Changelog",
    "content": "node_mailer changelog:\n\n0.6.4\n- Don't sent plaintext body for templates, only send html, this should help w/ some confusion of email clients that are getting confused\n\n0.6.3\n- Fix for logging\n\n0.6.2\n- Fix for template logic\n- Templates now default to html emails\n\n0.6.1\n- All Nodemailer arguments should now be merged in\n\n0.6.0 [Breaking]\n- Plaintext username/password\n\n0.5.0\n- NodeMailer as backing SmtpClient\n"
  },
  {
    "path": "MIT-LICENSE",
    "content": "Copyright (c) 2009 Marak Squires - http://github.com/marak/node_mailer\n \nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n \nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n \nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "Readme.md",
    "content": "# Project deprecated in favor of <a href=\"https://github.com/andris9/Nodemailer\">nodemailer</a>\n\nWe merged the code-bases over a year ago, and it's time to get rid of this project."
  },
  {
    "path": "demo-template-html.js",
    "content": "var email = require(\"./lib/node_mailer\");\n\nfor(var i = 0; i < 10; i++){\n\n  email.send({\n    host : \"localhost\",               // smtp server hostname\n    port : \"25\",                     // smtp server port\n    domain : \"localhost\",             // domain used by client to identify itself to server\n    to : \"marak.squires@gmail.com\",\n    from : \"obama@whitehouse.gov\",\n    subject : \"node_mailer test email\",\n    template : \"./templates/sample-html.txt\",   // path to template name\n    data : {\n      \"username\": \"Billy Bob\",\n      \"color\": function(){\n        var arr = [\"purple\", \"red\", \"green\", \"yello\"];\n        return arr[Math.floor(Math.random()*3)];\n      },\n      \"animal\": \"monkey\",\n      \"adverb\": \"quickly\",\n      \"noun\": \"hot lava\"\n    },\n\n    authentication : \"login\",        // auth login is supported; anything else is no auth\n    username : undefined,            // username\n    password : undefined,            // password\n    debug: true                      // log level per message\n  },\n  function(err, result){\n    if(err){ console.log(err); }\n  });\n}\n"
  },
  {
    "path": "demo-template.js",
    "content": "var email = require(\"./lib/node_mailer\");\n\nfor(var i = 0; i < 10; i++){\n\n  email.send({\n    host : \"localhost\",               // smtp server hostname\n    port : \"25\",                     // smtp server port\n    domain : \"localhost\",             // domain used by client to identify itself to server\n    to : \"marak.squires@gmail.com\",\n    from : \"obama@whitehouse.gov\",\n    subject : \"node_mailer test email\",\n    template : \"./templates/sample.txt\",   // path to template name\n    data : {\n      \"username\": \"Billy Bob\",\n      \"color\": function(){\n        var arr = [\"purple\", \"red\", \"green\", \"yello\"];\n        return arr[Math.floor(Math.random()*3)];\n      },\n      \"animal\": \"monkey\",\n      \"adverb\": \"quickly\",\n      \"noun\": \"hot lava\"\n    },\n\n    authentication : \"login\",        // auth login is supported; anything else is no auth\n    username : undefined,            // username\n    password : undefined,            // password\n    debug: true                      // log level per message\n  },\n  function(err, result){\n    if(err){ console.log(err); }\n  });\n}\n"
  },
  {
    "path": "demo.js",
    "content": "var email = require(\"./lib/node_mailer\");\n\nfor(var i = 0; i < 1; i++){\n  email.send({\n    ssl: true,\n    host : \"smtp.gmail.com\",              // smtp server hostname\n    port : 465,                     // smtp server port\n    domain : \"[127.0.0.1]\",            // domain used by client to identify itself to server\n    to : \"bradley.meck@gmail.com\",\n    from : \"bradley.meck@gmail.com\",\n    subject : \"node_mailer test email\",\n    reply_to:\"bradley@bradleymeck.com\",\n    body: \"Hello! This is a test of the node_mailer.\",\n    authentication : \"login\",        // auth login is supported; anything else is no auth\n    username : undefined,            // username\n    password : undefined,            // password\n    debug: true                      // log level per message\n  },\n  function(err, result){\n    if(err){ console.log(err); }\n  });\n}\n"
  },
  {
    "path": "lib/node_mailer.js",
    "content": "/* Copyright (c) 2009-2010 Marak Squires, Elijah Insua, Fedor Indutny - http://github.com/marak/node_mailer\n \nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n \nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n \nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n*/\n\nvar SMTPClient = require(\"nodemailer\").SMTPClient;\nvar EmailMessage = require(\"nodemailer\").EmailMessage;\nvar fs = require('fs');\nvar mustache = require('../vendor/mustache');\nvar _templateCache = {};\n\nfunction SMTPClientPool() {\n  this.servers = {};\n}\nSMTPClientPool.prototype.addClient = function(port,host,options) {\n  if(this.servers[host] && this.servers[host][options.user]) return;\n  var hostClients = this.servers[host] || (this.servers[host] = {});\n  var pool = this;\n  var client = hostClients[options.user] = new SMTPClient(host,port,options);\n  client.on(\"close\",function() {\n    if(client == hostClients[options.user]) {\n      //only because this could be crazy long lived and dynamic\n      delete hostClients[options.user];\n      if(Object.keys(hostClients).length == 0) {\n\tdelete pool.servers[host]\n      }\n    }\n  })\n  client.on(\"empty\",function(){\n\tdelete hostClients[options.user];\n\tclient.close();})\n}\nSMTPClientPool.prototype.send = function send(message, callback) {\n  var hostpool = this.servers[message.SERVER.host]\n  if(!hostpool) hostpool = {};\n  var client = hostpool[message.SERVER.user]\n  if(!client) {\n    client = hostpool[message.SERVER.user] = new SMTPClient(message.SERVER.host,message.SERVER.port,message.SERVER);\n    client.on(\"close\",function() {\n      if(client == hostClients[options.user]) {\n          //only because this could be crazy long lived and dynamic\n          delete hostClients[options.user];\n          if(Object.keys(hostClients).length == 0) {\n       delete pool.servers[host]\n          }\n        }\n    })\n    client.on(\"empty\",function(){\n     delete hostClients[options.user];\n     client.close();})\n  }\n  client.sendMail(message,callback);\n  client.on('error', callback);\n}\n\nfunction merge(x,y) {\n  var z = {};\n  for(var k in x) {\n    z[k] = x[k];\n  }\n  for(var k in y) {\n    z[k] = y[k];\n  }\n  return z;\n}\n\nvar pool = new SMTPClientPool();\n\nexports.send = function node_mail(message, callback) {\n  var server = {\n    host: message.host,\n    hostname: message.domain,\n    port: + message.port,\n    use_authentication: message.authentication,\n    ssl: message.ssl,\n    user: message.username && message.username.toString(),\n    pass: message.password && message.password.toString(),\n    debug: message.debug || false\n  };\n  if(message.username || message.password) {\n    pool.addClient(server.port, server.host, server);\n  }\n\n  function dispatchMail(message, server, callback) {\n      var _message = {\n          to: message.to,\n          sender: message.from,\n          subject: message.subject,\n          server: server,\n          debug: message.debug\n      };\n      if(message.html)_message.html = message.html;\n      pool.send(new EmailMessage(merge(message, _message)), callback);\n  }\n\n  // If a template was passed in as part of the message\n  if (message.template) {\n    // If the template path is in the cache\n    if (_templateCache[message.template]) {\n      // If the template is already fully loaded in the cahe\n      if (_templateCache[message.template].loaded) {\n        // Use the cached template and send the email\n        message.html = mustache.to_html(_templateCache[message.template].template, message.data);\n        dispatchMail(message, server, callback);\n      }\n      else {\n        // We've started to load the template, but it's not loaded yet. queue up this message to be sent later\n        _templateCache[message.template].queue.push(message);\n      }\n    }\n    else {\n      // The template path wasn't found in the cache, start to load the template\n      _templateCache[message.template]          = {};\n      _templateCache[message.template].loaded   = false;\n      _templateCache[message.template].template = '';\n      _templateCache[message.template].queue    = [];\n\n      fs.readFile(message.template, function(err, result){\n        if (err) {\n          callback(err);\n          return;\n        }\n\n        _templateCache[message.template].template = result.toString();\n        _templateCache[message.template].loaded   = true;\n\n        // \"Drain\" the queue\n        _templateCache[message.template].queue.push(message);\n        _templateCache[message.template].queue.forEach(function(msg, i){\n          msg.html = mustache.to_html(_templateCache[message.template].template, msg.data);\n          dispatchMail(msg, server, callback);\n        });\n\n        // Clear the queue out\n        _templateCache[message.template].queue = [];\n      });\n    }\n  }\n  else { // No template being used\n    dispatchMail(message, server, callback);\n  }\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"mailer\",\n  \"description\": \"send emails from node.js to a smtp server, simple as cake\",\n  \"version\": \"0.6.7\",\n  \"author\": \"Marak Squires\",\n  \"contributors\" : [\n    \"Elijah Insua <tmpvar@gmail.com> (http://tmvpar.com/)\",\n    \"Fedor Indutny <fedor.indutny@gmail.com> (http://indutny.com/)\",\n    \"Bradley Meck <bradley.meck@gmail.com> (http://bradleymeck.com)\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://github.com/Marak/node_mailer.git\"\n  },\n  \"dependencies\": {\n    \"nodemailer\": \"0.1.20\",\n    \"colors\": \">= 0.3.0\"\n  },\n  \"engine\": [ \"node >=0.3.0\" ],\n  \"main\": \"lib/node_mailer\"\n}\n"
  },
  {
    "path": "stubSMTP",
    "content": "#!/usr/bin/env bash\nif [ -z $1 ]\nthen port=1025\nelse port=$1\nfi\n\necho \"Starting dumb mail server on localhost:$port\"\npython -m smtpd -n -c DebuggingServer localhost:$port"
  },
  {
    "path": "templates/sample-html.txt",
    "content": "<div>Hello {{username}}, </div>\n<br/>\n<div>This is a sample template of the node mailer.</div>\n<br/>\n<div>It uses mustache templating to do basic search and replaces. </div>\n<br/>\n<div>The {{color}} {{animal}} {{adverb}} ran over the {{noun}}.</div>"
  },
  {
    "path": "templates/sample.txt",
    "content": "Hello {{username}}, \n\nThis is a sample template of the node mailer.\n\nIt uses mustache templating to do basic search and replaces. \n\nThe {{color}} {{animal}} {{adverb}} ran over the {{noun}}."
  },
  {
    "path": "vendor/mustache.js",
    "content": "/*\n * CommonJS-compatible mustache.js module\n *\n * See http://github.com/janl/mustache.js for more info.\n */\n\n/*\n  mustache.js — Logic-less templates in JavaScript\n\n  See http://mustache.github.com/ for more info.\n*/\n\nvar Mustache = function() {\n  var Renderer = function() {};\n\n  Renderer.prototype = {\n    otag: \"{{\",\n    ctag: \"}}\",\n    pragmas: {},\n    buffer: [],\n    pragmas_implemented: {\n      \"IMPLICIT-ITERATOR\": true\n    },\n    context: {},\n\n    render: function(template, context, partials, in_recursion) {\n      // reset buffer & set context\n      if(!in_recursion) {\n        this.context = context;\n        this.buffer = []; // TODO: make this non-lazy\n      }\n\n      // fail fast\n      if(!this.includes(\"\", template)) {\n        if(in_recursion) {\n          return template;\n        } else {\n          this.send(template);\n          return;\n        }\n      }\n\n      template = this.render_pragmas(template);\n      var html = this.render_section(template, context, partials);\n      if(in_recursion) {\n        return this.render_tags(html, context, partials, in_recursion);\n      }\n\n      this.render_tags(html, context, partials, in_recursion);\n    },\n\n    /*\n      Sends parsed lines\n    */\n    send: function(line) {\n      if(line != \"\") {\n        this.buffer.push(line);\n      }\n    },\n\n    /*\n      Looks for %PRAGMAS\n    */\n    render_pragmas: function(template) {\n      // no pragmas\n      if(!this.includes(\"%\", template)) {\n        return template;\n      }\n\n      var that = this;\n      var regex = new RegExp(this.otag + \"%([\\\\w-]+) ?([\\\\w]+=[\\\\w]+)?\" +\n            this.ctag);\n      return template.replace(regex, function(match, pragma, options) {\n        if(!that.pragmas_implemented[pragma]) {\n          throw({message: \n            \"This implementation of mustache doesn't understand the '\" +\n            pragma + \"' pragma\"});\n        }\n        that.pragmas[pragma] = {};\n        if(options) {\n          var opts = options.split(\"=\");\n          that.pragmas[pragma][opts[0]] = opts[1];\n        }\n        return \"\";\n        // ignore unknown pragmas silently\n      });\n    },\n\n    /*\n      Tries to find a partial in the curent scope and render it\n    */\n    render_partial: function(name, context, partials) {\n      name = this.trim(name);\n      if(!partials || partials[name] === undefined) {\n        throw({message: \"unknown_partial '\" + name + \"'\"});\n      }\n      if(typeof(context[name]) != \"object\") {\n        return this.render(partials[name], context, partials, true);\n      }\n      return this.render(partials[name], context[name], partials, true);\n    },\n\n    /*\n      Renders inverted (^) and normal (#) sections\n    */\n    render_section: function(template, context, partials) {\n      if(!this.includes(\"#\", template) && !this.includes(\"^\", template)) {\n        return template;\n      }\n\n      var that = this;\n      // CSW - Added \"+?\" so it finds the tighest bound, not the widest\n      var regex = new RegExp(this.otag + \"(\\\\^|\\\\#)\\\\s*(.+)\\\\s*\" + this.ctag +\n              \"\\n*([\\\\s\\\\S]+?)\" + this.otag + \"\\\\/\\\\s*\\\\2\\\\s*\" + this.ctag +\n              \"\\\\s*\", \"mg\");\n\n      // for each {{#foo}}{{/foo}} section do...\n      return template.replace(regex, function(match, type, name, content) {\n        var value = that.find(name, context);\n        if(type == \"^\") { // inverted section\n          if(!value || that.is_array(value) && value.length === 0) {\n            // false or empty list, render it\n            return that.render(content, context, partials, true);\n          } else {\n            return \"\";\n          }\n        } else if(type == \"#\") { // normal section\n          if(that.is_array(value)) { // Enumerable, Let's loop!\n            return that.map(value, function(row) {\n              return that.render(content, that.create_context(row),\n                partials, true);\n            }).join(\"\");\n          } else if(that.is_object(value)) { // Object, Use it as subcontext!\n            return that.render(content, that.create_context(value),\n              partials, true);\n          } else if(typeof value === \"function\") {\n            // higher order section\n            return value.call(context, content, function(text) {\n              return that.render(text, context, partials, true);\n            });\n          } else if(value) { // boolean section\n            return that.render(content, context, partials, true);\n          } else {\n            return \"\";\n          }\n        }\n      });\n    },\n\n    /*\n      Replace {{foo}} and friends with values from our view\n    */\n    render_tags: function(template, context, partials, in_recursion) {\n      // tit for tat\n      var that = this;\n\n      var new_regex = function() {\n        return new RegExp(that.otag + \"(=|!|>|\\\\{|%)?([^\\\\/#\\\\^]+?)\\\\1?\" +\n          that.ctag + \"+\", \"g\");\n      };\n\n      var regex = new_regex();\n      var tag_replace_callback = function(match, operator, name) {\n        switch(operator) {\n        case \"!\": // ignore comments\n          return \"\";\n        case \"=\": // set new delimiters, rebuild the replace regexp\n          that.set_delimiters(name);\n          regex = new_regex();\n          return \"\";\n        case \">\": // render partial\n          return that.render_partial(name, context, partials);\n        case \"{\": // the triple mustache is unescaped\n          return that.find(name, context);\n        default: // escape the value\n          return that.escape(that.find(name, context));\n        }\n      };\n      var lines = template.split(\"\\n\");\n      for(var i = 0; i < lines.length; i++) {\n        lines[i] = lines[i].replace(regex, tag_replace_callback, this);\n        if(!in_recursion) {\n          this.send(lines[i]);\n        }\n      }\n\n      if(in_recursion) {\n        return lines.join(\"\\n\");\n      }\n    },\n\n    set_delimiters: function(delimiters) {\n      var dels = delimiters.split(\" \");\n      this.otag = this.escape_regex(dels[0]);\n      this.ctag = this.escape_regex(dels[1]);\n    },\n\n    escape_regex: function(text) {\n      // thank you Simon Willison\n      if(!arguments.callee.sRE) {\n        var specials = [\n          '/', '.', '*', '+', '?', '|',\n          '(', ')', '[', ']', '{', '}', '\\\\'\n        ];\n        arguments.callee.sRE = new RegExp(\n          '(\\\\' + specials.join('|\\\\') + ')', 'g'\n        );\n      }\n      return text.replace(arguments.callee.sRE, '\\\\$1');\n    },\n\n    /*\n      find `name` in current `context`. That is find me a value\n      from the view object\n    */\n    find: function(name, context) {\n      name = this.trim(name);\n\n      // Checks whether a value is thruthy or false or 0\n      function is_kinda_truthy(bool) {\n        return bool === false || bool === 0 || bool;\n      }\n\n      var value;\n      if(is_kinda_truthy(context[name])) {\n        value = context[name];\n      } else if(is_kinda_truthy(this.context[name])) {\n        value = this.context[name];\n      }\n\n      if(typeof value === \"function\") {\n        return value.apply(context);\n      }\n      if(value !== undefined) {\n        return value;\n      }\n      // silently ignore unkown variables\n      return \"\";\n    },\n\n    // Utility methods\n\n    /* includes tag */\n    includes: function(needle, haystack) {\n      return haystack.indexOf(this.otag + needle) != -1;\n    },\n\n    /*\n      Does away with nasty characters\n    */\n    escape: function(s) {\n      s = String(s === null ? \"\" : s);\n      return s.replace(/&(?!\\w+;)|[\"<>\\\\]/g, function(s) {\n        switch(s) {\n        case \"&\": return \"&amp;\";\n        case \"\\\\\": return \"\\\\\\\\\";\n        case '\"': return '\\\"';\n        case \"<\": return \"&lt;\";\n        case \">\": return \"&gt;\";\n        default: return s;\n        }\n      });\n    },\n\n    // by @langalex, support for arrays of strings\n    create_context: function(_context) {\n      if(this.is_object(_context)) {\n        return _context;\n      } else {\n        var iterator = \".\";\n        if(this.pragmas[\"IMPLICIT-ITERATOR\"]) {\n          iterator = this.pragmas[\"IMPLICIT-ITERATOR\"].iterator;\n        }\n        var ctx = {};\n        ctx[iterator] = _context;\n        return ctx;\n      }\n    },\n\n    is_object: function(a) {\n      return a && typeof a == \"object\";\n    },\n\n    is_array: function(a) {\n      return Object.prototype.toString.call(a) === '[object Array]';\n    },\n\n    /*\n      Gets rid of leading and trailing whitespace\n    */\n    trim: function(s) {\n      return s.replace(/^\\s*|\\s*$/g, \"\");\n    },\n\n    /*\n      Why, why, why? Because IE. Cry, cry cry.\n    */\n    map: function(array, fn) {\n      if (typeof array.map == \"function\") {\n        return array.map(fn);\n      } else {\n        var r = [];\n        var l = array.length;\n        for(var i = 0; i < l; i++) {\n          r.push(fn(array[i]));\n        }\n        return r;\n      }\n    }\n  };\n\n  return({\n    name: \"mustache.js\",\n    version: \"0.3.1-dev\",\n\n    /*\n      Turns a template and view into HTML\n    */\n    to_html: function(template, view, partials, send_fun) {\n      var renderer = new Renderer();\n      if(send_fun) {\n        renderer.send = send_fun;\n      }\n      renderer.render(template, view, partials);\n      if(!send_fun) {\n        return renderer.buffer.join(\"\\n\");\n      }\n    }\n  });\n}();\n\nexports.name = Mustache.name;\nexports.version = Mustache.version;\n\nexports.to_html = function() {\n  return Mustache.to_html.apply(this, arguments);\n};\n"
  }
]