@push.rocks/smartmta 6.5.1 → 7.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/changelog.md +20 -0
- package/dist_rust/mailer-bin_linux_amd64 +0 -0
- package/dist_rust/mailer-bin_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +3 -0
- package/dist_ts/index.js +4 -1
- package/dist_ts/mail/core/classes.bouncemanager.d.ts +5 -12
- package/dist_ts/mail/core/classes.bouncemanager.js +27 -92
- package/dist_ts/mail/core/classes.email.js +2 -2
- package/dist_ts/mail/core/classes.templatemanager.d.ts +10 -6
- package/dist_ts/mail/core/classes.templatemanager.js +35 -51
- package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +15 -20
- package/dist_ts/mail/delivery/classes.delivery.queue.js +196 -114
- package/dist_ts/mail/delivery/classes.delivery.system.js +5 -5
- package/dist_ts/mail/interfaces.storage.d.ts +37 -6
- package/dist_ts/mail/interfaces.storage.js +33 -3
- package/dist_ts/mail/routing/classes.dkim.manager.d.ts +2 -2
- package/dist_ts/mail/routing/classes.dkim.manager.js +2 -3
- package/dist_ts/mail/routing/classes.dns.manager.d.ts +2 -2
- package/dist_ts/mail/routing/classes.dns.manager.js +1 -1
- package/dist_ts/mail/routing/classes.email.router.d.ts +2 -2
- package/dist_ts/mail/routing/classes.email.router.js +4 -5
- package/dist_ts/mail/routing/classes.unified.email.server.d.ts +8 -6
- package/dist_ts/mail/routing/classes.unified.email.server.js +12 -41
- package/dist_ts/mail/routing/interfaces.d.ts +0 -2
- package/dist_ts/mail/security/classes.dkimcreator.d.ts +15 -45
- package/dist_ts/mail/security/classes.dkimcreator.js +66 -294
- package/dist_ts/paths.d.ts +0 -12
- package/dist_ts/paths.js +3 -36
- package/dist_ts/plugins.d.ts +2 -5
- package/dist_ts/plugins.js +3 -6
- package/dist_ts/security/classes.contentscanner.js +1 -2
- package/dist_ts/security/classes.ipreputationchecker.d.ts +6 -6
- package/dist_ts/security/classes.ipreputationchecker.js +24 -84
- package/dist_ts/security/classes.rustsecuritybridge.d.ts +3 -3
- package/package.json +2 -3
- package/readme.md +12 -6
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +4 -0
- package/ts/mail/core/classes.bouncemanager.ts +31 -110
- package/ts/mail/core/classes.email.ts +1 -1
- package/ts/mail/core/classes.templatemanager.ts +42 -57
- package/ts/mail/delivery/classes.delivery.queue.ts +264 -135
- package/ts/mail/delivery/classes.delivery.system.ts +7 -5
- package/ts/mail/interfaces.storage.ts +64 -10
- package/ts/mail/routing/classes.dkim.manager.ts +3 -3
- package/ts/mail/routing/classes.dns.manager.ts +3 -3
- package/ts/mail/routing/classes.email.router.ts +6 -6
- package/ts/mail/routing/classes.unified.email.server.ts +23 -44
- package/ts/mail/routing/interfaces.ts +0 -2
- package/ts/mail/security/classes.dkimcreator.ts +104 -352
- package/ts/paths.ts +2 -41
- package/ts/plugins.ts +1 -6
- package/ts/security/classes.contentscanner.ts +0 -1
- package/ts/security/classes.ipreputationchecker.ts +26 -90
- package/ts/security/classes.rustsecuritybridge.ts +3 -3
|
@@ -719,11 +719,13 @@ export class MultiModeDeliverySystem extends EventEmitter {
|
|
|
719
719
|
const keySelector = mtaOptions.dkimOptions?.keySelector || 'default';
|
|
720
720
|
|
|
721
721
|
try {
|
|
722
|
-
// Ensure DKIM keys exist for the
|
|
723
|
-
await this.emailServer.dkimCreator.
|
|
722
|
+
// Ensure DKIM keys exist for the exact selector advertised in the signature.
|
|
723
|
+
await this.emailServer.dkimCreator.handleDKIMKeysForSelector(domainName, keySelector);
|
|
724
724
|
|
|
725
|
-
//
|
|
726
|
-
const dkimPrivateKey = (
|
|
725
|
+
// Load the private key for that same selector.
|
|
726
|
+
const dkimPrivateKey = (
|
|
727
|
+
await this.emailServer.dkimCreator.readDKIMKeysForSelector(domainName, keySelector)
|
|
728
|
+
).privateKey;
|
|
727
729
|
|
|
728
730
|
// Convert Email to raw format for signing
|
|
729
731
|
const rawEmail = email.toRFC822String();
|
|
@@ -840,4 +842,4 @@ export class MultiModeDeliverySystem extends EventEmitter {
|
|
|
840
842
|
public getStats(): IDeliveryStats {
|
|
841
843
|
return { ...this.stats };
|
|
842
844
|
}
|
|
843
|
-
}
|
|
845
|
+
}
|
|
@@ -1,13 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Durable storage for SmartMTA's small textual state.
|
|
3
|
+
*
|
|
4
|
+
* Implementations are supplied by the embedding application and are expected
|
|
5
|
+
* to use SmartData, SmartBucket, or another explicitly managed backend.
|
|
6
|
+
* SmartMTA never falls back to the local filesystem.
|
|
7
|
+
*/
|
|
8
|
+
export interface IStorageManager {
|
|
9
|
+
get(key: string): Promise<string | null>;
|
|
10
|
+
set(key: string, value: string): Promise<void>;
|
|
11
|
+
list(prefix: string): Promise<string[]>;
|
|
12
|
+
delete(key: string): Promise<void>;
|
|
6
13
|
}
|
|
7
14
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
/** Blob storage for queued messages and template attachments. */
|
|
16
|
+
export interface IBlobStorageManager {
|
|
17
|
+
get(key: string): Promise<Buffer | null>;
|
|
18
|
+
set(key: string, value: Buffer): Promise<void>;
|
|
19
|
+
list(prefix: string): Promise<string[]>;
|
|
20
|
+
delete(key: string): Promise<void>;
|
|
13
21
|
}
|
|
22
|
+
|
|
23
|
+
/** In-memory small-state store for tests and explicitly non-durable runtimes. */
|
|
24
|
+
export class MemoryStorageManager implements IStorageManager {
|
|
25
|
+
private readonly entries = new Map<string, string>();
|
|
26
|
+
|
|
27
|
+
public async get(key: string): Promise<string | null> {
|
|
28
|
+
return this.entries.get(key) ?? null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async set(key: string, value: string): Promise<void> {
|
|
32
|
+
this.entries.set(key, value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public async list(prefix: string): Promise<string[]> {
|
|
36
|
+
return [...this.entries.keys()].filter((key) => key.startsWith(prefix)).sort();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public async delete(key: string): Promise<void> {
|
|
40
|
+
this.entries.delete(key);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** In-memory blob store for tests and explicitly non-durable runtimes. */
|
|
45
|
+
export class MemoryBlobStorageManager implements IBlobStorageManager {
|
|
46
|
+
private readonly entries = new Map<string, Buffer>();
|
|
47
|
+
|
|
48
|
+
public async get(key: string): Promise<Buffer | null> {
|
|
49
|
+
const value = this.entries.get(key);
|
|
50
|
+
return value ? Buffer.from(value) : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async set(key: string, value: Buffer): Promise<void> {
|
|
54
|
+
this.entries.set(key, Buffer.from(value));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public async list(prefix: string): Promise<string[]> {
|
|
58
|
+
return [...this.entries.keys()].filter((key) => key.startsWith(prefix)).sort();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public async delete(key: string): Promise<void> {
|
|
62
|
+
this.entries.delete(key);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** @deprecated Use IStorageManager. */
|
|
67
|
+
export type IStorageManagerLike = IStorageManager;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { logger } from '../../logger.js';
|
|
2
2
|
import { DKIMCreator } from '../security/classes.dkimcreator.js';
|
|
3
|
-
import {
|
|
3
|
+
import type { IStorageManager } from '../interfaces.storage.js';
|
|
4
4
|
import { DomainRegistry } from './classes.domain.registry.js';
|
|
5
5
|
import { RustSecurityBridge } from '../../security/classes.rustsecuritybridge.js';
|
|
6
6
|
import { Email } from '../core/classes.email.js';
|
|
7
7
|
|
|
8
8
|
/** External DcRouter interface shape used by DkimManager */
|
|
9
9
|
interface DcRouter {
|
|
10
|
-
storageManager?:
|
|
10
|
+
storageManager?: IStorageManager;
|
|
11
11
|
dnsServer?: any;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -115,7 +115,7 @@ export class DkimManager {
|
|
|
115
115
|
|
|
116
116
|
logger.log('info', `DKIM DNS handler registered for new selector: ${newSelector}._domainkey.${domain}`);
|
|
117
117
|
|
|
118
|
-
if (
|
|
118
|
+
if (this.dcRouter.storageManager) {
|
|
119
119
|
await this.dcRouter.storageManager.set(
|
|
120
120
|
`/email/dkim/${domain}/public.key`,
|
|
121
121
|
keyPair.publicKey
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import type { IEmailDomainConfig } from './interfaces.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { IStorageManager } from '../interfaces.storage.js';
|
|
4
4
|
import { logger } from '../../logger.js';
|
|
5
5
|
/** External DcRouter interface shape used by DnsManager */
|
|
6
6
|
interface IDcRouterLike {
|
|
7
|
-
storageManager:
|
|
7
|
+
storageManager: IStorageManager;
|
|
8
8
|
dnsServer?: any;
|
|
9
9
|
options?: { dnsNsDomains?: string[]; dnsScopes?: string[] };
|
|
10
10
|
}
|
|
@@ -50,7 +50,7 @@ interface IDnsValidationRun {
|
|
|
50
50
|
*/
|
|
51
51
|
export class DnsManager {
|
|
52
52
|
private dcRouter: IDcRouterLike;
|
|
53
|
-
private storageManager:
|
|
53
|
+
private storageManager: IStorageManager;
|
|
54
54
|
private resolverFactory: () => IDnsResolver;
|
|
55
55
|
private activeResolvers = new Set<IDnsResolver>();
|
|
56
56
|
private activeValidation?: IDnsValidationRun;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import { EventEmitter } from 'node:events';
|
|
3
|
-
import {
|
|
3
|
+
import type { IStorageManager } from '../interfaces.storage.js';
|
|
4
4
|
import type { IEmailRoute, IEmailMatch, IEmailAction, IEmailContext } from './interfaces.js';
|
|
5
5
|
import type { Email } from '../core/classes.email.js';
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ import type { Email } from '../core/classes.email.js';
|
|
|
10
10
|
export class EmailRouter extends EventEmitter {
|
|
11
11
|
private routes: IEmailRoute[];
|
|
12
12
|
private patternCache: Map<string, boolean> = new Map();
|
|
13
|
-
private storageManager?:
|
|
13
|
+
private storageManager?: IStorageManager;
|
|
14
14
|
private persistChanges: boolean;
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -19,7 +19,7 @@ export class EmailRouter extends EventEmitter {
|
|
|
19
19
|
* @param options Router options
|
|
20
20
|
*/
|
|
21
21
|
constructor(routes: IEmailRoute[], options?: {
|
|
22
|
-
storageManager?:
|
|
22
|
+
storageManager?: IStorageManager;
|
|
23
23
|
persistChanges?: boolean;
|
|
24
24
|
}) {
|
|
25
25
|
super();
|
|
@@ -28,7 +28,7 @@ export class EmailRouter extends EventEmitter {
|
|
|
28
28
|
this.persistChanges = options?.persistChanges ?? !!this.storageManager;
|
|
29
29
|
|
|
30
30
|
// If storage manager is provided, try to load persisted routes
|
|
31
|
-
if (
|
|
31
|
+
if (this.storageManager) {
|
|
32
32
|
this.loadRoutes({ merge: true }).catch(error => {
|
|
33
33
|
console.error(`Failed to load persisted routes: ${error.message}`);
|
|
34
34
|
});
|
|
@@ -395,7 +395,7 @@ export class EmailRouter extends EventEmitter {
|
|
|
395
395
|
* Save current routes to storage
|
|
396
396
|
*/
|
|
397
397
|
public async saveRoutes(): Promise<void> {
|
|
398
|
-
if (!
|
|
398
|
+
if (!this.storageManager) {
|
|
399
399
|
this.emit('persistenceWarning', 'Cannot save routes: StorageManager not configured');
|
|
400
400
|
return;
|
|
401
401
|
}
|
|
@@ -426,7 +426,7 @@ export class EmailRouter extends EventEmitter {
|
|
|
426
426
|
merge?: boolean; // Merge with existing routes
|
|
427
427
|
replace?: boolean; // Replace existing routes
|
|
428
428
|
}): Promise<IEmailRoute[]> {
|
|
429
|
-
if (!
|
|
429
|
+
if (!this.storageManager) {
|
|
430
430
|
this.emit('persistenceWarning', 'Cannot load routes: StorageManager not configured');
|
|
431
431
|
return [];
|
|
432
432
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
|
-
import * as paths from '../../paths.js';
|
|
3
2
|
import { EventEmitter } from 'events';
|
|
4
3
|
import { logger } from '../../logger.js';
|
|
5
4
|
import {
|
|
@@ -8,7 +7,7 @@ import {
|
|
|
8
7
|
SecurityEventType
|
|
9
8
|
} from '../../security/index.js';
|
|
10
9
|
import { DKIMCreator } from '../security/classes.dkimcreator.js';
|
|
11
|
-
import {
|
|
10
|
+
import type { IStorageManager } from '../interfaces.storage.js';
|
|
12
11
|
import { RustSecurityBridge } from '../../security/classes.rustsecuritybridge.js';
|
|
13
12
|
import type { IEmailReceivedEvent, IRcptToRequestEvent, IAuthRequestEvent, IScramCredentialRequestEvent } from '../../security/classes.rustsecuritybridge.js';
|
|
14
13
|
import { EmailRouter } from './classes.email.router.js';
|
|
@@ -29,7 +28,7 @@ import { DkimManager } from './classes.dkim.manager.js';
|
|
|
29
28
|
|
|
30
29
|
/** External DcRouter interface shape used by UnifiedEmailServer */
|
|
31
30
|
interface DcRouter {
|
|
32
|
-
storageManager:
|
|
31
|
+
storageManager: IStorageManager;
|
|
33
32
|
dnsServer?: any;
|
|
34
33
|
options?: any;
|
|
35
34
|
}
|
|
@@ -118,9 +117,9 @@ export interface IUnifiedEmailServerOptions {
|
|
|
118
117
|
|
|
119
118
|
// TLS options
|
|
120
119
|
tls?: {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
certPem?: string;
|
|
121
|
+
keyPem?: string;
|
|
122
|
+
caPem?: string;
|
|
124
123
|
minVersion?: string;
|
|
125
124
|
ciphers?: string;
|
|
126
125
|
};
|
|
@@ -146,6 +145,8 @@ export interface IUnifiedEmailServerOptions {
|
|
|
146
145
|
recipientValidationTimeoutMs?: number;
|
|
147
146
|
/** Timeout for message acceptance callbacks. Defaults to 30000 ms. */
|
|
148
147
|
messageAcceptanceTimeoutMs?: number;
|
|
148
|
+
/** Maximum complete messages concurrently held across Rust and TypeScript. */
|
|
149
|
+
maxConcurrentMessages?: number;
|
|
149
150
|
/** Require trusted PROXY v1 from the backend proxy before SMTP greeting. */
|
|
150
151
|
proxyProtocol?: {
|
|
151
152
|
required?: boolean;
|
|
@@ -179,8 +180,8 @@ export interface IUnifiedEmailServerOptions {
|
|
|
179
180
|
connectionProxyProvider?: (context: IOutboundConnectionProxyContext) => Promise<IOutboundConnectionProxy | null | undefined>;
|
|
180
181
|
};
|
|
181
182
|
|
|
182
|
-
//
|
|
183
|
-
queue
|
|
183
|
+
// Queue persistence must be selected explicitly.
|
|
184
|
+
queue: IQueueOptions;
|
|
184
185
|
|
|
185
186
|
// Rate limiting (global limits, can be overridden per domain)
|
|
186
187
|
rateLimits?: IHierarchicalRateLimits;
|
|
@@ -283,7 +284,7 @@ export class UnifiedEmailServer extends EventEmitter {
|
|
|
283
284
|
this.rustBridge = RustSecurityBridge.getInstance();
|
|
284
285
|
|
|
285
286
|
// Initialize DKIM creator with storage manager
|
|
286
|
-
this.dkimCreator = new DKIMCreator(
|
|
287
|
+
this.dkimCreator = new DKIMCreator(dcRouter.storageManager);
|
|
287
288
|
|
|
288
289
|
// Initialize bounce manager with storage manager
|
|
289
290
|
this.bounceManager = new BounceManager({
|
|
@@ -298,7 +299,7 @@ export class UnifiedEmailServer extends EventEmitter {
|
|
|
298
299
|
// Initialize email router with routes and storage manager
|
|
299
300
|
this.emailRouter = new EmailRouter(options.routes || [], {
|
|
300
301
|
storageManager: dcRouter.storageManager,
|
|
301
|
-
persistChanges: options.persistRoutes ??
|
|
302
|
+
persistChanges: options.persistRoutes ?? true
|
|
302
303
|
});
|
|
303
304
|
|
|
304
305
|
// Initialize rate limiter
|
|
@@ -315,7 +316,6 @@ export class UnifiedEmailServer extends EventEmitter {
|
|
|
315
316
|
|
|
316
317
|
// Initialize delivery components
|
|
317
318
|
const queueOptions: IQueueOptions = {
|
|
318
|
-
storageType: 'memory', // Default to memory storage
|
|
319
319
|
maxRetries: 3,
|
|
320
320
|
baseRetryDelay: 300000, // 5 minutes
|
|
321
321
|
maxRetryDelay: 3600000, // 1 hour
|
|
@@ -409,8 +409,12 @@ export class UnifiedEmailServer extends EventEmitter {
|
|
|
409
409
|
let dkim: { domain: string; selector: string; privateKey: string } | undefined;
|
|
410
410
|
if (options?.dkimDomain) {
|
|
411
411
|
try {
|
|
412
|
-
const
|
|
413
|
-
|
|
412
|
+
const selector = options.dkimSelector || 'default';
|
|
413
|
+
const { privateKey } = await this.dkimCreator.readDKIMKeysForSelector(
|
|
414
|
+
options.dkimDomain,
|
|
415
|
+
selector,
|
|
416
|
+
);
|
|
417
|
+
dkim = { domain: options.dkimDomain, selector, privateKey };
|
|
414
418
|
} catch (err) {
|
|
415
419
|
logger.log('warn', `Failed to read DKIM keys for ${options.dkimDomain}: ${(err as Error).message}`);
|
|
416
420
|
}
|
|
@@ -664,20 +668,11 @@ export class UnifiedEmailServer extends EventEmitter {
|
|
|
664
668
|
}
|
|
665
669
|
|
|
666
670
|
private async startSmtpServer(): Promise<void> {
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
if (hasTlsConfig) {
|
|
672
|
-
try {
|
|
673
|
-
tlsKeyPem = plugins.fs.readFileSync(this.options.tls.keyPath!, 'utf8');
|
|
674
|
-
tlsCertPem = plugins.fs.readFileSync(this.options.tls.certPath!, 'utf8');
|
|
675
|
-
logger.log('info', 'TLS certificates loaded successfully');
|
|
676
|
-
} catch (error) {
|
|
677
|
-
logger.log('warn', `Failed to load TLS certificates: ${error.message}`);
|
|
678
|
-
}
|
|
671
|
+
const tlsCertPem = this.options.tls?.certPem;
|
|
672
|
+
const tlsKeyPem = this.options.tls?.keyPem;
|
|
673
|
+
if ((tlsCertPem && !tlsKeyPem) || (!tlsCertPem && tlsKeyPem)) {
|
|
674
|
+
throw new Error('SMTP TLS requires both certPem and keyPem');
|
|
679
675
|
}
|
|
680
|
-
|
|
681
676
|
const configuredSecurePort = this.options.smtp?.securePort;
|
|
682
677
|
if (configuredSecurePort !== undefined && !(this.options.ports as number[]).includes(configuredSecurePort)) {
|
|
683
678
|
throw new Error(`Configured SMTP securePort ${configuredSecurePort} is not included in ports`);
|
|
@@ -704,6 +699,7 @@ export class UnifiedEmailServer extends EventEmitter {
|
|
|
704
699
|
processingTimeoutSecs: this.options.hooks?.onMessageData
|
|
705
700
|
? Math.ceil(this.getMessageAcceptanceTimeoutMs() / 1000) + 1
|
|
706
701
|
: 30,
|
|
702
|
+
maxConcurrentMessages: this.options.smtp?.maxConcurrentMessages ?? 4,
|
|
707
703
|
recipientValidationEnabled: this.isRecipientValidationEnabled(),
|
|
708
704
|
recipientValidationTimeoutSecs: this.options.smtp?.recipientValidationTimeoutMs
|
|
709
705
|
? Math.ceil(this.options.smtp.recipientValidationTimeoutMs / 1000)
|
|
@@ -955,24 +951,7 @@ export class UnifiedEmailServer extends EventEmitter {
|
|
|
955
951
|
logger.log('info', `Rust SMTP received email from=${mailFrom} to=${rcptTo.join(',')} remote=${remoteAddr}`);
|
|
956
952
|
|
|
957
953
|
try {
|
|
958
|
-
|
|
959
|
-
let rawMessageBuffer: Buffer;
|
|
960
|
-
if (data.data.type === 'inline' && data.data.base64) {
|
|
961
|
-
rawMessageBuffer = Buffer.from(data.data.base64, 'base64');
|
|
962
|
-
} else if (data.data.type === 'file' && data.data.path) {
|
|
963
|
-
try {
|
|
964
|
-
rawMessageBuffer = plugins.fs.readFileSync(data.data.path);
|
|
965
|
-
} finally {
|
|
966
|
-
try {
|
|
967
|
-
plugins.fs.unlinkSync(data.data.path);
|
|
968
|
-
} catch {
|
|
969
|
-
// Ignore cleanup errors
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
} else {
|
|
973
|
-
throw new Error('Invalid email data transport');
|
|
974
|
-
}
|
|
975
|
-
|
|
954
|
+
const rawMessageBuffer = Buffer.from(data.data.base64, 'base64');
|
|
976
955
|
// Build a session-like object for processEmailByMode
|
|
977
956
|
const session: IExtendedSmtpSession = {
|
|
978
957
|
id: data.sessionId || 'rust-' + Math.random().toString(36).substring(2),
|
|
@@ -89,7 +89,6 @@ export interface IEmailAction {
|
|
|
89
89
|
mtaOptions?: {
|
|
90
90
|
domain?: string;
|
|
91
91
|
allowLocalDelivery?: boolean;
|
|
92
|
-
localDeliveryPath?: string;
|
|
93
92
|
dkimSign?: boolean;
|
|
94
93
|
dkimOptions?: {
|
|
95
94
|
domainName: string;
|
|
@@ -99,7 +98,6 @@ export interface IEmailAction {
|
|
|
99
98
|
smtpBanner?: string;
|
|
100
99
|
maxConnections?: number;
|
|
101
100
|
connTimeout?: number;
|
|
102
|
-
spoolDir?: string;
|
|
103
101
|
};
|
|
104
102
|
/** Content scanning configuration */
|
|
105
103
|
contentScanning?: boolean;
|