@stamhoofd/email 2.1.3 → 2.3.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.
@@ -0,0 +1,55 @@
1
+ /// <reference types="node" />
2
+ import Mail from 'nodemailer/lib/mailer';
3
+ import { I18n } from "@stamhoofd/backend-i18n";
4
+ export type EmailInterfaceRecipient = {
5
+ name?: string | null;
6
+ email: string;
7
+ };
8
+ export type EmailInterfaceBase = {
9
+ to: string | EmailInterfaceRecipient[];
10
+ bcc?: string;
11
+ replyTo?: string;
12
+ subject: string;
13
+ text?: string;
14
+ html?: string;
15
+ attachments?: {
16
+ filename: string;
17
+ path?: string;
18
+ href?: string;
19
+ content?: string | Buffer;
20
+ contentType?: string;
21
+ }[];
22
+ retryCount?: number;
23
+ type?: "transactional" | "broadcast";
24
+ headers?: Record<string, string> | null;
25
+ };
26
+ export type EmailInterface = EmailInterfaceBase & {
27
+ from: string;
28
+ };
29
+ export type EmailBuilder = () => EmailInterface | undefined;
30
+ declare class EmailStatic {
31
+ transporter: Mail;
32
+ transactionalTransporter: Mail;
33
+ rps: number;
34
+ currentQueue: EmailBuilder[];
35
+ sending: boolean;
36
+ setupIfNeeded(): void;
37
+ private sendNextIfNeeded;
38
+ parseTo(to: string | EmailInterfaceRecipient[]): EmailInterfaceRecipient[];
39
+ /**
40
+ * Get the raw email
41
+ */
42
+ parseEmailStr(emailStr: string): string[];
43
+ private doSend;
44
+ getInternalEmailFor(i18n: I18n): string;
45
+ getPersonalEmailFor(i18n: I18n): string;
46
+ /**
47
+ * Send an internal e-mail (from stamhoofd)
48
+ */
49
+ sendInternal(data: EmailInterfaceBase, i18n: I18n): void;
50
+ send(data: EmailInterface): void;
51
+ schedule(builder: EmailBuilder): void;
52
+ }
53
+ export declare const Email: EmailStatic;
54
+ export {};
55
+ //# sourceMappingURL=Email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Email.d.ts","sourceRoot":"","sources":["../../src/classes/Email.ts"],"names":[],"mappings":";AAEA,OAAO,IAAI,MAAM,uBAAuB,CAAC;AAIzC,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;AAE9C,MAAM,MAAM,uBAAuB,GAAG;IAClC,IAAI,CAAC,EAAE,MAAM,GAAC,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACjB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC7B,EAAE,EAAE,MAAM,GAAC,uBAAuB,EAAE,CAAC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAC,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,eAAe,GAAG,WAAW,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAC,IAAI,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAC;CAChB,CAAA;AAGD,MAAM,MAAM,YAAY,GAAG,MAAM,cAAc,GAAG,SAAS,CAAA;AAE3D,cAAM,WAAW;IACb,WAAW,EAAE,IAAI,CAAC;IAClB,wBAAwB,EAAE,IAAI,CAAC;IAC/B,GAAG,SAAK;IAER,YAAY,EAAE,YAAY,EAAE,CAAK;IACjC,OAAO,UAAQ;IAEf,aAAa;IAkDb,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAC,uBAAuB,EAAE,GAAG,uBAAuB,EAAE;IASxE;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;YAkF3B,MAAM;IA2HpB,mBAAmB,CAAC,IAAI,EAAE,IAAI;IAI9B,mBAAmB,CAAC,IAAI,EAAE,IAAI;IAI9B;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,IAAI;IAKjD,IAAI,CAAC,IAAI,EAAE,cAAc;IAgBzB,QAAQ,CAAC,OAAO,EAAE,YAAY;CAIjC;AAED,eAAO,MAAM,KAAK,aAAoB,CAAC"}
@@ -0,0 +1,309 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Email = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const utility_1 = require("@stamhoofd/utility");
6
+ const nodemailer_1 = tslib_1.__importDefault(require("nodemailer"));
7
+ const EmailAddress_1 = require("../models/EmailAddress");
8
+ const html_to_text_1 = tslib_1.__importDefault(require("html-to-text"));
9
+ const utility_2 = require("@stamhoofd/utility");
10
+ const backend_i18n_1 = require("@stamhoofd/backend-i18n");
11
+ class EmailStatic {
12
+ constructor() {
13
+ this.rps = 14;
14
+ this.currentQueue = [];
15
+ this.sending = false;
16
+ }
17
+ setupIfNeeded() {
18
+ if (this.transporter) {
19
+ return;
20
+ }
21
+ if (!STAMHOOFD.SMTP_HOST || !STAMHOOFD.SMTP_PORT) {
22
+ throw new Error("Missing environment variables to send emails");
23
+ return;
24
+ }
25
+ // create reusable transporter object using the default SMTP transport
26
+ this.transporter = nodemailer_1.default.createTransport({
27
+ pool: true,
28
+ host: STAMHOOFD.SMTP_HOST,
29
+ port: STAMHOOFD.SMTP_PORT,
30
+ auth: {
31
+ user: STAMHOOFD.SMTP_USERNAME, // generated ethereal user
32
+ pass: STAMHOOFD.SMTP_PASSWORD // generated ethereal password
33
+ }
34
+ });
35
+ // create reusable transporter object using the default SMTP transport
36
+ this.transactionalTransporter = nodemailer_1.default.createTransport({
37
+ pool: true,
38
+ host: STAMHOOFD.TRANSACTIONAL_SMTP_HOST,
39
+ port: STAMHOOFD.TRANSACTIONAL_SMTP_PORT,
40
+ auth: {
41
+ user: STAMHOOFD.TRANSACTIONAL_SMTP_USERNAME, // generated ethereal user
42
+ pass: STAMHOOFD.TRANSACTIONAL_SMTP_PASSWORD // generated ethereal password
43
+ }
44
+ });
45
+ // verify connection configuration
46
+ this.transporter.verify((error) => {
47
+ if (error) {
48
+ console.error("SMTP server not working", error);
49
+ }
50
+ else {
51
+ console.log("SMTP server is ready to take our messages");
52
+ }
53
+ });
54
+ // verify connection configuration
55
+ this.transactionalTransporter.verify((error) => {
56
+ if (error) {
57
+ console.error("Transactinoal SMTP server not working", error);
58
+ }
59
+ else {
60
+ console.log("Transactinoal SMTP server is ready to take our messages");
61
+ }
62
+ });
63
+ }
64
+ sendNextIfNeeded() {
65
+ if (!this.sending) {
66
+ if (this.currentQueue.length == 0) {
67
+ console.log("mail queue is empty");
68
+ return;
69
+ }
70
+ let next = this.currentQueue[0]();
71
+ while (next === undefined) {
72
+ this.currentQueue.shift();
73
+ if (this.currentQueue.length == 0) {
74
+ console.log("mail queue is empty");
75
+ return;
76
+ }
77
+ next = this.currentQueue[0]();
78
+ }
79
+ this.sending = true;
80
+ this.doSend(next).catch(e => {
81
+ console.error(e);
82
+ }).finally(() => {
83
+ this.sending = false;
84
+ this.sendNextIfNeeded();
85
+ });
86
+ }
87
+ }
88
+ parseTo(to) {
89
+ if (typeof to === "string") {
90
+ return this.parseEmailStr(to).map(email => ({ email }));
91
+ }
92
+ // Filter invalid email addresses
93
+ return to.filter(r => utility_1.DataValidator.isEmailValid(r.email));
94
+ }
95
+ /**
96
+ * Get the raw email
97
+ */
98
+ parseEmailStr(emailStr) {
99
+ let insideQuote = false;
100
+ let escaped = false;
101
+ let inAddr = false;
102
+ let email = "";
103
+ let didFindAddr = false;
104
+ let cleanedStr = "";
105
+ const addresses = [];
106
+ function endAddress() {
107
+ let m;
108
+ if (didFindAddr) {
109
+ m = email.trim();
110
+ }
111
+ else {
112
+ m = cleanedStr.trim();
113
+ }
114
+ if (utility_1.DataValidator.isEmailValid(m)) {
115
+ addresses.push(m);
116
+ }
117
+ didFindAddr = false;
118
+ email = "";
119
+ inAddr = false;
120
+ insideQuote = false;
121
+ escaped = false;
122
+ cleanedStr = "";
123
+ }
124
+ // eslint-disable-next-line @typescript-eslint/prefer-for-of
125
+ for (let index = 0; index < emailStr.length; index++) {
126
+ const shouldEscape = escaped;
127
+ if (escaped) {
128
+ escaped = false;
129
+ }
130
+ const character = emailStr[index];
131
+ if (insideQuote) {
132
+ if (character === "\\") {
133
+ escaped = true;
134
+ continue;
135
+ }
136
+ }
137
+ if (!shouldEscape) {
138
+ if (character === "\"") {
139
+ if (insideQuote) {
140
+ insideQuote = false;
141
+ continue;
142
+ }
143
+ insideQuote = true;
144
+ continue;
145
+ }
146
+ if (!insideQuote) {
147
+ if (character === "<") {
148
+ inAddr = true;
149
+ continue;
150
+ }
151
+ if (character === ">") {
152
+ inAddr = false;
153
+ didFindAddr = true;
154
+ continue;
155
+ }
156
+ if (character === ",") {
157
+ // End previous address
158
+ endAddress();
159
+ continue;
160
+ }
161
+ }
162
+ }
163
+ if (inAddr) {
164
+ email += character;
165
+ }
166
+ cleanedStr += character;
167
+ }
168
+ endAddress();
169
+ return addresses;
170
+ }
171
+ async doSend(data) {
172
+ var _a, _b;
173
+ if (STAMHOOFD.environment === 'test') {
174
+ // Do not send any emails
175
+ return;
176
+ }
177
+ // Check if this email is not marked as spam
178
+ // Filter recipients if bounced or spam
179
+ let recipients = this.parseTo(data.to);
180
+ if (recipients.length === 0) {
181
+ // Invalid string
182
+ console.warn("Invalid e-mail string: '" + data.to + "'. E-mail skipped");
183
+ return;
184
+ }
185
+ // Check spam and bounces
186
+ recipients = await EmailAddress_1.EmailAddress.filterSendTo(recipients);
187
+ if (recipients.length === 0) {
188
+ // Invalid string
189
+ console.warn("Filtered all emails due hard bounce or spam '" + data.to + "'. E-mail skipped");
190
+ return;
191
+ }
192
+ // Filter by environment
193
+ if (STAMHOOFD.environment === 'staging') {
194
+ recipients = recipients.filter(mail => !mail.email.includes("geen-email"));
195
+ }
196
+ if (STAMHOOFD.environment === 'development') {
197
+ recipients = recipients.filter(mail => mail.email.endsWith("@stamhoofd.be") || mail.email.endsWith("@bounce-testing.postmarkapp.com"));
198
+ }
199
+ if (recipients.length === 0) {
200
+ // Invalid string
201
+ console.warn("Filtered all emails due to environment filter '" + data.to + "'. E-mail skipped");
202
+ return;
203
+ }
204
+ // Rebuild to
205
+ const to = recipients.map((recipient) => {
206
+ if (!recipient.name) {
207
+ return recipient.email;
208
+ }
209
+ const cleanedName = utility_1.Formatter.emailSenderName(recipient.name);
210
+ if (cleanedName.length < 2) {
211
+ return recipient.email;
212
+ }
213
+ return '"' + cleanedName + '" <' + recipient.email + '>';
214
+ }).join(", ");
215
+ this.setupIfNeeded();
216
+ // send mail with defined transport object
217
+ const mail = {
218
+ from: data.from, // sender address
219
+ bcc: (STAMHOOFD.environment === "production" || !data.bcc) ? data.bcc : "simon@stamhoofd.be",
220
+ replyTo: data.replyTo,
221
+ to,
222
+ subject: data.subject, // Subject line
223
+ text: data.text, // plain text body
224
+ };
225
+ if (data.attachments) {
226
+ mail.attachments = data.attachments;
227
+ }
228
+ if (data.headers) {
229
+ mail.headers = data.headers;
230
+ }
231
+ if (data.html) {
232
+ mail.html = data.html;
233
+ if (!data.text) {
234
+ mail.text = html_to_text_1.default.fromString(data.html, {
235
+ wordwrap: null,
236
+ unorderedListItemPrefix: " - "
237
+ });
238
+ }
239
+ }
240
+ try {
241
+ if (!data.from.includes('@stamhoofd.be') && !data.from.includes('@stamhoofd.nl')) {
242
+ // Not supported
243
+ data.type = 'broadcast';
244
+ }
245
+ const transporter = (data.type === "transactional") ? this.transactionalTransporter : this.transporter;
246
+ const info = await transporter.sendMail(mail);
247
+ console.log("Message sent:", to, data.subject, info.messageId, data.type);
248
+ }
249
+ catch (e) {
250
+ console.error("Failed to send e-mail:");
251
+ console.error(e);
252
+ console.error(mail);
253
+ if (STAMHOOFD.environment === 'development') {
254
+ return;
255
+ }
256
+ // Sleep 1 second to give servers some time to fix possible rate limits
257
+ await (0, utility_2.sleep)(1000);
258
+ // Reschedule twice (at maximum) to fix temporary connection issues
259
+ data.retryCount = ((_a = data.retryCount) !== null && _a !== void 0 ? _a : 0) + 1;
260
+ if (data.retryCount <= 2) {
261
+ this.send(data);
262
+ }
263
+ else {
264
+ // Email address is not verified.
265
+ if (!data.from.includes("hallo@stamhoofd.be")) {
266
+ this.sendInternal({
267
+ to: "hallo@stamhoofd.be",
268
+ subject: "E-mail kon niet worden verzonden",
269
+ text: "Een e-mail vanaf " + data.from + " kon niet worden verstuurd aan " + mail.to + ": \n\n" + e + "\n\n" + ((_b = mail.text) !== null && _b !== void 0 ? _b : ""),
270
+ type: (data.type === "transactional") ? "broadcast" : "transactional"
271
+ }, new backend_i18n_1.I18n("nl", "BE"));
272
+ }
273
+ }
274
+ }
275
+ }
276
+ getInternalEmailFor(i18n) {
277
+ return '"Stamhoofd" <' + (i18n.$t("shared.emails.general")) + '>';
278
+ }
279
+ getPersonalEmailFor(i18n) {
280
+ return '"Simon Backx" <' + (i18n.$t("shared.emails.personal")) + '>';
281
+ }
282
+ /**
283
+ * Send an internal e-mail (from stamhoofd)
284
+ */
285
+ sendInternal(data, i18n) {
286
+ const mail = Object.assign(data, { from: this.getInternalEmailFor(i18n) });
287
+ this.send(mail);
288
+ }
289
+ send(data) {
290
+ if (STAMHOOFD.environment === 'test') {
291
+ // Do not send any emails
292
+ return;
293
+ }
294
+ let didSend = false;
295
+ this.schedule(() => {
296
+ if (didSend) {
297
+ return undefined;
298
+ }
299
+ didSend = true;
300
+ return data;
301
+ });
302
+ }
303
+ schedule(builder) {
304
+ this.currentQueue.push(builder);
305
+ this.sendNextIfNeeded();
306
+ }
307
+ }
308
+ exports.Email = new EmailStatic();
309
+ //# sourceMappingURL=Email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Email.js","sourceRoot":"","sources":["../../src/classes/Email.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Email.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Email.test.d.ts","sourceRoot":"","sources":["../../src/classes/Email.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const Email_1 = require("./Email");
4
+ describe("Email", () => {
5
+ it("should parse e-mail strings correctly", () => {
6
+ expect(Email_1.Email.parseEmailStr('"My crazy name" <hallo@stamhoofd.be>')).toEqual(["hallo@stamhoofd.be"]);
7
+ expect(Email_1.Email.parseEmailStr('hallo@stamhoofd.be')).toEqual(["hallo@stamhoofd.be"]);
8
+ expect(Email_1.Email.parseEmailStr('hallo@stamhoofd.be ')).toEqual(["hallo@stamhoofd.be"]);
9
+ expect(Email_1.Email.parseEmailStr('"hallo@stamhoofd.be"')).toEqual(["hallo@stamhoofd.be"]);
10
+ expect(Email_1.Email.parseEmailStr('<"hallo@stamhoofd.be">')).toEqual(["hallo@stamhoofd.be"]);
11
+ expect(Email_1.Email.parseEmailStr('Gekke naam <"hallo@stamhoofd.be">')).toEqual(["hallo@stamhoofd.be"]);
12
+ expect(Email_1.Email.parseEmailStr('<"hallo@stam\\"hoofd.be">')).toEqual([]);
13
+ expect(Email_1.Email.parseEmailStr('<"hallo@stam,hoofd.be">')).toEqual([]);
14
+ expect(Email_1.Email.parseEmailStr('<hallo@stam,hoofd.be>')).toEqual([]);
15
+ expect(Email_1.Email.parseEmailStr('"Hallo <dit is een test>" <hallo@stamhoofd.be>')).toEqual(["hallo@stamhoofd.be"]);
16
+ expect(Email_1.Email.parseEmailStr('"Hallo 👋🏽" <hallo@stamhoofd.be>')).toEqual(["hallo@stamhoofd.be"]);
17
+ expect(Email_1.Email.parseEmailStr('Hallo <hallo@stam.hoofd.be>')).toEqual(["hallo@stam.hoofd.be"]);
18
+ expect(Email_1.Email.parseEmailStr('Hallo <hallo@stam.hoofd.be')).toEqual([]);
19
+ expect(Email_1.Email.parseEmailStr('"Hallo <dit is \\" een test>" <hallo@stamhoofd.be>')).toEqual(["hallo@stamhoofd.be"]);
20
+ expect(Email_1.Email.parseEmailStr('"Hallo <dit is \\" een test佐>" <hallo@stamhoofd.be>')).toEqual(["hallo@stamhoofd.be"]);
21
+ expect(Email_1.Email.parseEmailStr('"Voornaam \'l Achternaam, en nog iets" <jwz@netscape.com>')).toEqual(["jwz@netscape.com"]);
22
+ expect(Email_1.Email.parseEmailStr('"Voornaam \'l Achternaam, en nog iets" <jwz@netscape.com>, "My crazy name" <hallo@stamhoofd.be>')).toEqual(["jwz@netscape.com", "hallo@stamhoofd.be"]);
23
+ expect(Email_1.Email.parseEmailStr('hallo@example.com, test@test.com')).toEqual(["hallo@example.com", "test@test.com"]);
24
+ expect(Email_1.Email.parseEmailStr('hallo@example.com, invalid, test@test.com')).toEqual(["hallo@example.com", "test@test.com"]);
25
+ });
26
+ });
27
+ //# sourceMappingURL=Email.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Email.test.js","sourceRoot":"","sources":["../../src/classes/Email.test.ts"],"names":[],"mappings":";;AAAA,mCAA+B;AAE/B,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACnB,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,sCAAsC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QACnG,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QACjF,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAClF,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QACnF,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QACrF,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,mCAAmC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAChG,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,2BAA2B,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACpE,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAClE,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAChE,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,gDAAgD,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAC7G,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,mCAAmC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAChG,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,6BAA6B,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAA;QAC3F,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,4BAA4B,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAErE,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,oDAAoD,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QACjH,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,qDAAqD,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAElH,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,2DAA2D,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAA;QACtH,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,iGAAiG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,CAAC,CAAA;QAElL,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,kCAAkC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC,CAAA;QAC/G,MAAM,CAAC,aAAK,CAAC,aAAa,CAAC,2CAA2C,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC,CAAA;IAC5H,CAAC,CAAC,CAAA;AACN,CAAC,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from "./models/EmailAddress";
2
+ export * from "./classes/Email";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAA;AACrC,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,gEAAqC;AACrC,0DAA+B"}
@@ -0,0 +1,14 @@
1
+ CREATE TABLE `email_addresses` (
2
+ `id` varchar(36) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
3
+ `email` varchar(255) DEFAULT NULL,
4
+ `organizationId` varchar(36) CHARACTER SET ascii COLLATE ascii_general_ci DEFAULT NULL,
5
+ `markedAsSpam` tinyint(1) DEFAULT NULL,
6
+ `hardBounce` tinyint(1) DEFAULT NULL,
7
+ `unsubscribedMarketing` tinyint(1) DEFAULT NULL,
8
+ `unsubscribedAll` tinyint(1) DEFAULT NULL,
9
+ `token` varchar(255) CHARACTER SET ascii COLLATE ascii_general_ci DEFAULT NULL,
10
+ `createdAt` datetime NOT NULL,
11
+ `updatedAt` datetime NOT NULL,
12
+ PRIMARY KEY (`id`),
13
+ UNIQUE KEY `email` (`email`,`organizationId`) USING BTREE
14
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
@@ -0,0 +1,5 @@
1
+ set foreign_key_checks=0;
2
+ ALTER TABLE `email_addresses` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
3
+ ALTER TABLE `email_addresses` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
4
+ ALTER DATABASE CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
5
+ set foreign_key_checks=1;
@@ -0,0 +1,23 @@
1
+ import { Model } from '@simonbackx/simple-database';
2
+ import { EmailInterfaceRecipient } from '../classes/Email';
3
+ export declare class EmailAddress extends Model {
4
+ static table: string;
5
+ id: string;
6
+ organizationId: string | null;
7
+ email: string;
8
+ markedAsSpam: boolean;
9
+ hardBounce: boolean;
10
+ unsubscribedMarketing: boolean;
11
+ unsubscribedAll: boolean;
12
+ token: string | null;
13
+ /**
14
+ * createdAt behaves more like createdAt for Challenge. Since every save is considered to have a new challenge
15
+ */
16
+ createdAt: Date;
17
+ updatedAt: Date;
18
+ static getOrCreate(email: string, organizationId: string | null): Promise<EmailAddress>;
19
+ static getByEmails(emails: string[], organizationId: string | null): Promise<EmailAddress[]>;
20
+ static getByEmail(email: string, organizationId: string | null): Promise<EmailAddress | undefined>;
21
+ static filterSendTo(recipients: EmailInterfaceRecipient[]): Promise<EmailInterfaceRecipient[]>;
22
+ }
23
+ //# sourceMappingURL=EmailAddress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailAddress.d.ts","sourceRoot":"","sources":["../../src/models/EmailAddress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAItE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAc3D,qBAAa,YAAa,SAAQ,KAAK;IACnC,MAAM,CAAC,KAAK,SAAqB;IAOjC,EAAE,EAAG,MAAM,CAAC;IAGZ,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IAIrC,KAAK,EAAE,MAAM,CAAC;IAGd,YAAY,UAAS;IAGrB,UAAU,UAAS;IAGnB,qBAAqB,UAAS;IAG9B,eAAe,UAAS;IAGxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAErB;;OAEG;IAQH,SAAS,EAAE,IAAI,CAAA;IASf,SAAS,EAAE,IAAI,CAAA;WAEF,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;WAoBhF,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;WA6BrF,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;WAK3F,YAAY,CAAC,UAAU,EAAE,uBAAuB,EAAE,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC;CAkBvG"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EmailAddress = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const simple_database_1 = require("@simonbackx/simple-database");
6
+ const crypto_1 = tslib_1.__importDefault(require("crypto"));
7
+ const uuid_1 = require("uuid");
8
+ const queues_1 = require("@stamhoofd/queues");
9
+ async function randomBytes(size) {
10
+ return new Promise((resolve, reject) => {
11
+ crypto_1.default.randomBytes(size, (err, buf) => {
12
+ if (err) {
13
+ reject(err);
14
+ return;
15
+ }
16
+ resolve(buf);
17
+ });
18
+ });
19
+ }
20
+ class EmailAddress extends simple_database_1.Model {
21
+ constructor() {
22
+ super(...arguments);
23
+ this.organizationId = null;
24
+ this.markedAsSpam = false;
25
+ this.hardBounce = false;
26
+ this.unsubscribedMarketing = false;
27
+ this.unsubscribedAll = false;
28
+ }
29
+ static async getOrCreate(email, organizationId) {
30
+ // Prevent race conditions when checking the same email address at the same time, and creating a new one
31
+ return await queues_1.QueueHandler.schedule("email-address/create-" + email + '-' + organizationId, async () => {
32
+ const existing = await this.getByEmail(email, organizationId);
33
+ if (existing) {
34
+ return existing;
35
+ }
36
+ const n = new EmailAddress();
37
+ n.organizationId = organizationId;
38
+ n.email = email;
39
+ n.token = (await randomBytes(64)).toString("base64").toUpperCase();
40
+ await n.save();
41
+ return n;
42
+ });
43
+ }
44
+ // Methods
45
+ static async getByEmails(emails, organizationId) {
46
+ if (emails.length > 30) {
47
+ // Normally an organization will never have so much bounces, so we'll request all emails and filter in them
48
+ const all = await this.where({ organizationId }, { limit: 1000 });
49
+ return all.filter(e => emails.includes(e.email));
50
+ }
51
+ if (emails.length == 0) {
52
+ return [];
53
+ }
54
+ if (organizationId === null) {
55
+ const [rows] = await simple_database_1.Database.select(`SELECT ${this.getDefaultSelect()} FROM ${this.table} WHERE \`email\` IN (?) AND \`organizationId\` is NULL`, [emails]);
56
+ return this.fromRows(rows, this.table);
57
+ }
58
+ const [rows] = await simple_database_1.Database.select(`SELECT ${this.getDefaultSelect()} FROM ${this.table} WHERE \`email\` IN (?) AND \`organizationId\` = ?`, [emails, organizationId]);
59
+ return this.fromRows(rows, this.table);
60
+ }
61
+ // Methods
62
+ static async getByEmail(email, organizationId) {
63
+ return (await this.where({ email, organizationId }, { limit: 1 }))[0];
64
+ }
65
+ // Methods
66
+ static async filterSendTo(recipients) {
67
+ if (recipients.length == 0) {
68
+ return [];
69
+ }
70
+ const emails = recipients.map(r => r.email);
71
+ const [results] = await simple_database_1.Database.select(`SELECT email FROM ${this.table} WHERE \`email\` IN (?) AND (\`hardBounce\` = 1 OR \`markedAsSpam\` = 1)`, [emails]);
72
+ const remove = results.map(r => r[this.table]['email']);
73
+ if (remove.length == 0) {
74
+ return recipients;
75
+ }
76
+ return recipients.filter(r => !remove.includes(r.email));
77
+ }
78
+ }
79
+ exports.EmailAddress = EmailAddress;
80
+ EmailAddress.table = "email_addresses";
81
+ tslib_1.__decorate([
82
+ (0, simple_database_1.column)({
83
+ primary: true, type: "string", beforeSave(value) {
84
+ return value !== null && value !== void 0 ? value : (0, uuid_1.v4)();
85
+ }
86
+ })
87
+ ], EmailAddress.prototype, "id", void 0);
88
+ tslib_1.__decorate([
89
+ (0, simple_database_1.column)({ type: "string", nullable: true })
90
+ ], EmailAddress.prototype, "organizationId", void 0);
91
+ tslib_1.__decorate([
92
+ (0, simple_database_1.column)({ type: "string" })
93
+ ], EmailAddress.prototype, "email", void 0);
94
+ tslib_1.__decorate([
95
+ (0, simple_database_1.column)({ type: "boolean" })
96
+ ], EmailAddress.prototype, "markedAsSpam", void 0);
97
+ tslib_1.__decorate([
98
+ (0, simple_database_1.column)({ type: "boolean" })
99
+ ], EmailAddress.prototype, "hardBounce", void 0);
100
+ tslib_1.__decorate([
101
+ (0, simple_database_1.column)({ type: "boolean" })
102
+ ], EmailAddress.prototype, "unsubscribedMarketing", void 0);
103
+ tslib_1.__decorate([
104
+ (0, simple_database_1.column)({ type: "boolean" })
105
+ ], EmailAddress.prototype, "unsubscribedAll", void 0);
106
+ tslib_1.__decorate([
107
+ (0, simple_database_1.column)({ type: "string", nullable: true })
108
+ ], EmailAddress.prototype, "token", void 0);
109
+ tslib_1.__decorate([
110
+ (0, simple_database_1.column)({
111
+ type: "datetime", beforeSave() {
112
+ const date = new Date();
113
+ date.setMilliseconds(0);
114
+ return date;
115
+ }
116
+ })
117
+ ], EmailAddress.prototype, "createdAt", void 0);
118
+ tslib_1.__decorate([
119
+ (0, simple_database_1.column)({
120
+ type: "datetime", beforeSave() {
121
+ const date = new Date();
122
+ date.setMilliseconds(0);
123
+ return date;
124
+ }
125
+ })
126
+ ], EmailAddress.prototype, "updatedAt", void 0);
127
+ //# sourceMappingURL=EmailAddress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailAddress.js","sourceRoot":"","sources":["../../src/models/EmailAddress.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@stamhoofd/email",
3
- "version": "2.1.3",
3
+ "version": "2.3.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "license": "UNLICENCED",
7
7
  "sideEffects": false,
8
8
  "files": [
9
- "src"
9
+ "src",
10
+ "dist"
10
11
  ],
11
12
  "scripts": {
12
13
  "build": "tsc -b && mkdir -p ./dist/migrations && cp ./src/migrations/*.sql ./dist/migrations",
@@ -22,5 +23,5 @@
22
23
  "html-to-text": "^8.1.0",
23
24
  "nodemailer": "6.9.13"
24
25
  },
25
- "gitHead": "b5773c547dceaae52b9c2a098b222417fcd42e4f"
26
+ "gitHead": "558516ab829f9a35ded06b8982991b1445a22c2c"
26
27
  }
@@ -0,0 +1,5 @@
1
+ set foreign_key_checks=0;
2
+ ALTER TABLE `email_addresses` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
3
+ ALTER TABLE `email_addresses` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
4
+ ALTER DATABASE CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
5
+ set foreign_key_checks=1;