nodemailer 1.7.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.npmignore CHANGED
@@ -1,4 +1,6 @@
1
1
  .travis.yml
2
+ .jshintrc
2
3
  assets
3
4
  examples
4
- test
5
+ test
6
+ Gruntfile.js
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.11.0 2015-12-28
4
+
5
+ Allow connection url based SMTP configurations
6
+
7
+ ## v1.10.0 2015-11-13
8
+
9
+ Added `defaults` argument for `createTransport` to predefine commonn values (eg. `from` address)
10
+
11
+ ## v1.9.0 2015-11-09
12
+
13
+ Returns a Promise for `sendMail` if callback is not defined
14
+
15
+ ## v1.8.0 2015-10-08
16
+
17
+ Added priority option (high, normal, low) for setting Importance header
18
+
3
19
  ## v1.7.0 2015-10-06
4
20
 
5
21
  Replaced hyperquest with needle. Fixes issues with compressed data and redirects
package/README.md CHANGED
@@ -6,13 +6,7 @@ Send e-mails from Node.js – easy as cake!
6
6
  [![Build Status](https://secure.travis-ci.org/andris9/Nodemailer.svg)](http://travis-ci.org/andris9/Nodemailer)
7
7
  <a href="http://badge.fury.io/js/nodemailer"><img src="https://badge.fury.io/js/nodemailer.svg" alt="NPM version" height="18"></a>
8
8
 
9
- ## Upgrade warning
10
-
11
- Do not upgrade Nodemailer from 0.7 or lower to 1.0 as there are breaking changes. You can continue to use the 0.7 branch as long as you like. See the documentation for 0.7 [here](https://github.com/andris9/Nodemailer/blob/0.7/README.md).
12
-
13
- ### Migration guide
14
-
15
- See the migration guide from 0.7 to 1.0 [in the 1.0 release blog post](http://www.andrisreinman.com/nodemailer-v1-0/#migrationguide).
9
+ > **Notice for v0.x users** – Do not upgrade Nodemailer from 0.7 or lower. You can continue to use the 0.7 branch as long as you like. See the documentation for 0.7 [here](https://github.com/andris9/Nodemailer/blob/0.7/README.md).
16
10
 
17
11
  ## Notes and information
18
12
 
@@ -41,14 +35,8 @@ This is a complete example to send an e-mail with plaintext and HTML body
41
35
  ```javascript
42
36
  var nodemailer = require('nodemailer');
43
37
 
44
- // create reusable transporter object using SMTP transport
45
- var transporter = nodemailer.createTransport({
46
- service: 'Gmail',
47
- auth: {
48
- user: 'gmail.user@gmail.com',
49
- pass: 'userpass'
50
- }
51
- });
38
+ // create reusable transporter object using the default SMTP transport
39
+ var transporter = nodemailer.createTransport('smtps://user%40gmail.com:pass@smtp.gmail.com');
52
40
 
53
41
  // NB! No need to recreate the transporter object. You can use
54
42
  // the same transporter object for all e-mails
@@ -72,6 +60,8 @@ transporter.sendMail(mailOptions, function(error, info){
72
60
  });
73
61
  ```
74
62
 
63
+ You may need to ["Allow Less Secure Apps"](https://www.google.com/settings/security/lesssecureapps) in your gmail account (it's all the way at the bottom). You also may need to ["Allow access to your Google account"](https://accounts.google.com/DisplayUnlockCaptcha)
64
+
75
65
  See [nodemailer-smtp-transport](https://github.com/andris9/nodemailer-smtp-transport#usage) for SMTP configuration options and [nodemailer-wellknown](https://github.com/andris9/nodemailer-wellknown#supported-services) for preconfigured service names (example uses 'gmail').
76
66
 
77
67
  > When using default SMTP transport, then you do not need to define transport type explicitly (even though you can), just provide the SMTP options and that's it. For anything else, see the docs of the particular [transport mechanism](#available-transports).
@@ -85,13 +75,14 @@ Install with npm
85
75
  To send e-mails you need a transporter object
86
76
 
87
77
  ```javascript
88
- var transporter = nodemailer.createTransport(transport)
78
+ var transporter = nodemailer.createTransport(transport[, defaults])
89
79
  ```
90
80
 
91
81
  Where
92
82
 
93
83
  * **transporter** is going to be an object that is able to send mail
94
84
  * **transport** is a transport mechanism. If it is not set [nodemailer-direct-transport](https://github.com/andris9/nodemailer-direct-transport) transport is used. If it is a regular object [nodemailer-smtp-transport](https://github.com/andris9/nodemailer-smtp-transport) is used and the value is passed as SMTP configuration.
85
+ * **defaults** is an object that defines default values for mail options (available since Nodemailer v1.10.0)
95
86
 
96
87
  > You have to create the transporter object only once. If you already have a transporter object you can use it to send mail as much as you like.
97
88
 
@@ -126,9 +117,14 @@ var transporter = nodemailer.createTransport({
126
117
  user: 'sender@gmail.com',
127
118
  pass: 'password'
128
119
  }
120
+ }, {
121
+ // default values for sendMail method
122
+ from: 'sender@address',
123
+ headers: {
124
+ 'My-Awesome-Header': '123'
125
+ }
129
126
  });
130
127
  transporter.sendMail({
131
- from: 'sender@address',
132
128
  to: 'receiver@address',
133
129
  subject: 'hello',
134
130
  text: 'hello world!'
@@ -187,6 +183,7 @@ transporter.sendMail({
187
183
  * **[nodemailer-html-to-text](https://github.com/andris9/nodemailer-html-to-text)** to auto generate plaintext content from html
188
184
  * **[nodemailer-express-handlebars](https://github.com/yads/nodemailer-express-handlebars)** to auto generate html emails from handlebars/mustache templates
189
185
  * **[nodemailer-plugin-inline-base64](https://github.com/mixmaxhq/nodemailer-plugin-inline-base64)** to convert base64 images to attachments
186
+ * **[nodemailer-hashcash](https://github.com/andris9/nodemailer-hashcash)** to generate [hashcash](http://www.hashcash.org/) headers
190
187
  * *add yours* (see plugin api documentation [here](#plugin-api))
191
188
 
192
189
  ## Sending mail
@@ -194,13 +191,13 @@ transporter.sendMail({
194
191
  Once you have a transporter object you can send mail
195
192
 
196
193
  ```javascript
197
- transporter.sendMail(data, callback)
194
+ transporter.sendMail(data[, callback])
198
195
  ```
199
196
 
200
197
  Where
201
198
 
202
199
  * **data** defines the mail content (see [e-mail message fields](#e-mail-message-fields) below)
203
- * **callback** is an optional callback function to run once the message is delivered or it failed.
200
+ * **callback** is an optional callback function to run once the message is delivered or it failed
204
201
  * **err** is the error object if message failed
205
202
  * **info** includes the result, the exact format depends on the transport mechanism used
206
203
  * **info.messageId** most transports *should* return the final Message-Id value used with this property
@@ -212,6 +209,8 @@ Where
212
209
 
213
210
  > If the message includes several recipients then the message is considered sent if at least one recipient is accepted
214
211
 
212
+ If `callback` argument is not set then the method return a Promise object. Nodemailer itself does not use Promises internally but it wraps the return into a Promise for convenience.
213
+
215
214
  ### E-mail message fields
216
215
 
217
216
  The following are the possible fields of an e-mail message:
@@ -228,6 +227,7 @@ The following are the possible fields of an e-mail message:
228
227
  - **text** - The plaintext version of the message as an Unicode string, Buffer, Stream or an object *{path: '...'}*
229
228
  - **html** - The HTML version of the message as an Unicode string, Buffer, Stream or an object *{path: '...'}*
230
229
  - **watchHtml** - Apple Watch specific HTML version of the message (*experimental*)
230
+ - **priority** - Sets message importance headers, either `'high'`, `'normal'` (default) or `'low'`.
231
231
  - **headers** - An object or array of additional header fields (e.g. *{"X-Key-Name": "key value"}* or *[{key: "X-Key-Name", value: "val1"}, {key: "X-Key-Name", value: "val2"}]*)
232
232
  - **attachments** - An array of attachment objects (see [below](#attachments) for details)
233
233
  - **alternatives** - An array of alternative text contents (in addition to text and html parts) (see [below](#alternatives) for details)
@@ -251,6 +251,9 @@ Attachment object consists of the following properties:
251
251
  * **contentType** - optional content type for the attachment, if not set will be derived from the `filename` property
252
252
  * **contentDisposition** - optional content disposition type for the attachment, defaults to 'attachment'
253
253
 
254
+ > **Warning about stream errors** –
255
+ > If an error occurs with an input stream, eg. an attachment from an URL fails to load, then message generation is not rejected. Instead, the error message gets written as the attachment contents.
256
+
254
257
  Attachments can be added as many as you want.
255
258
 
256
259
  ```javascript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodemailer",
3
- "version": "1.7.0",
3
+ "version": "1.11.0",
4
4
  "description": "Easy as cake e-mail sending from your Node.js applications",
5
5
  "main": "src/nodemailer.js",
6
6
  "scripts": {
@@ -26,23 +26,23 @@
26
26
  },
27
27
  "homepage": "http://www.nodemailer.com",
28
28
  "devDependencies": {
29
- "chai": "^3.3.0",
29
+ "chai": "^3.4.1",
30
30
  "grunt": "^0.4.5",
31
31
  "grunt-contrib-jshint": "^0.11.3",
32
32
  "grunt-mocha-test": "^0.12.7",
33
- "mocha": "^2.3.3",
33
+ "mocha": "^2.3.4",
34
34
  "nodemailer-dkim": "^1.0.3",
35
35
  "nodemailer-markdown": "^1.0.0",
36
36
  "nodemailer-stub-transport": "^1.0.0",
37
- "sinon": "^1.17.1",
38
- "smtp-server": "^1.6.0"
37
+ "sinon": "^1.17.2",
38
+ "smtp-server": "^1.7.1"
39
39
  },
40
40
  "dependencies": {
41
41
  "libmime": "^1.2.0",
42
- "mailcomposer": "^2.0.0",
43
- "needle": "^0.10.0",
44
- "nodemailer-direct-transport": "^1.0.2",
45
- "nodemailer-smtp-transport": "^1.0.3"
42
+ "mailcomposer": "^2.1.0",
43
+ "needle": "^0.11.0",
44
+ "nodemailer-direct-transport": "^1.1.0",
45
+ "nodemailer-smtp-transport": "^1.1.0"
46
46
  },
47
47
  "engines": {
48
48
  "node": ">=0.10.0"
package/src/nodemailer.js CHANGED
@@ -11,16 +11,19 @@ var needle = require('needle');
11
11
  var PassThrough = require('stream').PassThrough;
12
12
 
13
13
  // Export createTransport method
14
- module.exports.createTransport = function(transporter) {
14
+ module.exports.createTransport = function (transporter, defaults) {
15
15
  transporter = transporter || directTransport({
16
16
  debug: true
17
17
  });
18
18
 
19
- if (typeof transporter === 'object' && typeof transporter.send !== 'function') {
19
+ if (
20
+ (typeof transporter === 'object' && typeof transporter.send !== 'function') ||
21
+ (typeof transporter === 'string' && /^smtps?:/i.test(transporter))
22
+ ) {
20
23
  transporter = smtpTransport(transporter);
21
24
  }
22
25
 
23
- return new Nodemailer(transporter);
26
+ return new Nodemailer(transporter, defaults);
24
27
  };
25
28
 
26
29
  /**
@@ -29,9 +32,11 @@ module.exports.createTransport = function(transporter) {
29
32
  * @constructor
30
33
  * @param {Object} transporter Transport object instance to pass the mails to
31
34
  */
32
- function Nodemailer(transporter) {
35
+ function Nodemailer(transporter, defaults) {
33
36
  EventEmitter.call(this);
34
37
 
38
+ this._defaults = defaults || {};
39
+
35
40
  this._plugins = {
36
41
  compile: [],
37
42
  stream: []
@@ -46,7 +51,7 @@ function Nodemailer(transporter) {
46
51
  }
47
52
  util.inherits(Nodemailer, EventEmitter);
48
53
 
49
- Nodemailer.prototype.use = function(step, plugin) {
54
+ Nodemailer.prototype.use = function (step, plugin) {
50
55
  step = (step || '').toString();
51
56
  if (!this._plugins.hasOwnProperty(step)) {
52
57
  this._plugins[step] = [plugin];
@@ -58,7 +63,7 @@ Nodemailer.prototype.use = function(step, plugin) {
58
63
  /**
59
64
  * Optional close method, passed to the underlying transport object
60
65
  */
61
- Nodemailer.prototype.close = function( /* possible arguments */ ) {
66
+ Nodemailer.prototype.close = function ( /* possible arguments */ ) {
62
67
  var args = Array.prototype.slice.call(arguments);
63
68
  if (typeof this.transporter.close === 'function') {
64
69
  this.transporter.close.apply(this.transporter, args);
@@ -71,10 +76,32 @@ Nodemailer.prototype.close = function( /* possible arguments */ ) {
71
76
  * @param {Object} data E-data description
72
77
  * @param {Function} callback Callback to run once the sending succeeded or failed
73
78
  */
74
- Nodemailer.prototype.sendMail = function(data, callback) {
79
+ Nodemailer.prototype.sendMail = function (data, callback) {
80
+ var promise;
81
+
82
+ if (!callback && typeof Promise === 'function') {
83
+ promise = new Promise(function (resolve, reject) {
84
+ callback = callbackPromise(resolve, reject);
85
+ });
86
+ }
87
+
75
88
  data = data || {};
76
89
  data.headers = data.headers || {};
77
- callback = callback || function() {};
90
+ callback = callback || function () {};
91
+
92
+ // apply defaults
93
+ Object.keys(this._defaults).forEach(function (key) {
94
+ if (!(key in data)) {
95
+ data[key] = this._defaults[key];
96
+ } else if (key === 'headers') {
97
+ // headers is a special case. Allow setting individual default headers
98
+ Object.keys(this._defaults.headers || {}).forEach(function (key) {
99
+ if (!(key in data.headers)) {
100
+ data.headers[key] = this._defaults.headers[key];
101
+ }
102
+ }.bind(this));
103
+ }
104
+ }.bind(this));
78
105
 
79
106
  var mail = {
80
107
  data: data,
@@ -83,10 +110,10 @@ Nodemailer.prototype.sendMail = function(data, callback) {
83
110
  };
84
111
 
85
112
  if (typeof this.transporter === 'string') {
86
- return callback(new Error('Unsupported configuration, downgrade Nodemailer to v0.7.1 or see the migration guide https://github.com/andris9/Nodemailer#migration-guide'));
113
+ return callback(new Error('Unsupported configuration, downgrade Nodemailer to v0.7.1 to use it'));
87
114
  }
88
115
 
89
- this._processPlugins('compile', mail, function(err) {
116
+ this._processPlugins('compile', mail, function (err) {
90
117
  if (err) {
91
118
  return callback(err);
92
119
  }
@@ -97,13 +124,32 @@ Nodemailer.prototype.sendMail = function(data, callback) {
97
124
  mail.message.setHeader('X-Mailer', mail.data.xMailer || this._getVersionString());
98
125
  }
99
126
 
100
- this._processPlugins('stream', mail, function(err) {
127
+ if (mail.data.priority) {
128
+ switch ((mail.data.priority || '').toString().toLowerCase()) {
129
+ case 'high':
130
+ mail.message.setHeader('X-Priority', '1 (Highest)');
131
+ mail.message.setHeader('X-MSMail-Priority', 'High');
132
+ mail.message.setHeader('Importance', 'High');
133
+ break;
134
+ case 'low':
135
+ mail.message.setHeader('X-Priority', '5 (Lowest)');
136
+ mail.message.setHeader('X-MSMail-Priority', 'Low');
137
+ mail.message.setHeader('Importance', 'Low');
138
+ break;
139
+ default:
140
+ // do not add anything, since all messages are 'Normal' by default
141
+ }
142
+ }
143
+
144
+ this._processPlugins('stream', mail, function (err) {
101
145
  if (err) {
102
146
  return callback(err);
103
147
  }
104
148
  this.transporter.send(mail, callback);
105
149
  }.bind(this));
106
150
  }.bind(this));
151
+
152
+ return promise;
107
153
  };
108
154
 
109
155
  /**
@@ -119,7 +165,15 @@ Nodemailer.prototype.sendMail = function(data, callback) {
119
165
  * @param {String|Number} key Property name or an Array index
120
166
  * @param {Function} callback Callback function with (err, value)
121
167
  */
122
- Nodemailer.prototype.resolveContent = function(data, key, callback) {
168
+ Nodemailer.prototype.resolveContent = function (data, key, callback) {
169
+ var promise;
170
+
171
+ if (!callback && typeof Promise === 'function') {
172
+ promise = new Promise(function (resolve, reject) {
173
+ callback = callbackPromise(resolve, reject);
174
+ });
175
+ }
176
+
123
177
  var content = data && data[key] && data[key].content || data[key];
124
178
  var contentStream;
125
179
  var encoding = (typeof data[key] === 'object' && data[key].encoding || 'utf8')
@@ -133,7 +187,7 @@ Nodemailer.prototype.resolveContent = function(data, key, callback) {
133
187
 
134
188
  if (typeof content === 'object') {
135
189
  if (typeof content.pipe === 'function') {
136
- return this._resolveStream(content, function(err, value) {
190
+ return this._resolveStream(content, function (err, value) {
137
191
  if (err) {
138
192
  return callback(err);
139
193
  }
@@ -149,7 +203,7 @@ Nodemailer.prototype.resolveContent = function(data, key, callback) {
149
203
  parse_response: false,
150
204
  compressed: true,
151
205
  follow_max: 5
152
- }).on('end', function(err) {
206
+ }).on('end', function (err) {
153
207
  if (err) {
154
208
  contentStream.emit('error', err);
155
209
  }
@@ -174,7 +228,9 @@ Nodemailer.prototype.resolveContent = function(data, key, callback) {
174
228
  }
175
229
 
176
230
  // default action, return as is
177
- callback(null, content);
231
+ setImmediate(callback.bind(null, null, content));
232
+
233
+ return promise;
178
234
  };
179
235
 
180
236
  /**
@@ -183,12 +239,12 @@ Nodemailer.prototype.resolveContent = function(data, key, callback) {
183
239
  * @param {Object} stream Readable stream
184
240
  * @param {Function} callback Callback function with (err, value)
185
241
  */
186
- Nodemailer.prototype._resolveStream = function(stream, callback) {
242
+ Nodemailer.prototype._resolveStream = function (stream, callback) {
187
243
  var responded = false;
188
244
  var chunks = [];
189
245
  var chunklen = 0;
190
246
 
191
- stream.on('error', function(err) {
247
+ stream.on('error', function (err) {
192
248
  if (responded) {
193
249
  return;
194
250
  }
@@ -197,14 +253,14 @@ Nodemailer.prototype._resolveStream = function(stream, callback) {
197
253
  callback(err);
198
254
  });
199
255
 
200
- stream.on('data', function(chunk) {
256
+ stream.on('data', function (chunk) {
201
257
  if (chunk && chunk.length) {
202
258
  chunks.push(chunk);
203
259
  chunklen += chunk.length;
204
260
  }
205
261
  });
206
262
 
207
- stream.on('end', function() {
263
+ stream.on('end', function () {
208
264
  if (responded) {
209
265
  return;
210
266
  }
@@ -221,7 +277,7 @@ Nodemailer.prototype._resolveStream = function(stream, callback) {
221
277
  });
222
278
  };
223
279
 
224
- Nodemailer.prototype._getVersionString = function() {
280
+ Nodemailer.prototype._getVersionString = function () {
225
281
  return util.format(
226
282
  '%s (%s; +%s; %s/%s)',
227
283
  packageData.name,
@@ -232,7 +288,7 @@ Nodemailer.prototype._getVersionString = function() {
232
288
  );
233
289
  };
234
290
 
235
- Nodemailer.prototype._processPlugins = function(step, mail, callback) {
291
+ Nodemailer.prototype._processPlugins = function (step, mail, callback) {
236
292
  step = (step || '').toString();
237
293
 
238
294
  if (!this._plugins.hasOwnProperty(step) || !this._plugins[step].length) {
@@ -241,12 +297,12 @@ Nodemailer.prototype._processPlugins = function(step, mail, callback) {
241
297
 
242
298
  var plugins = Array.prototype.slice.call(this._plugins[step]);
243
299
 
244
- var processPlugins = function() {
300
+ var processPlugins = function () {
245
301
  if (!plugins.length) {
246
302
  return callback(null);
247
303
  }
248
304
  var plugin = plugins.shift();
249
- plugin(mail, function(err) {
305
+ plugin(mail, function (err) {
250
306
  if (err) {
251
307
  return callback(err);
252
308
  }
@@ -255,4 +311,23 @@ Nodemailer.prototype._processPlugins = function(step, mail, callback) {
255
311
  }.bind(this);
256
312
 
257
313
  processPlugins();
258
- };
314
+ };
315
+
316
+ /**
317
+ * Wrapper for creating a callback than either resolves or rejects a promise
318
+ * based on input
319
+ *
320
+ * @param {Function} resolve Function to run if callback is called
321
+ * @param {Function} reject Function to run if callback ends with an error
322
+ */
323
+ function callbackPromise(resolve, reject) {
324
+ return function () {
325
+ var args = Array.prototype.slice.call(arguments);
326
+ var err = args.shift();
327
+ if (err) {
328
+ reject(err);
329
+ } else {
330
+ resolve.apply(null, args);
331
+ }
332
+ };
333
+ }
package/.jshintrc DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "indent": 4,
3
- "node": true,
4
- "globalstrict": true,
5
- "evil": true,
6
- "unused": true,
7
- "undef": true,
8
- "newcap": true,
9
- "esnext": true,
10
- "curly": true,
11
- "eqeqeq": true,
12
- "expr": true,
13
-
14
- "predef": [
15
- "describe",
16
- "it",
17
- "beforeEach",
18
- "afterEach"
19
- ]
20
- }
package/Gruntfile.js DELETED
@@ -1,30 +0,0 @@
1
- 'use strict';
2
-
3
- module.exports = function(grunt) {
4
-
5
- // Project configuration.
6
- grunt.initConfig({
7
- jshint: {
8
- all: ['src/*.js', 'test/*.js', 'examples/*.js', 'Gruntfile.js'],
9
- options: {
10
- jshintrc: '.jshintrc'
11
- }
12
- },
13
-
14
- mochaTest: {
15
- all: {
16
- options: {
17
- reporter: 'spec'
18
- },
19
- src: ['test/*-test.js']
20
- }
21
- }
22
- });
23
-
24
- // Load the plugin(s)
25
- grunt.loadNpmTasks('grunt-contrib-jshint');
26
- grunt.loadNpmTasks('grunt-mocha-test');
27
-
28
- // Tasks
29
- grunt.registerTask('default', ['jshint', 'mochaTest']);
30
- };