@vynelix/vynemit-adapter-smtp 1.0.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/dist/index.d.ts +1 -0
- package/dist/index.js +17 -0
- package/dist/smtp.adapter.d.ts +19 -0
- package/dist/smtp.adapter.js +98 -0
- package/jest.config.js +6 -0
- package/package.json +33 -0
- package/tsconfig.json +23 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './smtp.adapter';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./smtp.adapter"), exports);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DeliveryReceipt, TransportAdapter, ChannelType, NotificationPreferences, EmailNotification } from '@vynelix/vynemit-core';
|
|
2
|
+
export declare class SmtpProvider implements TransportAdapter {
|
|
3
|
+
private transporter;
|
|
4
|
+
name: ChannelType;
|
|
5
|
+
private fromEmail;
|
|
6
|
+
constructor({ host, port, user, pass, fromEmail }: {
|
|
7
|
+
host: string;
|
|
8
|
+
port: number;
|
|
9
|
+
user: string;
|
|
10
|
+
pass: string;
|
|
11
|
+
fromEmail: string;
|
|
12
|
+
});
|
|
13
|
+
sendBatch(notifications: EmailNotification[], preferences: NotificationPreferences): Promise<DeliveryReceipt[]>;
|
|
14
|
+
canSend(notification: EmailNotification, preferences: NotificationPreferences): boolean;
|
|
15
|
+
send(notification: EmailNotification, preferences: NotificationPreferences): Promise<DeliveryReceipt>;
|
|
16
|
+
private resolveEmail;
|
|
17
|
+
private isValidEmail;
|
|
18
|
+
healthCheck(): Promise<boolean>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SmtpProvider = void 0;
|
|
7
|
+
const nodemailer_1 = __importDefault(require("nodemailer"));
|
|
8
|
+
class SmtpProvider {
|
|
9
|
+
constructor({ host, port, user, pass, fromEmail }) {
|
|
10
|
+
this.name = 'email';
|
|
11
|
+
this.fromEmail = fromEmail;
|
|
12
|
+
console.log(`[SMTP] Initializing SmtpProvider for ${host}:${port} (from: ${fromEmail})`);
|
|
13
|
+
this.transporter = nodemailer_1.default.createTransport({
|
|
14
|
+
host,
|
|
15
|
+
port,
|
|
16
|
+
secure: port === 465,
|
|
17
|
+
auth: { user, pass },
|
|
18
|
+
connectionTimeout: 5000, // 5 seconds
|
|
19
|
+
greetingTimeout: 5000,
|
|
20
|
+
socketTimeout: 5000,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async sendBatch(notifications, preferences) {
|
|
24
|
+
return Promise.all(notifications.map(notification => this.send(notification, preferences)));
|
|
25
|
+
}
|
|
26
|
+
canSend(notification, preferences) {
|
|
27
|
+
const email = this.resolveEmail(notification, preferences);
|
|
28
|
+
return !!email && this.isValidEmail(email);
|
|
29
|
+
}
|
|
30
|
+
async send(notification, preferences) {
|
|
31
|
+
try {
|
|
32
|
+
const email = this.resolveEmail(notification, preferences);
|
|
33
|
+
if (!email) {
|
|
34
|
+
console.error('[SMTP] Recipient email address not found');
|
|
35
|
+
throw new Error('Recipient email address not found');
|
|
36
|
+
}
|
|
37
|
+
console.log(`[SMTP] Attempting to send email via SMTP to: ${email}`);
|
|
38
|
+
const info = await this.transporter.sendMail({
|
|
39
|
+
from: this.fromEmail,
|
|
40
|
+
to: email,
|
|
41
|
+
subject: notification.title,
|
|
42
|
+
text: notification.text || notification.body,
|
|
43
|
+
html: notification.html || notification.body,
|
|
44
|
+
});
|
|
45
|
+
console.log(`[SMTP] Email sent successfully. MessageID: ${info.messageId}`);
|
|
46
|
+
return {
|
|
47
|
+
notificationId: notification.id,
|
|
48
|
+
channel: 'email',
|
|
49
|
+
status: 'sent',
|
|
50
|
+
attempts: 1,
|
|
51
|
+
lastAttempt: new Date(),
|
|
52
|
+
metadata: {
|
|
53
|
+
messageId: info.messageId,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error(`[SMTP] Error sending email to ${notification.data?.email}:`, error);
|
|
59
|
+
return {
|
|
60
|
+
notificationId: notification.id,
|
|
61
|
+
channel: 'email',
|
|
62
|
+
status: 'failed',
|
|
63
|
+
attempts: 1,
|
|
64
|
+
lastAttempt: new Date(),
|
|
65
|
+
error: error.message,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
resolveEmail(notification, preferences) {
|
|
70
|
+
// 1. Check notification data
|
|
71
|
+
if (notification.data?.email && typeof notification.data.email === 'string') {
|
|
72
|
+
return notification.data.email;
|
|
73
|
+
}
|
|
74
|
+
// 2. Check user preferences
|
|
75
|
+
if (preferences?.data?.email && typeof preferences.data.email === 'string') {
|
|
76
|
+
return preferences.data.email;
|
|
77
|
+
}
|
|
78
|
+
// 3. Fallback to userId if it looks like an email
|
|
79
|
+
if (this.isValidEmail(notification.userId)) {
|
|
80
|
+
return notification.userId;
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
isValidEmail(email) {
|
|
85
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
86
|
+
return emailRegex.test(email);
|
|
87
|
+
}
|
|
88
|
+
async healthCheck() {
|
|
89
|
+
try {
|
|
90
|
+
await this.transporter.verify();
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.SmtpProvider = SmtpProvider;
|
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vynelix/vynemit-adapter-smtp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"test": "jest",
|
|
9
|
+
"test:watch": "jest --watch"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/IsaiahTek/vynemit.git",
|
|
14
|
+
"directory": "packages/adapter-smtp"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/IsaiahTek/vynemit/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/IsaiahTek/vynemit#readme",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"nodemailer": "^6.9.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@vynelix/vynemit-core": "*"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/jest": "^29.5.0",
|
|
28
|
+
"@types/nodemailer": "^6.4.7",
|
|
29
|
+
"jest": "^29.5.0",
|
|
30
|
+
"ts-jest": "^29.1.0",
|
|
31
|
+
"typescript": "^5.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2020"
|
|
7
|
+
],
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"src/**/*"
|
|
18
|
+
],
|
|
19
|
+
"exclude": [
|
|
20
|
+
"node_modules",
|
|
21
|
+
"dist"
|
|
22
|
+
]
|
|
23
|
+
}
|