1 | 'use strict';
|
2 |
|
3 | var AWS = require('aws-sdk');
|
4 | var packageData = require('../package.json');
|
5 |
|
6 |
|
7 | module.exports = function(options) {
|
8 | return new SESTransport(options);
|
9 | };
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | function SESTransport(options) {
|
26 | options = options || {};
|
27 |
|
28 | var pattern = /(.*)email(.*)\.(.*).amazonaws.com/i,
|
29 | result = pattern.exec(options.ServiceUrl);
|
30 |
|
31 | this.options = options;
|
32 | this.options.accessKeyId = options.accessKeyId || options.AWSAccessKeyID;
|
33 | this.options.secretAccessKey = options.secretAccessKey || options.AWSSecretKey;
|
34 | this.options.sessionToken = options.sessionToken || options.AWSSecurityToken;
|
35 | this.options.apiVersion = '2010-12-01';
|
36 | this.options.region = options.region || (result && result[3]) || 'us-east-1';
|
37 |
|
38 | this.options.rateLimit = Number(options.rateLimit) || false;
|
39 | this.queue = [];
|
40 | this.sending = false;
|
41 |
|
42 | this.name = 'SES';
|
43 | this.version = packageData.version;
|
44 |
|
45 | this.ses = new AWS.SES(this.options);
|
46 | }
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 | SESTransport.prototype.send = function(mail, callback) {
|
55 |
|
56 | mail.message.keepBcc = true;
|
57 |
|
58 | if (this.options.rateLimit) {
|
59 | this.queue.push({
|
60 | mail: mail,
|
61 | callback: callback
|
62 | });
|
63 | this.processQueue();
|
64 | } else {
|
65 | this.sendMessage(mail, callback);
|
66 | }
|
67 | };
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | SESTransport.prototype.processQueue = function() {
|
73 | if (this.sending) {
|
74 | return;
|
75 | }
|
76 |
|
77 | if (!this.queue.length) {
|
78 | return;
|
79 | }
|
80 |
|
81 | this.sending = true;
|
82 | var item = this.queue.shift();
|
83 | var startTime = Date.now();
|
84 |
|
85 | this.sendMessage(item.mail, function() {
|
86 | var args = Array.prototype.slice.call(arguments);
|
87 | var timeDelta = Date.now() - startTime;
|
88 |
|
89 | if (typeof item.callback === 'function') {
|
90 | setImmediate(function() {
|
91 | item.callback.apply(null, args);
|
92 | });
|
93 | }
|
94 |
|
95 | if (timeDelta >= 1000 / this.options.rateLimit) {
|
96 | this.sending = false;
|
97 | setImmediate(this.processQueue.bind(this));
|
98 | } else {
|
99 | setTimeout(function() {
|
100 | this.sending = false;
|
101 | this.processQueue();
|
102 | }.bind(this), Math.ceil(1000 / this.options.rateLimit - timeDelta));
|
103 | }
|
104 | }.bind(this));
|
105 | };
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 | SESTransport.prototype.sendMessage = function(mail, callback) {
|
114 | this.generateMessage(mail.message.createReadStream(), (function(err, raw) {
|
115 | if (err) {
|
116 | return typeof callback === 'function' && callback(err);
|
117 | }
|
118 | this.handleMessage(mail, raw, callback);
|
119 | }).bind(this));
|
120 | };
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 | SESTransport.prototype.handleMessage = function(mail, raw, callback) {
|
130 | var params = {
|
131 | RawMessage: {
|
132 | Data: new Buffer(raw, 'utf-8')
|
133 | }
|
134 | };
|
135 | this.ses.sendRawEmail(params, function(err, data) {
|
136 | this.responseHandler(err, mail, data, callback);
|
137 | }.bind(this));
|
138 | };
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | SESTransport.prototype.responseHandler = function(err, mail, data, callback) {
|
149 | if (err) {
|
150 | if (!(err instanceof Error)) {
|
151 | err = new Error('Email failed: ' + err);
|
152 | }
|
153 | return typeof callback === 'function' && callback(err, null);
|
154 | }
|
155 | return typeof callback === 'function' && callback(null, {
|
156 | envelope: mail.data.envelope || mail.message.getEnvelope(),
|
157 | messageId: data && data.MessageId && data.MessageId + '@email.amazonses.com'
|
158 | });
|
159 | };
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 | SESTransport.prototype.generateMessage = function(mailStream, callback) {
|
171 | var chunks = [];
|
172 | var chunklen = 0;
|
173 |
|
174 | mailStream.on('data', function(chunk) {
|
175 | chunks.push(chunk);
|
176 | chunklen += chunk.length;
|
177 | });
|
178 |
|
179 | mailStream.on('end', function() {
|
180 | callback(null, Buffer.concat(chunks, chunklen).toString());
|
181 | });
|
182 | }; |
\ | No newline at end of file |