diff --git a/docs/api.md b/docs/api.md
index f7d16ece..324693f2 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -1164,6 +1164,22 @@ POST /users/logout
Require a user to verify their email address before being able to login. This will send an email to the user containing a link to verify their address. Once the user follows the link they will be redirected to `/` and be able to login normally.
```js
+// first setup the mail datasource (see #mail-model for more info)
+var mail = loopback.createDataSource({
+ connector: loopback.Mail,
+ transports: [{
+ type: 'smtp',
+ host: 'smtp.gmail.com',
+ secureConnection: true,
+ port: 465,
+ auth: {
+ user: 'you@gmail.com',
+ pass: 'your-password'
+ }
+ }]
+});
+
+User.email.attachTo(mail);
User.requireEmailVerfication = true;
User.afterRemote('create', function(ctx, user, next) {
var options = {
@@ -1231,6 +1247,43 @@ MySession.attachTo(loopback.memory());
Send emails from your loopback app.
+```js
+// extend a one-off model for sending email
+var MyEmail = loopback.Email.extend('my-email');
+
+// create a mail data source
+var mail = loopback.createDataSource({
+ connector: loopback.Mail,
+ transports: [{
+ type: 'smtp',
+ host: 'smtp.gmail.com',
+ secureConnection: true,
+ port: 465,
+ auth: {
+ user: 'you@gmail.com',
+ pass: 'your-password'
+ }
+ }]
+});
+
+// attach the model
+MyEmail.attachTo(mail);
+
+// send an email
+MyEmail.send({
+ to: 'foo@bar.com',
+ from: 'you@gmail.com',
+ subject: 'my subject',
+ text: 'my text',
+ html: 'my html'
+}, function(err, mail) {
+ console.log('email sent!');
+});
+```
+
+> NOTE: the mail connector uses [nodemailer](http://www.nodemailer.com/). See
+> the [nodemailer docs](http://www.nodemailer.com/) for more info.
+
### REST Router
Expose models over rest using the `loopback.rest` router.
diff --git a/index.js b/index.js
index 5db6b786..737666bd 100644
--- a/index.js
+++ b/index.js
@@ -10,9 +10,10 @@ var loopback = module.exports = require('./lib/loopback');
loopback.Connector = require('./lib/connectors/base-connector');
loopback.Memory = require('./lib/connectors/memory');
+loopback.Mail = require('./lib/connectors/mail');
/**
* Types
*/
-loopback.GeoPoint = require('loopback-datasource-juggler/lib/geo').GeoPoint;
\ No newline at end of file
+loopback.GeoPoint = require('loopback-datasource-juggler/lib/geo').GeoPoint;
diff --git a/lib/connectors/mail.js b/lib/connectors/mail.js
new file mode 100644
index 00000000..682f9470
--- /dev/null
+++ b/lib/connectors/mail.js
@@ -0,0 +1,121 @@
+/**
+ * Dependencies.
+ */
+
+var mailer = require('nodemailer')
+ , assert = require('assert');
+
+/**
+ * Export the MailConnector class.
+ */
+
+module.exports = MailConnector;
+
+/**
+ * Create an instance of the connector with the given `settings`.
+ */
+
+function MailConnector(settings) {
+ assert(typeof settings === 'object', 'cannot initiaze MailConnector without a settings object');
+ var transports = settings.transports || [];
+
+ transports.forEach(this.setupTransport.bind(this));
+}
+
+MailConnector.initialize = function(dataSource, callback) {
+ dataSource.connector = new MailConnector(dataSource.settings);
+ callback();
+}
+
+MailConnector.prototype.DataAccessObject = Mailer;
+
+
+/**
+ * Add a transport to the available transports. See https://github.com/andris9/Nodemailer#setting-up-a-transport-method.
+ *
+ * Example:
+ *
+ * Email.setupTransport({
+ * type: 'SMTP',
+ * host: "smtp.gmail.com", // hostname
+ * secureConnection: true, // use SSL
+ * port: 465, // port for secure SMTP
+ * auth: {
+ * user: "gmail.user@gmail.com",
+ * pass: "userpass"
+ * }
+ * });
+ *
+ */
+
+MailConnector.prototype.setupTransport = function(setting) {
+ var connector = this;
+ connector.transports = connector.transports || [];
+ connector.transportsIndex = connector.transportsIndex || {};
+ var transport = mailer.createTransport(setting.type, setting);
+ connector.transportsIndex[setting.type] = transport;
+ connector.transports.push(transport);
+}
+
+function Mailer() {
+
+}
+
+/**
+ * Send an email with the given `options`.
+ *
+ * Example Options:
+ *
+ * {
+ * from: "Fred Foo ✔ ", // sender address
+ * to: "bar@blurdybloop.com, baz@blurdybloop.com", // list of receivers
+ * subject: "Hello ✔", // Subject line
+ * text: "Hello world ✔", // plaintext body
+ * html: "Hello world ✔" // html body
+ * }
+ *
+ * See https://github.com/andris9/Nodemailer for other supported options.
+ *
+ * @param {Object} options
+ * @param {Function} callback Called after the e-mail is sent or the sending failed
+ */
+
+Mailer.send = function (options, fn) {
+ var dataSource = this.dataSource;
+ var settings = dataSource && dataSource.settings;
+ var connector = dataSource.connector;
+ var transportsIndex = connector.transportsIndex;
+ var transport = transportsIndex[options.transport || 'SMTP'] || connector.transports[0];
+ assert(transport, 'You must supply an Email.settings.transports array containing at least one transport');
+
+ if(settings && settings.debug) {
+ console.log('Sending Mail:');
+ if(options.transport) {
+ console.log('\t TRANSPORT:', options.transport);
+ }
+ console.log('\t TO:', options.to);
+ console.log('\t FROM:', options.from);
+ console.log('\t SUBJECT:', options.subject);
+ console.log('\t TEXT:', options.text);
+ console.log('\t HTML:', options.html);
+ }
+
+ transport.sendMail(options, fn);
+}
+
+/**
+ * Send an email instance using `modelInstance.send()`.
+ */
+
+Mailer.prototype.send = function (fn) {
+ this.constructor.send(this, fn);
+}
+
+/**
+ * Access the node mailer object.
+ */
+
+MailConnector.mailer =
+MailConnector.prototype.mailer =
+Mailer.mailer =
+Mailer.prototype.mailer = mailer;
diff --git a/lib/models/email.js b/lib/models/email.js
index 9bb3a79c..d2c33bc2 100644
--- a/lib/models/email.js
+++ b/lib/models/email.js
@@ -3,9 +3,7 @@
*/
var Model = require('../loopback').Model
- , loopback = require('../loopback')
- , mailer = require('nodemailer')
- , assert = require('assert');
+ , loopback = require('../loopback');
/**
* Default Email properties.
@@ -24,87 +22,3 @@ var properties = {
*/
var Email = module.exports = Model.extend('email', properties);
-
-/*!
- * Setup the Email class after extension.
- */
-
-Email.setup = function (settings) {
- settings = settings || this.settings;
- var transports = settings.transports || [];
-
- transports.forEach(this.setupTransport.bind(this));
-}
-
-/**
- * Add a transport to the available transports. See https://github.com/andris9/Nodemailer#setting-up-a-transport-method.
- *
- * Example:
- *
- * Email.setupTransport({
- * type: 'SMTP',
- * host: "smtp.gmail.com", // hostname
- * secureConnection: true, // use SSL
- * port: 465, // port for secure SMTP
- * auth: {
- * user: "gmail.user@gmail.com",
- * pass: "userpass"
- * }
- * });
- *
- */
-
-Email.setupTransport = function (setting) {
- var Email = this;
- Email.transports = Email.transports || [];
- Email.transportsIndex = Email.transportsIndex || {};
- var transport = mailer.createTransport(setting.type, setting);
- Email.transportsIndex[setting.type] = transport;
- Email.transports.push(transport);
-}
-
-/**
- * Send an email with the given `options`.
- *
- * Example Options:
- *
- * {
- * from: "Fred Foo ✔ ", // sender address
- * to: "bar@blurdybloop.com, baz@blurdybloop.com", // list of receivers
- * subject: "Hello ✔", // Subject line
- * text: "Hello world ✔", // plaintext body
- * html: "Hello world ✔" // html body
- * }
- *
- * See https://github.com/andris9/Nodemailer for other supported options.
- *
- * @param {Object} options
- * @param {Function} callback Called after the e-mail is sent or the sending failed
- */
-
-Email.send = function (options, fn) {
- var transport = this.transportsIndex[options.transport || 'SMTP'] || this.transports[0];
- assert(transport, 'You must supply an Email.settings.transports array containing at least one transport');
-
- transport.sendMail(options, fn);
-}
-
-/**
- * Access the node mailer object.
- *
- * Email.mailer
- * // or
- * var email = new Email({to: 'foo@bar.com', from: 'bar@bat.com'});
- * email.mailer
- */
-
-Email.mailer =
-Email.prototype.mailer = mailer;
-
-/**
- * Send an email instance using `Email.send()`.
- */
-
-Email.prototype.send = function (fn) {
- this.constructor.send(this, fn);
-}
diff --git a/test/email.test.js b/test/email.test.js
new file mode 100644
index 00000000..36727dca
--- /dev/null
+++ b/test/email.test.js
@@ -0,0 +1,56 @@
+var loopback = require('../');
+var MailConnector = loopback.Mail;
+var MyEmail = loopback.Email.extend('my-email');
+var assert = require('assert');
+
+describe('Email and SMTP', function () {
+ var mail = loopback.createDataSource({
+ connector: MailConnector,
+ transports: [
+ {type: 'STUB'}
+ ]
+ });
+
+ MyEmail.attachTo(mail);
+
+ it('should have a send method', function () {
+ assert(typeof MyEmail.send === 'function');
+ assert(typeof MyEmail.prototype.send === 'function');
+ });
+
+ describe('MyEmail', function () {
+ it('MyEmail.send(options, callback)', function (done) {
+ var options = {
+ to: 'to@to.com',
+ from: 'from@from.com',
+ subject: 'subject',
+ text: 'text',
+ html: 'html
'
+ };
+
+ MyEmail.send(options, function(err, mail) {
+ assert(mail.message);
+ assert(mail.envelope);
+ assert(mail.messageId);
+ done(err);
+ });
+ });
+
+ it('myEmail.send(callback)', function (done) {
+ var message = new MyEmail({
+ to: 'to@to.com',
+ from: 'from@from.com',
+ subject: 'subject',
+ text: 'text',
+ html: 'html
'
+ });
+
+ message.send(function (err, mail) {
+ assert(mail.message);
+ assert(mail.envelope);
+ assert(mail.messageId);
+ done(err);
+ });
+ });
+ });
+});
diff --git a/test/user.test.js b/test/user.test.js
index 51857050..e664c73a 100644
--- a/test/user.test.js
+++ b/test/user.test.js
@@ -1,6 +1,7 @@
var User = loopback.User.extend('user');
var Session = loopback.Session;
var passport = require('passport');
+var MailConnector = require('../lib/connectors/mail');
var userMemory = loopback.createDataSource({
connector: loopback.Memory
@@ -9,9 +10,13 @@ var userMemory = loopback.createDataSource({
describe('User', function(){
+ var mailDataSource = loopback.createDataSource({
+ connector: MailConnector,
+ transports: [{type: 'STUB'}]
+ });
User.attachTo(userMemory);
User.session.attachTo(userMemory);
- User.email.setup({transports: [{type: 'STUB'}]});
+ User.email.attachTo(mailDataSource);
// allow many User.afterRemote's to be called
User.setMaxListeners(0);