Refactor email model into mail connector
This commit is contained in:
parent
26d0f74d66
commit
a3f1d8d944
53
docs/api.md
53
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.
|
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
|
```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.requireEmailVerfication = true;
|
||||||
User.afterRemote('create', function(ctx, user, next) {
|
User.afterRemote('create', function(ctx, user, next) {
|
||||||
var options = {
|
var options = {
|
||||||
|
@ -1231,6 +1247,43 @@ MySession.attachTo(loopback.memory());
|
||||||
|
|
||||||
Send emails from your loopback app.
|
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 <em>html</em>'
|
||||||
|
}, 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
|
### REST Router
|
||||||
|
|
||||||
Expose models over rest using the `loopback.rest` router.
|
Expose models over rest using the `loopback.rest` router.
|
||||||
|
|
3
index.js
3
index.js
|
@ -10,9 +10,10 @@ var loopback = module.exports = require('./lib/loopback');
|
||||||
|
|
||||||
loopback.Connector = require('./lib/connectors/base-connector');
|
loopback.Connector = require('./lib/connectors/base-connector');
|
||||||
loopback.Memory = require('./lib/connectors/memory');
|
loopback.Memory = require('./lib/connectors/memory');
|
||||||
|
loopback.Mail = require('./lib/connectors/mail');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types
|
* Types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
loopback.GeoPoint = require('loopback-datasource-juggler/lib/geo').GeoPoint;
|
loopback.GeoPoint = require('loopback-datasource-juggler/lib/geo').GeoPoint;
|
||||||
|
|
|
@ -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 ✔ <foo@blurdybloop.com>", // sender address
|
||||||
|
* to: "bar@blurdybloop.com, baz@blurdybloop.com", // list of receivers
|
||||||
|
* subject: "Hello ✔", // Subject line
|
||||||
|
* text: "Hello world ✔", // plaintext body
|
||||||
|
* html: "<b>Hello world ✔</b>" // 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;
|
|
@ -3,9 +3,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Model = require('../loopback').Model
|
var Model = require('../loopback').Model
|
||||||
, loopback = require('../loopback')
|
, loopback = require('../loopback');
|
||||||
, mailer = require('nodemailer')
|
|
||||||
, assert = require('assert');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Email properties.
|
* Default Email properties.
|
||||||
|
@ -24,87 +22,3 @@ var properties = {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Email = module.exports = Model.extend('email', 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 ✔ <foo@blurdybloop.com>", // sender address
|
|
||||||
* to: "bar@blurdybloop.com, baz@blurdybloop.com", // list of receivers
|
|
||||||
* subject: "Hello ✔", // Subject line
|
|
||||||
* text: "Hello world ✔", // plaintext body
|
|
||||||
* html: "<b>Hello world ✔</b>" // 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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -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: '<h1>html</h1>'
|
||||||
|
};
|
||||||
|
|
||||||
|
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: '<h1>html</h1>'
|
||||||
|
});
|
||||||
|
|
||||||
|
message.send(function (err, mail) {
|
||||||
|
assert(mail.message);
|
||||||
|
assert(mail.envelope);
|
||||||
|
assert(mail.messageId);
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,7 @@
|
||||||
var User = loopback.User.extend('user');
|
var User = loopback.User.extend('user');
|
||||||
var Session = loopback.Session;
|
var Session = loopback.Session;
|
||||||
var passport = require('passport');
|
var passport = require('passport');
|
||||||
|
var MailConnector = require('../lib/connectors/mail');
|
||||||
|
|
||||||
var userMemory = loopback.createDataSource({
|
var userMemory = loopback.createDataSource({
|
||||||
connector: loopback.Memory
|
connector: loopback.Memory
|
||||||
|
@ -9,9 +10,13 @@ var userMemory = loopback.createDataSource({
|
||||||
|
|
||||||
describe('User', function(){
|
describe('User', function(){
|
||||||
|
|
||||||
|
var mailDataSource = loopback.createDataSource({
|
||||||
|
connector: MailConnector,
|
||||||
|
transports: [{type: 'STUB'}]
|
||||||
|
});
|
||||||
User.attachTo(userMemory);
|
User.attachTo(userMemory);
|
||||||
User.session.attachTo(userMemory);
|
User.session.attachTo(userMemory);
|
||||||
User.email.setup({transports: [{type: 'STUB'}]});
|
User.email.attachTo(mailDataSource);
|
||||||
|
|
||||||
// allow many User.afterRemote's to be called
|
// allow many User.afterRemote's to be called
|
||||||
User.setMaxListeners(0);
|
User.setMaxListeners(0);
|
||||||
|
|
Loading…
Reference in New Issue