chore: update webscoket connetion and polling service

This commit is contained in:
mahyargdz
2025-07-30 09:37:11 +03:30
parent 5315fae914
commit f46c2ced99
13 changed files with 140 additions and 113 deletions
+1
View File
@@ -280,6 +280,7 @@ export const enum EmailMessage {
MESSAGE_REMOVED_FROM_FAVORITE_SUCCESSFULLY = "پیام با موفقیت از مورد علاقه حذف شد",
TRASH_EMPTYED_SUCCESSFULLY = "سطل زباله با موفقیت خالی شد",
SPAM_EMPTYED_SUCCESSFULLY = "همه پیام های اسپم با موفقیت حذف شدند",
SAVE_DRAFT_SUCCESS = "پیش نویس با موفقیت ذخیره شد",
}
export const enum WebSocketMessage {
+2 -6
View File
@@ -28,11 +28,7 @@ import { EmailPollingService } from "../email-utils/services/email-polling.servi
@UsePipes(new ValidationPipe({ transform: true }))
@UseFilters(WsExceptionFilter)
@WebSocketGateway({
namespace: WEBSOCKET_NAMESPACES.EMAIL,
cors: { origin: true, credentials: true },
transports: ["websocket", "polling"],
})
@WebSocketGateway({ namespace: WEBSOCKET_NAMESPACES.EMAIL, cors: { origin: true, credentials: true }, transports: ["websocket", "polling"] })
export class EmailGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer()
server: Server;
@@ -86,7 +82,7 @@ export class EmailGateway implements OnGatewayInit, OnGatewayConnection, OnGatew
// Start email polling for this user
try {
await this.emailPollingService.startPollingForUser(user.id, client.id);
await this.emailPollingService.startPollingForUser(user.wildduckUserId, user.id, client.id);
this.logger.log(`Email polling started for user ${user.id}`);
} catch (pollingError) {
this.logger.error(`Failed to start email polling for user ${user.id}:`, pollingError);
@@ -1,4 +1,5 @@
export interface EmailPollingJobData {
wildduckUserId: string;
userId: string;
lastCheckTimestamp?: string;
connectionId: string;
@@ -23,47 +23,41 @@ export class EmailPollingProcessor extends WorkerProcessor {
}
async process(job: Job<EmailPollingJobData>): Promise<void> {
const { userId, lastCheckTimestamp, connectionId } = job.data;
const { wildduckUserId, userId, lastCheckTimestamp, connectionId } = job.data;
this.logger.debug(`Processing email polling job for user ${userId} (connection: ${connectionId})`);
try {
// Check if user is still connected before processing
if (!this.emailGateway.isUserConnected(userId)) {
this.logger.debug(`User ${userId} no longer connected, skipping email check`);
return;
}
// Get user's mailbox information
const mailboxIds = await this.mailboxResolverService.getUserMailboxIds(userId);
const mailboxIds = await this.mailboxResolverService.getUserMailboxIds(wildduckUserId);
if (!mailboxIds.inbox) {
this.logger.warn(`No inbox found for user ${userId}`);
return;
}
// Calculate time range for checking new emails
const checkSince = lastCheckTimestamp ? new Date(lastCheckTimestamp) : new Date(Date.now() - 5 * 60 * 1000);
const now = new Date();
this.logger.debug(`Checking emails for user ${userId} since ${checkSince.toISOString()}`);
// Get new emails from inbox since last check
const newEmails = await this.getRecentEmails(userId, mailboxIds.inbox, checkSince);
const newEmails = await this.getRecentEmails(wildduckUserId, mailboxIds.inbox, checkSince);
if (newEmails.length > 0) {
this.logger.log(`Found ${newEmails.length} new emails for user ${userId}`);
// Notify user of each new email via websocket
this.logger.log(`Found ${newEmails.length} new emails for user ${wildduckUserId}`);
const lastEmail = newEmails[newEmails.length - 1];
await this.emailGateway.notifyNewEmail(userId, {
wildduckUserId: userId,
wildduckUserId,
userId,
messageId: lastEmail.id,
date: lastEmail.date || new Date().toISOString(),
from: lastEmail.from,
to: lastEmail.to || [],
subject: lastEmail.subject,
userId,
timestamp: lastEmail.date || new Date().toISOString(),
mailboxId: lastEmail.mailbox,
mailboxName: "Inbox",
@@ -72,7 +66,7 @@ export class EmailPollingProcessor extends WorkerProcessor {
});
// Update unread count
const unreadStats = await this.getUnreadCounts(userId, mailboxIds);
const unreadStats = await this.getUnreadCounts(wildduckUserId, mailboxIds);
await this.emailGateway.notifyUnreadCountUpdate(userId, {
userId,
totalUnread: unreadStats.total,
@@ -96,15 +90,15 @@ export class EmailPollingProcessor extends WorkerProcessor {
throw error; // Re-throw to trigger retry mechanism
}
}
// Helper method to get recent emails from a mailbox
private async getRecentEmails(userId: string, mailboxId: string, since: Date) {
//=======================================================
private async getRecentEmails(wildduckUserId: string, mailboxId: string, since: Date) {
try {
const response = await firstValueFrom(
this.mailServerService.messages.searchMessages(userId, {
this.mailServerService.messages.searchMessages(wildduckUserId, {
mailbox: mailboxId,
limit: 50, // Limit to avoid too many results
order: "desc", // Most recent first
limit: 50,
order: "desc",
unseen: true,
}),
);
@@ -117,22 +111,20 @@ export class EmailPollingProcessor extends WorkerProcessor {
return emailDate >= since;
});
} catch (error) {
this.logger.error(`Error fetching recent emails for user ${userId}:`, error);
this.logger.error(`Error fetching recent emails for user ${wildduckUserId}:`, error);
return [];
}
}
// Helper method to get unread counts from all mailboxes
private async getUnreadCounts(userId: string, mailboxIds: UserMailboxIds) {
//=======================================================
private async getUnreadCounts(wildduckUserId: string, mailboxIds: UserMailboxIds) {
try {
const mailboxCounts: Record<string, number> = {};
let total = 0;
// Get unread count from each mailbox
for (const [mailboxName, mailboxId] of Object.entries(mailboxIds)) {
if (mailboxId) {
try {
const response = await firstValueFrom(this.mailServerService.mailboxes.getMailbox(userId, mailboxId));
const response = await firstValueFrom(this.mailServerService.mailboxes.getMailbox(wildduckUserId, mailboxId));
if (response.success && response.unseen !== undefined) {
mailboxCounts[mailboxName] = response.unseen;
@@ -150,7 +142,7 @@ export class EmailPollingProcessor extends WorkerProcessor {
mailboxCounts,
};
} catch (error) {
this.logger.error(`Error calculating unread counts for user ${userId}:`, error);
this.logger.error(`Error calculating unread counts for user ${wildduckUserId}:`, error);
return {
total: 0,
mailboxCounts: {},
@@ -14,11 +14,12 @@ export class EmailPollingService {
constructor(@InjectQueue(EMAIL_QUEUE_CONSTANTS.EMAIL_POLLING_QUEUE) private readonly emailPollingQueue: Queue<EmailPollingJobData>) {}
//=======================================================
async startPollingForUser(userId: string, connectionId: string): Promise<void> {
async startPollingForUser(wildduckUserId: string, userId: string, connectionId: string): Promise<void> {
try {
await this.stopPollingForUser(userId);
const jobData: EmailPollingJobData = {
wildduckUserId,
userId,
connectionId,
lastCheckTimestamp: new Date().toISOString(),
@@ -54,6 +55,7 @@ export class EmailPollingService {
async stopPollingForUser(userId: string): Promise<void> {
try {
const activeJob = this.activeJobs.get(userId);
console.log(activeJob);
if (!activeJob) {
this.logger.debug(`No active polling job found for user ${userId}`);
return;
@@ -140,9 +142,9 @@ export class EmailPollingService {
}
//=======================================================
async restartPollingForUser(userId: string, connectionId: string): Promise<void> {
async restartPollingForUser(wildduckUserId: string, userId: string, connectionId: string): Promise<void> {
this.logger.log(`Restarting email polling for user ${userId}`);
await this.stopPollingForUser(userId);
await this.startPollingForUser(userId, connectionId);
await this.startPollingForUser(wildduckUserId, userId, connectionId);
}
}
@@ -18,14 +18,14 @@ export class MailboxResolverService {
/**
* Get user mailbox IDs with caching
*/
async getUserMailboxIds(userId: string): Promise<UserMailboxIds> {
const cached = this.getCachedMailboxIds(userId);
async getUserMailboxIds(wildduckUserId: string): Promise<UserMailboxIds> {
const cached = this.getCachedMailboxIds(wildduckUserId);
if (cached) return cached;
this.logger.log(`Fetching mailbox IDs for user: ${userId}`);
this.logger.log(`Fetching mailbox IDs for user: ${wildduckUserId}`);
try {
const mailboxes = await firstValueFrom(this.mailServerService.mailboxes.listMailboxes(userId));
const mailboxes = await firstValueFrom(this.mailServerService.mailboxes.listMailboxes(wildduckUserId));
const mailboxIds: UserMailboxIds = {
inbox: this.findMailboxId(mailboxes.results, MailboxEnum.INBOX),
@@ -37,12 +37,12 @@ export class MailboxResolverService {
// favorite: this.findMailboxId(mailboxes.results, MailboxEnum.FAVORITE, false),
};
this.cacheMailboxIds(userId, mailboxIds);
this.cacheMailboxIds(wildduckUserId, mailboxIds);
this.logger.log(`Mailbox IDs cached for user: ${userId}`);
this.logger.log(`Mailbox IDs cached for user: ${wildduckUserId}`);
return mailboxIds;
} catch (error) {
this.logger.error(`Failed to fetch mailbox IDs for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`);
this.logger.error(`Failed to fetch mailbox IDs for user ${wildduckUserId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
@@ -50,12 +50,12 @@ export class MailboxResolverService {
/**
* Get specific mailbox ID
*/
async getMailboxId(userId: string, mailboxType: keyof UserMailboxIds): Promise<string> {
const mailboxIds = await this.getUserMailboxIds(userId);
async getMailboxId(wildduckUserId: string, mailboxType: keyof UserMailboxIds): Promise<string> {
const mailboxIds = await this.getUserMailboxIds(wildduckUserId);
const mailboxId = mailboxIds[mailboxType];
if (!mailboxId) {
throw new NotFoundException(`${mailboxType} mailbox not found for user ${userId}`);
throw new NotFoundException(`${mailboxType} mailbox not found for user ${wildduckUserId}`);
}
return mailboxId;
@@ -73,37 +73,37 @@ export class MailboxResolverService {
/**
* Get drafts mailbox ID
*/
async getDraftsMailboxId(userId: string): Promise<string> {
return this.getMailboxId(userId, "drafts");
async getDraftsMailboxId(wildduckUserId: string): Promise<string> {
return this.getMailboxId(wildduckUserId, "drafts");
}
/**
* Get inbox mailbox ID
*/
async getInboxMailboxId(userId: string): Promise<string> {
return this.getMailboxId(userId, "inbox");
async getInboxMailboxId(wildduckUserId: string): Promise<string> {
return this.getMailboxId(wildduckUserId, "inbox");
}
/**
* Get sent mailbox ID
*/
async getSentMailboxId(userId: string): Promise<string> {
return this.getMailboxId(userId, "sent");
async getSentMailboxId(wildduckUserId: string): Promise<string> {
return this.getMailboxId(wildduckUserId, "sent");
}
/**
* Get trash mailbox ID
*/
async getTrashMailboxId(userId: string): Promise<string> {
return this.getMailboxId(userId, "trash");
async getTrashMailboxId(wildduckUserId: string): Promise<string> {
return this.getMailboxId(wildduckUserId, "trash");
}
async getJunkMailboxId(userId: string): Promise<string> {
return this.getMailboxId(userId, "junk");
async getJunkMailboxId(wildduckUserId: string): Promise<string> {
return this.getMailboxId(wildduckUserId, "junk");
}
async getArchiveMailboxId(userId: string): Promise<string> {
return this.getMailboxId(userId, "archive");
async getArchiveMailboxId(wildduckUserId: string): Promise<string> {
return this.getMailboxId(wildduckUserId, "archive");
}
// async getFavoriteMailboxId(userId: string): Promise<string> {
@@ -113,10 +113,10 @@ export class MailboxResolverService {
/**
* Clear cache for a specific user
*/
clearUserCache(userId: string): void {
this.mailboxCache.delete(userId);
this.cacheExpiry.delete(userId);
this.logger.log(`Cache cleared for user: ${userId}`);
clearUserCache(wildduckUserId: string): void {
this.mailboxCache.delete(wildduckUserId);
this.cacheExpiry.delete(wildduckUserId);
this.logger.log(`Cache cleared for user: ${wildduckUserId}`);
}
/**
@@ -131,18 +131,18 @@ export class MailboxResolverService {
/**
* Get cached mailbox IDs if not expired
*/
private getCachedMailboxIds(userId: string): UserMailboxIds | null {
const cached = this.mailboxCache.get(userId);
const expiry = this.cacheExpiry.get(userId);
private getCachedMailboxIds(wildduckUserId: string): UserMailboxIds | null {
const cached = this.mailboxCache.get(wildduckUserId);
const expiry = this.cacheExpiry.get(wildduckUserId);
if (cached && expiry && Date.now() < expiry) {
this.logger.debug(`Using cached mailbox IDs for user: ${userId}`);
this.logger.debug(`Using cached mailbox IDs for user: ${wildduckUserId}`);
return cached;
}
if (cached) {
this.logger.debug(`Cache expired for user: ${userId}`);
this.clearUserCache(userId);
this.logger.debug(`Cache expired for user: ${wildduckUserId}`);
this.clearUserCache(wildduckUserId);
}
return null;
@@ -151,9 +151,9 @@ export class MailboxResolverService {
/**
* Cache mailbox IDs with expiry
*/
private cacheMailboxIds(userId: string, mailboxIds: UserMailboxIds): void {
this.mailboxCache.set(userId, mailboxIds);
this.cacheExpiry.set(userId, Date.now() + this.CACHE_DURATION);
private cacheMailboxIds(wildduckUserId: string, mailboxIds: UserMailboxIds): void {
this.mailboxCache.set(wildduckUserId, mailboxIds);
this.cacheExpiry.set(wildduckUserId, Date.now() + this.CACHE_DURATION);
}
/**
@@ -49,13 +49,13 @@ export const EMAIL_QUEUE_CONSTANTS = {
EMAIL_BULK_ACTION_DELAY: 1000,
EMAIL_BULK_ACTION_BATCH_SIZE: 250,
EMAIL_BULK_ACTION_ATTEMPTS: 3,
EMAIL_BULK_ACTION_BACKOFF_DELAY: 2000, // 2 seconds
EMAIL_BULK_ACTION_BACKOFF_DELAY: 2000,
EMAIL_BULK_ACTION_PRIORITY: 1,
//
EMAIL_POLLING_INTERVAL: 30000, // 30 seconds
EMAIL_POLLING_REMOVE_ON_COMPLETE: 5, // Keep last 5 completed jobs
EMAIL_POLLING_REMOVE_ON_FAIL: 10, // Keep last 10 failed jobs
EMAIL_POLLING_ATTEMPTS: 3, // Retry failed jobs 3 times
EMAIL_POLLING_BACKOFF_DELAY: 2000, // 2 seconds
EMAIL_POLLING_INTERVAL: 3000,
EMAIL_POLLING_REMOVE_ON_COMPLETE: true,
EMAIL_POLLING_REMOVE_ON_FAIL: 10,
EMAIL_POLLING_ATTEMPTS: 3,
EMAIL_POLLING_BACKOFF_DELAY: 2000,
EMAIL_POLLING_PRIORITY: 1,
} as const;
+6 -6
View File
@@ -115,24 +115,24 @@ export class EmailController {
@ApiResponse({ status: 206, description: "Some messages marked as read, some failed" })
@ApiResponse({ status: 404, description: "Mailbox not found" })
@ApiResponse({ status: 403, description: "Not authorized to mark messages as read" })
markAllMessagesAsRead(@UserDec("wildduckUserId") userId: string, @Query() query: MailboxIdQueryDto) {
return this.emailService.markAllMessagesAsRead(userId, query.mailbox);
markAllMessagesAsRead(@UserDec("wildduckUserId") wildduckUserId: string, @UserDec("id") userId: string, @Query() query: MailboxIdQueryDto) {
return this.emailService.markAllMessagesAsRead(wildduckUserId, userId, query.mailbox);
}
@Patch("messages/empty-trash")
@ApiOperation({ summary: "Empty trash" })
@ApiResponse({ status: 200, description: "Trash emptied successfully" })
@ApiResponse({ status: 404, description: "Trash not found" })
emptyTrash(@UserDec("wildduckUserId") userId: string, @Query() query: MailboxIdQueryDto) {
return this.emailService.emptyTrash(userId, query.mailbox);
emptyTrash(@UserDec("wildduckUserId") wildduckUserId: string, @UserDec("id") userId: string, @Query() query: MailboxIdQueryDto) {
return this.emailService.emptyTrash(wildduckUserId, userId, query.mailbox);
}
@Patch("messages/empty-spam")
@ApiOperation({ summary: "Empty spam" })
@ApiResponse({ status: 200, description: "Spam emptied successfully" })
@ApiResponse({ status: 404, description: "Spam not found" })
emptySpam(@UserDec("wildduckUserId") userId: string, @Query() query: MailboxIdQueryDto) {
return this.emailService.emptySpam(userId, query.mailbox);
emptySpam(@UserDec("wildduckUserId") wildduckUserId: string, @UserDec("id") userId: string, @Query() query: MailboxIdQueryDto) {
return this.emailService.emptySpam(wildduckUserId, userId, query.mailbox);
}
@Get("messages/inbox")
+4
View File
@@ -17,6 +17,10 @@ import { User } from "../users/entities/user.entity";
imports: [
BullModule.registerQueue({
name: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_QUEUE,
defaultJobOptions: {
removeOnComplete: true,
removeOnFail: false,
},
}),
MailServerModule,
TemplatesModule,
@@ -1,4 +1,5 @@
export interface IEmailBulkActionJob {
wildduckUserId: string;
userId: string;
mailboxId: string;
}
@@ -31,17 +31,17 @@ export class EmailBulkActionProcessor extends WorkerHost {
switch (name) {
case EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_SEEN_ALL:
this.logger.debug(`Processing bulk action for: ${data.wildduckUserId}`);
await this.markAllMessagesAsRead(data.wildduckUserId, data.mailboxId);
await this.markAllMessagesAsRead(data.wildduckUserId, data.userId, data.mailboxId);
break;
case EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_TRASH:
this.logger.debug(`Processing bulk action for: ${data.wildduckUserId}`);
await this.emptyTrash(data.wildduckUserId, data.mailboxId);
await this.emptyTrash(data.wildduckUserId, data.userId, data.mailboxId);
break;
case EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_SPAM:
this.logger.debug(`Processing bulk action for: ${data.wildduckUserId}`);
await this.emptySpam(data.wildduckUserId, data.mailboxId);
await this.emptySpam(data.wildduckUserId, data.userId, data.mailboxId);
break;
default:
@@ -55,12 +55,11 @@ export class EmailBulkActionProcessor extends WorkerHost {
}
//==============================================
private async markAllMessagesAsRead(wildduckUserId: string, mailboxId: string) {
private async markAllMessagesAsRead(wildduckUserId: string, userId: string, mailboxId: string) {
this.logger.log(`Marking all messages as read for user ${wildduckUserId} in mailbox ${mailboxId}`);
try {
// Get all unread messages from the mailbox with a reasonable limit
const limit = EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_BATCH_SIZE; // Process in batches to avoid memory issues
const limit = EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_BATCH_SIZE;
let totalMarked = 0;
let hasMore = true;
let next: string | undefined;
@@ -72,11 +71,10 @@ export class EmailBulkActionProcessor extends WorkerHost {
};
while (hasMore) {
// Fetch unread messages in batches
const query: Record<string, unknown> = {
limit,
order: "desc",
unseen: true, // Only get unread messages
unseen: true,
};
if (next) {
@@ -90,7 +88,6 @@ export class EmailBulkActionProcessor extends WorkerHost {
break;
}
// Mark each message as seen
for (const message of response.results) {
try {
await this.emailService.markMessageAsSeen(wildduckUserId, message.id, mailboxId);
@@ -105,7 +102,6 @@ export class EmailBulkActionProcessor extends WorkerHost {
}
}
// Check if there are more messages
next = typeof response.nextCursor === "string" ? response.nextCursor : undefined;
hasMore = !!next && response.results.length === limit;
}
@@ -113,12 +109,14 @@ export class EmailBulkActionProcessor extends WorkerHost {
results.totalMarked = totalMarked;
await this.emailNotificationService.notifyEmailRead({
userId: wildduckUserId,
userId,
messageId: results.successful[0],
mailboxId,
});
this.logger.log(`Marked ${totalMarked} messages as read for user ${wildduckUserId} in mailbox ${mailboxId}, ${results.failed.length} failed`);
this.logger.verbose(
`Marked ${totalMarked} messages as read for user ${wildduckUserId} in mailbox ${mailboxId}, ${results.failed.length} failed`,
);
return {
success: true,
@@ -133,7 +131,7 @@ export class EmailBulkActionProcessor extends WorkerHost {
//==============================================
private async emptyTrash(wildduckUserId: string, mailboxId: string) {
private async emptyTrash(wildduckUserId: string, userId: string, mailboxId: string) {
this.logger.log(`Emptying trash for user ${wildduckUserId} in mailbox ${mailboxId}`);
try {
@@ -145,7 +143,7 @@ export class EmailBulkActionProcessor extends WorkerHost {
}
await this.emailNotificationService.notifyEmailDeleted({
userId: wildduckUserId,
userId,
messageId: randomInt(1, 500),
mailboxId,
});
@@ -162,7 +160,7 @@ export class EmailBulkActionProcessor extends WorkerHost {
}
//==============================================
private async emptySpam(wildduckUserId: string, mailboxId: string) {
private async emptySpam(wildduckUserId: string, userId: string, mailboxId: string) {
this.logger.log(`Emptying spam for user ${wildduckUserId} in mailbox ${mailboxId}`);
try {
@@ -174,7 +172,7 @@ export class EmailBulkActionProcessor extends WorkerHost {
}
await this.emailNotificationService.notifyEmailDeleted({
userId: wildduckUserId,
userId,
messageId: randomInt(1, 500),
mailboxId,
});
+45 -15
View File
@@ -88,7 +88,7 @@ export class EmailService {
});
return {
message: EmailMessage.EMAIL_SENDING_SUCCESS,
message: sendEmailDto.isDraft ? EmailMessage.SAVE_DRAFT_SUCCESS : EmailMessage.EMAIL_SENDING_SUCCESS,
messageId: response.message.id,
queueId: response.message.queueId,
};
@@ -109,15 +109,18 @@ export class EmailService {
async searchMessages(wildduckUserId: string, query: SearchMessagesQueryDto) {
const wildDuckQuery: SearchMessagesMailServerQueryDto = {
...query,
limit: query.limit || 20,
limit: 100,
page: query.page || 1,
order: query.order || "desc",
searchable: true,
query: query.search,
from: query.from || query.search,
// mailbox: query.mailbox,
// subject: query.subject || query.search,
// from: query.from || query.search,
// to: query.to || query.search,
};
delete wildDuckQuery?.mailbox;
delete wildDuckQuery.search;
const response = await firstValueFrom(this.mailServerService.messages.searchMessages(wildduckUserId, wildDuckQuery));
@@ -283,11 +286,12 @@ export class EmailService {
}
//==============================================
async markAllMessagesAsRead(wildduckUserId: string, mailboxId: string) {
async markAllMessagesAsRead(wildduckUserId: string, userId: string, mailboxId: string) {
await this.emailBulkActionQueue.add(
EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_SEEN_ALL,
{
wildduckUserId,
userId,
mailboxId,
},
{
@@ -308,11 +312,24 @@ export class EmailService {
}
//==============================================
async emptyTrash(wildduckUserId: string, mailboxId: string) {
await this.emailBulkActionQueue.add(EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_TRASH, {
wildduckUserId,
mailboxId,
});
async emptyTrash(wildduckUserId: string, userId: string, mailboxId: string) {
await this.emailBulkActionQueue.add(
EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_TRASH,
{
wildduckUserId,
userId,
mailboxId,
},
{
delay: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_DELAY,
priority: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_PRIORITY,
attempts: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_ATTEMPTS,
backoff: {
type: "exponential",
delay: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_BACKOFF_DELAY,
},
},
);
return {
success: true,
@@ -321,11 +338,24 @@ export class EmailService {
}
//==============================================
async emptySpam(wildduckUserId: string, mailboxId: string) {
await this.emailBulkActionQueue.add(EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_SPAM, {
wildduckUserId,
mailboxId,
});
async emptySpam(wildduckUserId: string, userId: string, mailboxId: string) {
await this.emailBulkActionQueue.add(
EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_EMPTY_SPAM,
{
wildduckUserId,
userId,
mailboxId,
},
{
delay: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_DELAY,
priority: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_PRIORITY,
attempts: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_ATTEMPTS,
backoff: {
type: "exponential",
delay: EMAIL_QUEUE_CONSTANTS.EMAIL_BULK_ACTION_BACKOFF_DELAY,
},
},
);
return {
success: true,
@@ -27,6 +27,8 @@ export class UpdateMessageDto {
}
export class SearchMessagesMailServerQueryDto {
search?: string;
q?: string;
mailbox?: string;