feat(email): add persistent smartmta storage and runtime-managed email domain syncing

This commit is contained in:
2026-04-14 13:11:48 +00:00
parent 9a378ae87f
commit 1d7e5495fa
14 changed files with 690 additions and 163 deletions

View File

@@ -48,7 +48,7 @@ export class EmailOpsHandler {
}
const queue = emailServer.deliveryQueue;
const item = queue.getItem(dataArg.emailId);
const item = emailServer.getQueueItem(dataArg.emailId);
if (!item) {
return { success: false, error: 'Email not found in queue' };
@@ -82,22 +82,10 @@ export class EmailOpsHandler {
*/
private getAllQueueEmails(): interfaces.requests.IEmail[] {
const emailServer = this.opsServerRef.dcRouterRef.emailServer;
if (!emailServer?.deliveryQueue) {
if (!emailServer) {
return [];
}
const queue = emailServer.deliveryQueue;
const queueMap = (queue as any).queue as Map<string, any>;
if (!queueMap) {
return [];
}
const emails: interfaces.requests.IEmail[] = [];
for (const [id, item] of queueMap.entries()) {
emails.push(this.mapQueueItemToEmail(item));
}
const emails = emailServer.getQueueItems().map((item) => this.mapQueueItemToEmail(item));
// Sort by createdAt descending (newest first)
emails.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
@@ -110,12 +98,10 @@ export class EmailOpsHandler {
*/
private getEmailDetail(emailId: string): interfaces.requests.IEmailDetail | null {
const emailServer = this.opsServerRef.dcRouterRef.emailServer;
if (!emailServer?.deliveryQueue) {
if (!emailServer) {
return null;
}
const queue = emailServer.deliveryQueue;
const item = queue.getItem(emailId);
const item = emailServer.getQueueItem(emailId);
if (!item) {
return null;

View File

@@ -530,13 +530,49 @@ export class StatsHandler {
nextRetry?: number;
}>;
}> {
// TODO: Implement actual queue status collection
const emailServer = this.opsServerRef.dcRouterRef.emailServer;
if (!emailServer) {
return {
pending: 0,
active: 0,
failed: 0,
retrying: 0,
items: [],
};
}
const queueStats = emailServer.getQueueStats();
const items = emailServer.getQueueItems()
.sort((a, b) => {
const left = a.createdAt instanceof Date ? a.createdAt.getTime() : new Date(a.createdAt).getTime();
const right = b.createdAt instanceof Date ? b.createdAt.getTime() : new Date(b.createdAt).getTime();
return right - left;
})
.slice(0, 50)
.map((item) => {
const emailLike = item.processingResult;
const recipients = Array.isArray(emailLike?.to)
? emailLike.to
: Array.isArray(emailLike?.email?.to)
? emailLike.email.to
: [];
const subject = emailLike?.subject || emailLike?.email?.subject || '';
return {
id: item.id,
recipient: recipients[0] || '',
subject,
status: item.status,
attempts: item.attempts,
nextRetry: item.nextAttempt instanceof Date ? item.nextAttempt.getTime() : undefined,
};
});
return {
pending: 0,
active: 0,
failed: 0,
retrying: 0,
items: [],
pending: queueStats.status.pending,
active: queueStats.status.processing,
failed: queueStats.status.failed,
retrying: queueStats.status.deferred,
items,
};
}
@@ -600,4 +636,4 @@ export class StatsHandler {
],
};
}
}
}