@push.rocks/smartmta 5.1.2 → 5.2.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/changelog.md +14 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/index.d.ts +3 -0
- package/dist_ts/index.js +4 -0
- package/dist_ts/logger.d.ts +17 -0
- package/dist_ts/logger.js +76 -0
- package/dist_ts/mail/core/classes.bouncemanager.d.ts +185 -0
- package/dist_ts/mail/core/classes.bouncemanager.js +569 -0
- package/dist_ts/mail/core/classes.email.d.ts +291 -0
- package/dist_ts/mail/core/classes.email.js +802 -0
- package/dist_ts/mail/core/classes.emailvalidator.d.ts +61 -0
- package/dist_ts/mail/core/classes.emailvalidator.js +184 -0
- package/dist_ts/mail/core/classes.templatemanager.d.ts +95 -0
- package/dist_ts/mail/core/classes.templatemanager.js +240 -0
- package/dist_ts/mail/core/index.d.ts +4 -0
- package/dist_ts/mail/core/index.js +6 -0
- package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
- package/dist_ts/mail/delivery/classes.delivery.queue.js +488 -0
- package/dist_ts/mail/delivery/classes.delivery.system.d.ts +160 -0
- package/dist_ts/mail/delivery/classes.delivery.system.js +630 -0
- package/dist_ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
- package/dist_ts/mail/delivery/classes.unified.rate.limiter.js +820 -0
- package/dist_ts/mail/delivery/index.d.ts +4 -0
- package/dist_ts/mail/delivery/index.js +6 -0
- package/dist_ts/mail/delivery/interfaces.d.ts +140 -0
- package/dist_ts/mail/delivery/interfaces.js +17 -0
- package/dist_ts/mail/index.d.ts +7 -0
- package/dist_ts/mail/index.js +12 -0
- package/dist_ts/mail/routing/classes.dkim.manager.d.ts +25 -0
- package/dist_ts/mail/routing/classes.dkim.manager.js +127 -0
- package/dist_ts/mail/routing/classes.dns.manager.d.ts +79 -0
- package/dist_ts/mail/routing/classes.dns.manager.js +415 -0
- package/dist_ts/mail/routing/classes.domain.registry.d.ts +54 -0
- package/dist_ts/mail/routing/classes.domain.registry.js +119 -0
- package/dist_ts/mail/routing/classes.email.action.executor.d.ts +33 -0
- package/dist_ts/mail/routing/classes.email.action.executor.js +137 -0
- package/dist_ts/mail/routing/classes.email.router.d.ts +171 -0
- package/dist_ts/mail/routing/classes.email.router.js +494 -0
- package/dist_ts/mail/routing/classes.unified.email.server.d.ts +241 -0
- package/dist_ts/mail/routing/classes.unified.email.server.js +935 -0
- package/dist_ts/mail/routing/index.d.ts +7 -0
- package/dist_ts/mail/routing/index.js +9 -0
- package/dist_ts/mail/routing/interfaces.d.ts +187 -0
- package/dist_ts/mail/routing/interfaces.js +2 -0
- package/dist_ts/mail/security/classes.dkimcreator.d.ts +72 -0
- package/dist_ts/mail/security/classes.dkimcreator.js +360 -0
- package/dist_ts/mail/security/classes.spfverifier.d.ts +62 -0
- package/dist_ts/mail/security/classes.spfverifier.js +87 -0
- package/dist_ts/mail/security/index.d.ts +2 -0
- package/dist_ts/mail/security/index.js +4 -0
- package/dist_ts/paths.d.ts +14 -0
- package/dist_ts/paths.js +39 -0
- package/dist_ts/plugins.d.ts +24 -0
- package/dist_ts/plugins.js +28 -0
- package/dist_ts/security/classes.contentscanner.d.ts +130 -0
- package/dist_ts/security/classes.contentscanner.js +338 -0
- package/dist_ts/security/classes.ipreputationchecker.d.ts +73 -0
- package/dist_ts/security/classes.ipreputationchecker.js +263 -0
- package/dist_ts/security/classes.rustsecuritybridge.d.ts +398 -0
- package/dist_ts/security/classes.rustsecuritybridge.js +484 -0
- package/dist_ts/security/classes.securitylogger.d.ts +140 -0
- package/dist_ts/security/classes.securitylogger.js +235 -0
- package/dist_ts/security/index.d.ts +4 -0
- package/dist_ts/security/index.js +5 -0
- package/package.json +6 -1
- package/readme.md +52 -9
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/index.ts +3 -0
- package/ts/logger.ts +91 -0
- package/ts/mail/core/classes.bouncemanager.ts +731 -0
- package/ts/mail/core/classes.email.ts +942 -0
- package/ts/mail/core/classes.emailvalidator.ts +239 -0
- package/ts/mail/core/classes.templatemanager.ts +320 -0
- package/ts/mail/core/index.ts +5 -0
- package/ts/mail/delivery/classes.delivery.queue.ts +645 -0
- package/ts/mail/delivery/classes.delivery.system.ts +816 -0
- package/ts/mail/delivery/classes.unified.rate.limiter.ts +1053 -0
- package/ts/mail/delivery/index.ts +5 -0
- package/ts/mail/delivery/interfaces.ts +167 -0
- package/ts/mail/index.ts +17 -0
- package/ts/mail/routing/classes.dkim.manager.ts +157 -0
- package/ts/mail/routing/classes.dns.manager.ts +573 -0
- package/ts/mail/routing/classes.domain.registry.ts +139 -0
- package/ts/mail/routing/classes.email.action.executor.ts +175 -0
- package/ts/mail/routing/classes.email.router.ts +575 -0
- package/ts/mail/routing/classes.unified.email.server.ts +1207 -0
- package/ts/mail/routing/index.ts +9 -0
- package/ts/mail/routing/interfaces.ts +202 -0
- package/ts/mail/security/classes.dkimcreator.ts +447 -0
- package/ts/mail/security/classes.spfverifier.ts +126 -0
- package/ts/mail/security/index.ts +3 -0
- package/ts/paths.ts +48 -0
- package/ts/plugins.ts +53 -0
- package/ts/security/classes.contentscanner.ts +400 -0
- package/ts/security/classes.ipreputationchecker.ts +315 -0
- package/ts/security/classes.rustsecuritybridge.ts +943 -0
- package/ts/security/classes.securitylogger.ts +299 -0
- package/ts/security/index.ts +40 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Log level for security events
|
|
5
|
+
*/
|
|
6
|
+
export var SecurityLogLevel;
|
|
7
|
+
(function (SecurityLogLevel) {
|
|
8
|
+
SecurityLogLevel["INFO"] = "info";
|
|
9
|
+
SecurityLogLevel["WARN"] = "warn";
|
|
10
|
+
SecurityLogLevel["ERROR"] = "error";
|
|
11
|
+
SecurityLogLevel["CRITICAL"] = "critical";
|
|
12
|
+
})(SecurityLogLevel || (SecurityLogLevel = {}));
|
|
13
|
+
/**
|
|
14
|
+
* Security event types for categorization
|
|
15
|
+
*/
|
|
16
|
+
export var SecurityEventType;
|
|
17
|
+
(function (SecurityEventType) {
|
|
18
|
+
SecurityEventType["AUTHENTICATION"] = "authentication";
|
|
19
|
+
SecurityEventType["ACCESS_CONTROL"] = "access_control";
|
|
20
|
+
SecurityEventType["EMAIL_VALIDATION"] = "email_validation";
|
|
21
|
+
SecurityEventType["EMAIL_PROCESSING"] = "email_processing";
|
|
22
|
+
SecurityEventType["EMAIL_FORWARDING"] = "email_forwarding";
|
|
23
|
+
SecurityEventType["EMAIL_DELIVERY"] = "email_delivery";
|
|
24
|
+
SecurityEventType["DKIM"] = "dkim";
|
|
25
|
+
SecurityEventType["SPF"] = "spf";
|
|
26
|
+
SecurityEventType["DMARC"] = "dmarc";
|
|
27
|
+
SecurityEventType["RATE_LIMIT"] = "rate_limit";
|
|
28
|
+
SecurityEventType["RATE_LIMITING"] = "rate_limiting";
|
|
29
|
+
SecurityEventType["SPAM"] = "spam";
|
|
30
|
+
SecurityEventType["MALWARE"] = "malware";
|
|
31
|
+
SecurityEventType["CONNECTION"] = "connection";
|
|
32
|
+
SecurityEventType["DATA_EXPOSURE"] = "data_exposure";
|
|
33
|
+
SecurityEventType["CONFIGURATION"] = "configuration";
|
|
34
|
+
SecurityEventType["IP_REPUTATION"] = "ip_reputation";
|
|
35
|
+
SecurityEventType["REJECTED_CONNECTION"] = "rejected_connection";
|
|
36
|
+
})(SecurityEventType || (SecurityEventType = {}));
|
|
37
|
+
/**
|
|
38
|
+
* Security logger for enhanced security monitoring
|
|
39
|
+
*/
|
|
40
|
+
export class SecurityLogger {
|
|
41
|
+
static instance;
|
|
42
|
+
securityEvents = [];
|
|
43
|
+
maxEventHistory;
|
|
44
|
+
enableNotifications;
|
|
45
|
+
constructor(options) {
|
|
46
|
+
this.maxEventHistory = options?.maxEventHistory || 1000;
|
|
47
|
+
this.enableNotifications = options?.enableNotifications || false;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get singleton instance
|
|
51
|
+
*/
|
|
52
|
+
static getInstance(options) {
|
|
53
|
+
if (!SecurityLogger.instance) {
|
|
54
|
+
SecurityLogger.instance = new SecurityLogger(options);
|
|
55
|
+
}
|
|
56
|
+
return SecurityLogger.instance;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Log a security event
|
|
60
|
+
* @param event The security event to log
|
|
61
|
+
*/
|
|
62
|
+
logEvent(event) {
|
|
63
|
+
const fullEvent = {
|
|
64
|
+
...event,
|
|
65
|
+
timestamp: Date.now()
|
|
66
|
+
};
|
|
67
|
+
// Store in memory buffer
|
|
68
|
+
this.securityEvents.push(fullEvent);
|
|
69
|
+
// Trim history if needed
|
|
70
|
+
if (this.securityEvents.length > this.maxEventHistory) {
|
|
71
|
+
this.securityEvents.shift();
|
|
72
|
+
}
|
|
73
|
+
// Log to regular logger with appropriate level
|
|
74
|
+
switch (event.level) {
|
|
75
|
+
case SecurityLogLevel.INFO:
|
|
76
|
+
logger.log('info', `[SECURITY:${event.type}] ${event.message}`, event.details);
|
|
77
|
+
break;
|
|
78
|
+
case SecurityLogLevel.WARN:
|
|
79
|
+
logger.log('warn', `[SECURITY:${event.type}] ${event.message}`, event.details);
|
|
80
|
+
break;
|
|
81
|
+
case SecurityLogLevel.ERROR:
|
|
82
|
+
case SecurityLogLevel.CRITICAL:
|
|
83
|
+
logger.log('error', `[SECURITY:${event.type}] ${event.message}`, event.details);
|
|
84
|
+
// Send notification for critical events if enabled
|
|
85
|
+
if (event.level === SecurityLogLevel.CRITICAL && this.enableNotifications) {
|
|
86
|
+
this.sendNotification(fullEvent);
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get recent security events
|
|
93
|
+
* @param limit Maximum number of events to return
|
|
94
|
+
* @param filter Filter for specific event types
|
|
95
|
+
* @returns Recent security events
|
|
96
|
+
*/
|
|
97
|
+
getRecentEvents(limit = 100, filter) {
|
|
98
|
+
let filteredEvents = this.securityEvents;
|
|
99
|
+
// Apply filters
|
|
100
|
+
if (filter) {
|
|
101
|
+
if (filter.level) {
|
|
102
|
+
filteredEvents = filteredEvents.filter(event => event.level === filter.level);
|
|
103
|
+
}
|
|
104
|
+
if (filter.type) {
|
|
105
|
+
filteredEvents = filteredEvents.filter(event => event.type === filter.type);
|
|
106
|
+
}
|
|
107
|
+
if (filter.fromTimestamp) {
|
|
108
|
+
filteredEvents = filteredEvents.filter(event => event.timestamp >= filter.fromTimestamp);
|
|
109
|
+
}
|
|
110
|
+
if (filter.toTimestamp) {
|
|
111
|
+
filteredEvents = filteredEvents.filter(event => event.timestamp <= filter.toTimestamp);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Return most recent events up to limit
|
|
115
|
+
return filteredEvents
|
|
116
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
117
|
+
.slice(0, limit);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get events by security level
|
|
121
|
+
* @param level The security level to filter by
|
|
122
|
+
* @param limit Maximum number of events to return
|
|
123
|
+
* @returns Security events matching the level
|
|
124
|
+
*/
|
|
125
|
+
getEventsByLevel(level, limit = 100) {
|
|
126
|
+
return this.getRecentEvents(limit, { level });
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get events by security type
|
|
130
|
+
* @param type The event type to filter by
|
|
131
|
+
* @param limit Maximum number of events to return
|
|
132
|
+
* @returns Security events matching the type
|
|
133
|
+
*/
|
|
134
|
+
getEventsByType(type, limit = 100) {
|
|
135
|
+
return this.getRecentEvents(limit, { type });
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get security events for a specific IP address
|
|
139
|
+
* @param ipAddress The IP address to filter by
|
|
140
|
+
* @param limit Maximum number of events to return
|
|
141
|
+
* @returns Security events for the IP address
|
|
142
|
+
*/
|
|
143
|
+
getEventsByIP(ipAddress, limit = 100) {
|
|
144
|
+
return this.securityEvents
|
|
145
|
+
.filter(event => event.ipAddress === ipAddress)
|
|
146
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
147
|
+
.slice(0, limit);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get security events for a specific domain
|
|
151
|
+
* @param domain The domain to filter by
|
|
152
|
+
* @param limit Maximum number of events to return
|
|
153
|
+
* @returns Security events for the domain
|
|
154
|
+
*/
|
|
155
|
+
getEventsByDomain(domain, limit = 100) {
|
|
156
|
+
return this.securityEvents
|
|
157
|
+
.filter(event => event.domain === domain)
|
|
158
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
159
|
+
.slice(0, limit);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Send a notification for critical security events
|
|
163
|
+
* @param event The security event to notify about
|
|
164
|
+
* @private
|
|
165
|
+
*/
|
|
166
|
+
sendNotification(event) {
|
|
167
|
+
// In a production environment, this would integrate with a notification service
|
|
168
|
+
// For now, we'll just log that we would send a notification
|
|
169
|
+
logger.log('error', `[SECURITY NOTIFICATION] ${event.message}`, {
|
|
170
|
+
...event,
|
|
171
|
+
notificationSent: true
|
|
172
|
+
});
|
|
173
|
+
// Future integration with alerting systems would go here
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Clear event history
|
|
177
|
+
*/
|
|
178
|
+
clearEvents() {
|
|
179
|
+
this.securityEvents = [];
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get statistical summary of security events
|
|
183
|
+
* @param timeWindow Optional time window in milliseconds
|
|
184
|
+
* @returns Summary of security events
|
|
185
|
+
*/
|
|
186
|
+
getEventsSummary(timeWindow) {
|
|
187
|
+
// Filter by time window if provided
|
|
188
|
+
let events = this.securityEvents;
|
|
189
|
+
if (timeWindow) {
|
|
190
|
+
const cutoff = Date.now() - timeWindow;
|
|
191
|
+
events = events.filter(e => e.timestamp >= cutoff);
|
|
192
|
+
}
|
|
193
|
+
// Count by level
|
|
194
|
+
const byLevel = Object.values(SecurityLogLevel).reduce((acc, level) => {
|
|
195
|
+
acc[level] = events.filter(e => e.level === level).length;
|
|
196
|
+
return acc;
|
|
197
|
+
}, {});
|
|
198
|
+
// Count by type
|
|
199
|
+
const byType = Object.values(SecurityEventType).reduce((acc, type) => {
|
|
200
|
+
acc[type] = events.filter(e => e.type === type).length;
|
|
201
|
+
return acc;
|
|
202
|
+
}, {});
|
|
203
|
+
// Count by IP
|
|
204
|
+
const ipCounts = new Map();
|
|
205
|
+
events.forEach(e => {
|
|
206
|
+
if (e.ipAddress) {
|
|
207
|
+
ipCounts.set(e.ipAddress, (ipCounts.get(e.ipAddress) || 0) + 1);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
// Count by domain
|
|
211
|
+
const domainCounts = new Map();
|
|
212
|
+
events.forEach(e => {
|
|
213
|
+
if (e.domain) {
|
|
214
|
+
domainCounts.set(e.domain, (domainCounts.get(e.domain) || 0) + 1);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
// Sort and limit top entries
|
|
218
|
+
const topIPs = Array.from(ipCounts.entries())
|
|
219
|
+
.map(([ip, count]) => ({ ip, count }))
|
|
220
|
+
.sort((a, b) => b.count - a.count)
|
|
221
|
+
.slice(0, 10);
|
|
222
|
+
const topDomains = Array.from(domainCounts.entries())
|
|
223
|
+
.map(([domain, count]) => ({ domain, count }))
|
|
224
|
+
.sort((a, b) => b.count - a.count)
|
|
225
|
+
.slice(0, 10);
|
|
226
|
+
return {
|
|
227
|
+
total: events.length,
|
|
228
|
+
byLevel,
|
|
229
|
+
byType,
|
|
230
|
+
topIPs,
|
|
231
|
+
topDomains
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zZWN1cml0eWxvZ2dlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3NlY3VyaXR5L2NsYXNzZXMuc2VjdXJpdHlsb2dnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV0Qzs7R0FFRztBQUNILE1BQU0sQ0FBTixJQUFZLGdCQUtYO0FBTEQsV0FBWSxnQkFBZ0I7SUFDMUIsaUNBQWEsQ0FBQTtJQUNiLGlDQUFhLENBQUE7SUFDYixtQ0FBZSxDQUFBO0lBQ2YseUNBQXFCLENBQUE7QUFDdkIsQ0FBQyxFQUxXLGdCQUFnQixLQUFoQixnQkFBZ0IsUUFLM0I7QUFFRDs7R0FFRztBQUNILE1BQU0sQ0FBTixJQUFZLGlCQW1CWDtBQW5CRCxXQUFZLGlCQUFpQjtJQUMzQixzREFBaUMsQ0FBQTtJQUNqQyxzREFBaUMsQ0FBQTtJQUNqQywwREFBcUMsQ0FBQTtJQUNyQywwREFBcUMsQ0FBQTtJQUNyQywwREFBcUMsQ0FBQTtJQUNyQyxzREFBaUMsQ0FBQTtJQUNqQyxrQ0FBYSxDQUFBO0lBQ2IsZ0NBQVcsQ0FBQTtJQUNYLG9DQUFlLENBQUE7SUFDZiw4Q0FBeUIsQ0FBQTtJQUN6QixvREFBK0IsQ0FBQTtJQUMvQixrQ0FBYSxDQUFBO0lBQ2Isd0NBQW1CLENBQUE7SUFDbkIsOENBQXlCLENBQUE7SUFDekIsb0RBQStCLENBQUE7SUFDL0Isb0RBQStCLENBQUE7SUFDL0Isb0RBQStCLENBQUE7SUFDL0IsZ0VBQTJDLENBQUE7QUFDN0MsQ0FBQyxFQW5CVyxpQkFBaUIsS0FBakIsaUJBQWlCLFFBbUI1QjtBQXFCRDs7R0FFRztBQUNILE1BQU0sT0FBTyxjQUFjO0lBQ2pCLE1BQU0sQ0FBQyxRQUFRLENBQWlCO0lBQ2hDLGNBQWMsR0FBcUIsRUFBRSxDQUFDO0lBQ3RDLGVBQWUsQ0FB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
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { SecurityLogger, SecurityLogLevel, SecurityEventType, type ISecurityEvent } from './classes.securitylogger.js';
|
|
2
|
+
export { IPReputationChecker, ReputationThreshold, IPType, type IReputationResult, type IIPReputationOptions } from './classes.ipreputationchecker.js';
|
|
3
|
+
export { ContentScanner, ThreatCategory, type IScanResult, type IContentScannerOptions } from './classes.contentscanner.js';
|
|
4
|
+
export { RustSecurityBridge, BridgeState, type IBridgeResilienceConfig, type IDkimVerificationResult, type ISpfResult, type IDmarcResult, type IEmailSecurityResult, type IValidationResult, type IBounceDetection, type IRustReputationResult, type IVersionInfo, type IOutboundEmail, type ISmtpSendResult, type ISmtpSendOptions, type ISmtpVerifyResult, type ISmtpPoolStatus, } from './classes.rustsecuritybridge.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SecurityLogger, SecurityLogLevel, SecurityEventType } from './classes.securitylogger.js';
|
|
2
|
+
export { IPReputationChecker, ReputationThreshold, IPType } from './classes.ipreputationchecker.js';
|
|
3
|
+
export { ContentScanner, ThreatCategory } from './classes.contentscanner.js';
|
|
4
|
+
export { RustSecurityBridge, BridgeState, } from './classes.rustsecuritybridge.js';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9zZWN1cml0eS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsY0FBYyxFQUNkLGdCQUFnQixFQUNoQixpQkFBaUIsRUFFbEIsTUFBTSw2QkFBNkIsQ0FBQztBQUVyQyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLG1CQUFtQixFQUNuQixNQUFNLEVBR1AsTUFBTSxrQ0FBa0MsQ0FBQztBQUUxQyxPQUFPLEVBQ0wsY0FBYyxFQUNkLGNBQWMsRUFHZixNQUFNLDZCQUE2QixDQUFDO0FBRXJDLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsV0FBVyxHQWVaLE1BQU0saUNBQWlDLENBQUMifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartmta",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "A high-performance, enterprise-grade Mail Transfer Agent (MTA) built from scratch in TypeScript with Rust acceleration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mta",
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"author": "Task Venture Capital GmbH",
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"type": "module",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": "./dist_ts/index.js"
|
|
32
|
+
},
|
|
30
33
|
"bin": {
|
|
31
34
|
"mailer": "./bin/mailer-wrapper.js"
|
|
32
35
|
},
|
|
@@ -56,6 +59,8 @@
|
|
|
56
59
|
"uuid": "^13.0.0"
|
|
57
60
|
},
|
|
58
61
|
"files": [
|
|
62
|
+
"ts/**/*",
|
|
63
|
+
"dist_ts/**/*",
|
|
59
64
|
"bin/",
|
|
60
65
|
"scripts/install-binary.js",
|
|
61
66
|
"dist_rust/**/*",
|
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @push.rocks/smartmta
|
|
2
2
|
|
|
3
|
-
A high-performance, enterprise-grade Mail Transfer Agent (MTA) built from scratch in TypeScript with a Rust-powered SMTP engine — no nodemailer, no shortcuts. 🚀
|
|
3
|
+
A high-performance, enterprise-grade Mail Transfer Agent (MTA) built from scratch in TypeScript with a Rust-powered SMTP engine — no nodemailer, no shortcuts. Automatic MX record discovery means you just call `sendEmail()` and smartmta figures out where to deliver. 🚀
|
|
4
4
|
|
|
5
5
|
## Issue Reporting and Security
|
|
6
6
|
|
|
@@ -78,9 +78,10 @@ After installation, run `pnpm build` to compile the Rust binary (`mailer-bin`).
|
|
|
78
78
|
|
|
79
79
|
**Data flow for outbound mail:**
|
|
80
80
|
|
|
81
|
-
1. 📝 TypeScript constructs the email and
|
|
82
|
-
2.
|
|
83
|
-
3.
|
|
81
|
+
1. 📝 TypeScript constructs the email and calls `sendEmail()` (defaults to MTA mode)
|
|
82
|
+
2. 🔍 MTA mode automatically resolves MX records for each recipient domain, sorts by priority, and groups recipients for efficient delivery
|
|
83
|
+
3. 🦀 Sends to Rust via IPC — Rust builds the RFC 2822 message, signs with DKIM, and delivers via its SMTP client with connection pooling
|
|
84
|
+
4. 📬 Result (accepted/rejected recipients, server response) returned to TypeScript
|
|
84
85
|
|
|
85
86
|
## Usage
|
|
86
87
|
|
|
@@ -169,9 +170,9 @@ await emailServer.start();
|
|
|
169
170
|
|
|
170
171
|
> 🔒 **Note:** `start()` will throw if the Rust binary is not compiled. Run `pnpm build` first.
|
|
171
172
|
|
|
172
|
-
### 📧 Sending
|
|
173
|
+
### 📧 Sending Emails (Automatic MX Discovery)
|
|
173
174
|
|
|
174
|
-
|
|
175
|
+
The recommended way to send email is `sendEmail()`. It defaults to **MTA mode**, which automatically resolves MX records for each recipient domain via DNS — you don't need to know the destination mail server:
|
|
175
176
|
|
|
176
177
|
```typescript
|
|
177
178
|
import { Email, UnifiedEmailServer } from '@push.rocks/smartmta';
|
|
@@ -179,8 +180,7 @@ import { Email, UnifiedEmailServer } from '@push.rocks/smartmta';
|
|
|
179
180
|
// Build an email
|
|
180
181
|
const email = new Email({
|
|
181
182
|
from: 'sender@example.com',
|
|
182
|
-
to: ['
|
|
183
|
-
cc: ['cc@example.com'],
|
|
183
|
+
to: ['alice@gmail.com', 'bob@company.org'],
|
|
184
184
|
subject: 'Hello from smartmta! 🚀',
|
|
185
185
|
text: 'Plain text body',
|
|
186
186
|
html: '<h1>Hello!</h1><p>HTML body with <strong>formatting</strong></p>',
|
|
@@ -194,7 +194,50 @@ const email = new Email({
|
|
|
194
194
|
],
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
-
// Send
|
|
197
|
+
// Send — MTA mode auto-discovers MX servers for gmail.com and company.org
|
|
198
|
+
const emailId = await emailServer.sendEmail(email);
|
|
199
|
+
|
|
200
|
+
// Optionally specify a delivery mode explicitly
|
|
201
|
+
const emailId2 = await emailServer.sendEmail(email, 'mta');
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
In MTA mode, smartmta:
|
|
205
|
+
- 🔍 Resolves MX records for each recipient domain (e.g. `gmail.com`, `company.org`)
|
|
206
|
+
- 📊 Sorts MX hosts by priority (lowest = highest priority per RFC 5321)
|
|
207
|
+
- 🔄 Tries each MX host in order until delivery succeeds
|
|
208
|
+
- 🌐 Falls back to the domain's A record if no MX records exist
|
|
209
|
+
- 📦 Groups recipients by domain for efficient batch delivery
|
|
210
|
+
- 🔑 Signs outbound mail with DKIM automatically
|
|
211
|
+
|
|
212
|
+
### 📮 Delivery Modes
|
|
213
|
+
|
|
214
|
+
`sendEmail()` accepts a mode parameter that controls how the email is delivered:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
public async sendEmail(
|
|
218
|
+
email: Email,
|
|
219
|
+
mode: EmailProcessingMode = 'mta', // 'mta' | 'forward' | 'process'
|
|
220
|
+
route?: IEmailRoute,
|
|
221
|
+
options?: {
|
|
222
|
+
skipSuppressionCheck?: boolean;
|
|
223
|
+
ipAddress?: string;
|
|
224
|
+
isTransactional?: boolean;
|
|
225
|
+
}
|
|
226
|
+
): Promise<string>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
| Mode | Description |
|
|
230
|
+
|---|---|
|
|
231
|
+
| `mta` (default) | **Auto MX discovery** — resolves MX records via DNS, delivers directly to the recipient's mail server. No relay configuration needed. |
|
|
232
|
+
| `forward` | **Relay delivery** — forwards the email to a configured SMTP host (e.g. an internal mail gateway or third-party relay). |
|
|
233
|
+
| `process` | **Scan + deliver** — runs the content scanning / security pipeline first, then delivers via auto MX resolution. |
|
|
234
|
+
|
|
235
|
+
### 📬 Direct SMTP Delivery (Low-Level)
|
|
236
|
+
|
|
237
|
+
For cases where you know the exact target SMTP server (e.g. relaying to a specific host), use the lower-level `sendOutboundEmail()`:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// Send directly to a known SMTP server (bypasses MX resolution)
|
|
198
241
|
const result = await emailServer.sendOutboundEmail('smtp.example.com', 587, email, {
|
|
199
242
|
auth: { user: 'sender@example.com', pass: 'your-password' },
|
|
200
243
|
dkimDomain: 'example.com',
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* autocreated commitinfo by @push.rocks/commitinfo
|
|
3
|
+
*/
|
|
4
|
+
export const commitinfo = {
|
|
5
|
+
name: '@push.rocks/smartmta',
|
|
6
|
+
version: '5.2.0',
|
|
7
|
+
description: 'A high-performance, enterprise-grade Mail Transfer Agent (MTA) built from scratch in TypeScript with Rust acceleration.'
|
|
8
|
+
}
|
package/ts/index.ts
ADDED
package/ts/logger.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
|
|
4
|
+
// Map NODE_ENV to valid TEnvironment
|
|
5
|
+
const nodeEnv = process.env.NODE_ENV || 'production';
|
|
6
|
+
const envMap: Record<string, 'local' | 'test' | 'staging' | 'production'> = {
|
|
7
|
+
'development': 'local',
|
|
8
|
+
'test': 'test',
|
|
9
|
+
'staging': 'staging',
|
|
10
|
+
'production': 'production'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Default Smartlog instance
|
|
14
|
+
const baseLogger = new plugins.smartlog.Smartlog({
|
|
15
|
+
logContext: {
|
|
16
|
+
environment: envMap[nodeEnv] || 'production',
|
|
17
|
+
runtime: 'node',
|
|
18
|
+
zone: 'serve.zone',
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Extended logger compatible with the original enhanced logger API
|
|
23
|
+
class StandardLogger {
|
|
24
|
+
private defaultContext: Record<string, any> = {};
|
|
25
|
+
private correlationId: string | null = null;
|
|
26
|
+
|
|
27
|
+
constructor() {}
|
|
28
|
+
|
|
29
|
+
// Log methods
|
|
30
|
+
public log(level: 'error' | 'warn' | 'info' | 'success' | 'debug', message: string, context: Record<string, any> = {}) {
|
|
31
|
+
const combinedContext = {
|
|
32
|
+
...this.defaultContext,
|
|
33
|
+
...context
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
if (this.correlationId) {
|
|
37
|
+
combinedContext.correlation_id = this.correlationId;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
baseLogger.log(level, message, combinedContext);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public error(message: string, context: Record<string, any> = {}) {
|
|
44
|
+
this.log('error', message, context);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public warn(message: string, context: Record<string, any> = {}) {
|
|
48
|
+
this.log('warn', message, context);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public info(message: string, context: Record<string, any> = {}) {
|
|
52
|
+
this.log('info', message, context);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public success(message: string, context: Record<string, any> = {}) {
|
|
56
|
+
this.log('success', message, context);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public debug(message: string, context: Record<string, any> = {}) {
|
|
60
|
+
this.log('debug', message, context);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Context management
|
|
64
|
+
public setContext(context: Record<string, any>, overwrite: boolean = false) {
|
|
65
|
+
if (overwrite) {
|
|
66
|
+
this.defaultContext = context;
|
|
67
|
+
} else {
|
|
68
|
+
this.defaultContext = {
|
|
69
|
+
...this.defaultContext,
|
|
70
|
+
...context
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Correlation ID management
|
|
76
|
+
public setCorrelationId(id: string | null = null): string {
|
|
77
|
+
this.correlationId = id || randomUUID();
|
|
78
|
+
return this.correlationId;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public getCorrelationId(): string | null {
|
|
82
|
+
return this.correlationId;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public clearCorrelationId(): void {
|
|
86
|
+
this.correlationId = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Export a singleton instance
|
|
91
|
+
export const logger = new StandardLogger();
|