diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index b9d23fc..e86e97d 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -194,6 +194,9 @@ export const enum EmailMessage { SENT_MESSAGES_RETRIEVAL_FAILED = "دریافت پیام های ارسالی با خطا مواجه شد", TRASH_MESSAGES_RETRIEVED_SUCCESSFULLY = "پیام های حذف شده با موفقیت دریافت شد", TRASH_MESSAGES_RETRIEVAL_FAILED = "دریافت پیام های حذف شده با خطا مواجه شد", + DRAFT_UPDATED_SUCCESSFULLY = "پیش نویس با موفقیت به روز رسانی شد", + DRAFT_SENT_SUCCESSFULLY = "پیش نویس با موفقیت ارسال شد", + DRAFT_DELETED_SUCCESSFULLY = "پیش نویس با موفقیت حذف شد", } export const enum SmsMessage { diff --git a/src/modules/auth/services/tokens.service.ts b/src/modules/auth/services/tokens.service.ts index 0864d6e..68f8af7 100755 --- a/src/modules/auth/services/tokens.service.ts +++ b/src/modules/auth/services/tokens.service.ts @@ -26,10 +26,10 @@ export class TokensService { id: user.id, role: user.role.name, inboxId: mailboxes?.[0] || "", - sentId: mailboxes?.[1] || "", - draftsId: mailboxes?.[2] || "", - trashId: mailboxes?.[3] || "", - junkId: mailboxes?.[4] || "", + draftsId: mailboxes?.[1] || "", + junkId: mailboxes?.[2] || "", + sentId: mailboxes?.[3] || "", + trashId: mailboxes?.[4] || "", wildduckUserId: user.wildduckUserId, }, em, diff --git a/src/modules/email/DTO/email-params.dto.ts b/src/modules/email/DTO/email-params.dto.ts index 411483d..1aa8d6b 100644 --- a/src/modules/email/DTO/email-params.dto.ts +++ b/src/modules/email/DTO/email-params.dto.ts @@ -39,7 +39,7 @@ export class UserMailboxParamDto { mailboxId: string; } -export class UserMailboxMessageParamDto { +export class MessageParamDto { @ApiProperty({ description: "Message ID", example: "12345" }) @Transform(({ value }) => parseInt(value)) @IsNumber({}, { message: EmailMessage.MESSAGE_ID_MUST_BE_NUMBER }) diff --git a/src/modules/email/DTO/send-email.dto.ts b/src/modules/email/DTO/send-email.dto.ts index d112f31..8d9fec9 100644 --- a/src/modules/email/DTO/send-email.dto.ts +++ b/src/modules/email/DTO/send-email.dto.ts @@ -215,3 +215,8 @@ export class SendEmailDto { @ApiPropertyOptional({ description: "Optional envelope (optional)" }) envelope?: EmailEnvelopeDto; } + +//######################################################## +export class UpdateDraftDto extends SendEmailDto { + // Draft ID is passed in URL parameter, not in body +} diff --git a/src/modules/email/email.controller.ts b/src/modules/email/email.controller.ts index 147b00f..4f0d331 100644 --- a/src/modules/email/email.controller.ts +++ b/src/modules/email/email.controller.ts @@ -1,10 +1,10 @@ import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from "@nestjs/common"; import { ApiOperation, ApiResponse } from "@nestjs/swagger"; -import { QueueIdParamDto, UserMailboxMessageParamDto } from "./DTO/email-params.dto"; +import { MessageParamDto, QueueIdParamDto } from "./DTO/email-params.dto"; import { MessageListQueryDto } from "./DTO/email-query.dto"; import { SearchMessagesQueryDto } from "./DTO/email-query.dto"; -import { SendEmailDto } from "./DTO/send-email.dto"; +import { SendEmailDto, UpdateDraftDto } from "./DTO/send-email.dto"; import { EmailService } from "./services/email.service"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { UserDec } from "../../common/decorators/user.decorator"; @@ -31,28 +31,20 @@ export class EmailController { return this.emailService.getEmailStatus(params.queueId); } - @Get("messages/inbox") - @ApiOperation({ summary: "List messages in a inbox" }) - @ApiResponse({ status: 200, description: "List of messages" }) - @ApiResponse({ status: 404, description: "Mailbox not found" }) - listMessages(@UserDec("wildduckUserId") userId: string, @UserDec("inboxId") inboxId: string, @Query() query: MessageListQueryDto) { - return this.emailService.listMessages(userId, inboxId, query); - } - @Get("messages/inbox/:messageId") @ApiOperation({ summary: "Get a specific message" }) @ApiResponse({ status: 200, description: "Message details" }) @ApiResponse({ status: 404, description: "Message not found" }) - getMessage(@UserDec("wildduckUserId") userId: string, @UserDec("inboxId") inboxId: string, @Param() params: UserMailboxMessageParamDto) { - return this.emailService.getMessage(userId, inboxId, params.messageId); + getMessage(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto) { + return this.emailService.getMessage(userId, params.messageId); } @Delete("messages/inbox/:messageId") @ApiOperation({ summary: "Delete a message" }) @ApiResponse({ status: 200, description: "Message deleted successfully" }) @ApiResponse({ status: 404, description: "Message not found" }) - deleteMessage(@UserDec("wildduckUserId") userId: string, @UserDec("inboxId") inboxId: string, @Param() params: UserMailboxMessageParamDto) { - return this.emailService.deleteMessage(userId, inboxId, params.messageId); + deleteMessage(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto) { + return this.emailService.deleteMessage(userId, params.messageId); } @Get("search") @@ -66,23 +58,67 @@ export class EmailController { @ApiOperation({ summary: "Mark a message as seen" }) @ApiResponse({ status: 200, description: "Message marked as seen successfully" }) @ApiResponse({ status: 404, description: "Message not found" }) - markMessageAsSeen(@UserDec("wildduckUserId") userId: string, @UserDec("inboxId") inboxId: string, @Param() params: UserMailboxMessageParamDto) { - return this.emailService.markMessageAsSeen(userId, inboxId, Number(params.messageId)); + markMessageAsSeen(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto) { + return this.emailService.markMessageAsSeen(userId, Number(params.messageId)); + } + + @Get("messages/inbox") + @ApiOperation({ summary: "List messages in a inbox" }) + @ApiResponse({ status: 200, description: "List of messages" }) + @ApiResponse({ status: 404, description: "Mailbox not found" }) + listMessages(@UserDec("wildduckUserId") userId: string, @Query() query: MessageListQueryDto) { + return this.emailService.listMessages(userId, query); } @Get("messages/sent") @ApiOperation({ summary: "List messages in sent mailbox" }) @ApiResponse({ status: 200, description: "List of sent messages" }) @ApiResponse({ status: 404, description: "Sent mailbox not found" }) - getSentMessages(@UserDec("wildduckUserId") userId: string, @UserDec("sentId") sentId: string, @Query() query: MessageListQueryDto) { - return this.emailService.getSentMessages(userId, sentId, query); + getSentMessages(@UserDec("wildduckUserId") userId: string, @Query() query: MessageListQueryDto) { + return this.emailService.getSentMessages(userId, query); } @Get("messages/trash") @ApiOperation({ summary: "List messages in trash mailbox" }) @ApiResponse({ status: 200, description: "List of trash messages" }) @ApiResponse({ status: 404, description: "Trash mailbox not found" }) - getTrashMessages(@UserDec("wildduckUserId") userId: string, @UserDec("trashId") trashId: string, @Query() query: MessageListQueryDto) { - return this.emailService.getTrashMessages(userId, trashId, query); + getTrashMessages(@UserDec("wildduckUserId") userId: string, @Query() query: MessageListQueryDto) { + return this.emailService.getTrashMessages(userId, query); + } + + @Get("messages/drafts") + @ApiOperation({ summary: "List messages in drafts mailbox" }) + @ApiResponse({ status: 200, description: "List of drafts messages" }) + @ApiResponse({ status: 404, description: "Drafts mailbox not found" }) + getDraftsMessages(@UserDec("wildduckUserId") userId: string, @Query() query: MessageListQueryDto) { + return this.emailService.getDraftsMessages(userId, query); + } + + @Patch("messages/drafts/:messageId") + @ApiOperation({ summary: "Update an existing draft" }) + @ApiResponse({ status: 200, description: "Draft updated successfully" }) + @ApiResponse({ status: 400, description: "Invalid draft data" }) + @ApiResponse({ status: 404, description: "Draft not found" }) + @ApiResponse({ status: 403, description: "Not authorized to update draft" }) + updateDraft(@UserDec("wildduckUserId") userEmailId: string, @Param() params: MessageParamDto, @Body() updateDraftDto: UpdateDraftDto) { + return this.emailService.updateDraft(userEmailId, Number(params.messageId), updateDraftDto); + } + + @Post("messages/drafts/:messageId/send") + @ApiOperation({ summary: "Send a draft message" }) + @ApiResponse({ status: 200, description: "Draft sent successfully" }) + @ApiResponse({ status: 404, description: "Draft not found" }) + @ApiResponse({ status: 403, description: "Not authorized to send draft" }) + sendDraft(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto) { + return this.emailService.sendDraft(userId, Number(params.messageId)); + } + + @Delete("messages/drafts/:messageId") + @ApiOperation({ summary: "Delete a draft message" }) + @ApiResponse({ status: 200, description: "Draft deleted successfully" }) + @ApiResponse({ status: 404, description: "Draft not found" }) + @ApiResponse({ status: 403, description: "Not authorized to delete draft" }) + deleteDraft(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto) { + return this.emailService.deleteDraft(userId, Number(params.messageId)); } } diff --git a/src/modules/email/email.module.ts b/src/modules/email/email.module.ts index 6120fba..f513d6d 100644 --- a/src/modules/email/email.module.ts +++ b/src/modules/email/email.module.ts @@ -2,13 +2,14 @@ import { Module } from "@nestjs/common"; import { EmailController } from "./email.controller"; import { EmailService } from "./services/email.service"; +import { MailboxResolverService } from "./services/mailbox-resolver.service"; import { MailServerModule } from "../mail-server/mail-server.module"; import { UsersModule } from "../users/users.module"; @Module({ imports: [MailServerModule, UsersModule], controllers: [EmailController], - providers: [EmailService], - exports: [EmailService], + providers: [EmailService, MailboxResolverService], + exports: [EmailService, MailboxResolverService], }) export class EmailModule {} diff --git a/src/modules/email/services/email.service.ts b/src/modules/email/services/email.service.ts index 7769dff..9a3ec46 100644 --- a/src/modules/email/services/email.service.ts +++ b/src/modules/email/services/email.service.ts @@ -1,10 +1,11 @@ import { Injectable, Logger } from "@nestjs/common"; import { firstValueFrom } from "rxjs"; +import { MailboxResolverService } from "./mailbox-resolver.service"; import { EmailMessage } from "../../../common/enums/message.enum"; import { MailServerService } from "../../mail-server/services/mail-server.service"; import { MessageListQueryDto, SearchMessagesQueryDto } from "../DTO/email-query.dto"; -import { SendEmailDto } from "../DTO/send-email.dto"; +import { SendEmailDto, UpdateDraftDto } from "../DTO/send-email.dto"; @Injectable() export class EmailService { @@ -12,6 +13,7 @@ export class EmailService { constructor( private readonly mailServerService: MailServerService, + private readonly mailboxResolverService: MailboxResolverService, // private readonly userService: UsersService, ) {} @@ -82,13 +84,14 @@ export class EmailService { } //######################################################## - async listMessages(userId: string, inboxId: string, query: MessageListQueryDto) { - this.logger.log(`Listing messages in mailbox ${inboxId} for user: ${userId}`); - + async listMessages(userId: string, query: MessageListQueryDto) { try { - const { results, total: count } = await firstValueFrom(this.mailServerService.messages.listMessages(userId, inboxId, query)); + const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); + this.logger.log(`Listing messages in mailbox ${inboxMailboxId} for user: ${userId}`); - this.logger.log(`Found ${count} messages in mailbox ${inboxId} for user: ${userId}`); + const { results, total: count } = await firstValueFrom(this.mailServerService.messages.listMessages(userId, inboxMailboxId, query)); + + this.logger.log(`Found ${count} messages in mailbox ${inboxMailboxId} for user: ${userId}`); return { message: EmailMessage.MESSAGES_LISTED_SUCCESSFULLY, @@ -97,20 +100,19 @@ export class EmailService { paginate: true, }; } catch (error) { - this.logger.error( - `Failed to list messages for mailbox ${inboxId} and user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`, - ); + this.logger.error(`Failed to list messages for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } //######################################################## - async getMessage(userId: string, inboxId: string, messageId: number) { - this.logger.log(`Getting message ${messageId} from inbox ${inboxId} for user: ${userId}`); - + async getMessage(userId: string, messageId: number) { try { - await this.markMessageAsSeen(userId, inboxId, messageId); - const message = await firstValueFrom(this.mailServerService.messages.getMessage(userId, inboxId, messageId)); + const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); + this.logger.log(`Getting message ${messageId} from inbox ${inboxMailboxId} for user: ${userId}`); + + await this.markMessageAsSeen(userId, messageId); + const message = await firstValueFrom(this.mailServerService.messages.getMessage(userId, inboxMailboxId, messageId)); this.logger.log(`Retrieved message ${messageId} for user: ${userId}`); @@ -124,9 +126,10 @@ export class EmailService { } //######################################################## - async deleteMessage(userId: string, inboxId: string, messageId: number) { + async deleteMessage(userId: string, messageId: number) { try { - const result = await firstValueFrom(this.mailServerService.messages.deleteMessage(userId, inboxId, messageId)); + const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); + const result = await firstValueFrom(this.mailServerService.messages.deleteMessage(userId, inboxMailboxId, messageId)); return { success: true, @@ -140,9 +143,10 @@ export class EmailService { } //============================================== - async markMessageAsSeen(userId: string, inboxId: string, messageId: number) { + async markMessageAsSeen(userId: string, messageId: number) { try { - const result = await firstValueFrom(this.mailServerService.messages.updateMessage(userId, inboxId, messageId, { seen: true })); + const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId); + const result = await firstValueFrom(this.mailServerService.messages.updateMessage(userId, inboxMailboxId, messageId, { seen: true })); return { success: true, @@ -158,14 +162,15 @@ export class EmailService { } //============================================== - async getSentMessages(userId: string, sentId: string, query: MessageListQueryDto) { + async getSentMessages(userId: string, query: MessageListQueryDto) { try { - const result = await firstValueFrom(this.mailServerService.messages.listMessages(userId, sentId, query)); + const sentMailboxId = await this.mailboxResolverService.getSentMailboxId(userId); + const { results: sentMails, total: count } = await firstValueFrom(this.mailServerService.messages.listMessages(userId, sentMailboxId, query)); return { - success: true, - message: EmailMessage.SENT_MESSAGES_RETRIEVED_SUCCESSFULLY, - data: result, + sentMails, + count, + paginate: true, }; } catch (error) { this.logger.error(`Failed to get sent messages for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); @@ -174,18 +179,133 @@ export class EmailService { } //============================================== - async getTrashMessages(userId: string, trashId: string, query: MessageListQueryDto) { + async getTrashMessages(userId: string, query: MessageListQueryDto) { try { - const result = await firstValueFrom(this.mailServerService.messages.listMessages(userId, trashId, query)); - + const trashMailboxId = await this.mailboxResolverService.getTrashMailboxId(userId); + const { results: trashMails, total: count } = await firstValueFrom(this.mailServerService.messages.listMessages(userId, trashMailboxId, query)); return { - success: true, - message: EmailMessage.TRASH_MESSAGES_RETRIEVED_SUCCESSFULLY, - data: result, + trashMails, + count, + paginate: true, }; } catch (error) { this.logger.error(`Failed to get trash messages for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } + + async getDraftsMessages(userId: string, query: MessageListQueryDto) { + try { + const draftsMailboxId = await this.mailboxResolverService.getDraftsMailboxId(userId); + + const { results: draftsMail, total: count } = await firstValueFrom( + this.mailServerService.messages.listMessages(userId, draftsMailboxId, query), + ); + return { + draftsMail, + count, + paginate: true, + }; + } catch (error) { + this.logger.error(`Failed to get drafts messages for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); + throw error; + } + } + + //============================================== + async updateDraft(userEmailId: string, messageId: number, updateDraftDto: UpdateDraftDto) { + this.logger.log(`Updating draft ${messageId} for user ${userEmailId}`); + + try { + const draftsMailboxId = await this.mailboxResolverService.getDraftsMailboxId(userEmailId); + const existingDraft = await firstValueFrom(this.mailServerService.messages.getMessage(userEmailId, draftsMailboxId, messageId)); + + const draftData: SendEmailDto = { + mailbox: updateDraftDto.mailbox, + from: updateDraftDto.from || { address: existingDraft.from?.address || "" }, + to: updateDraftDto.to || [], + cc: updateDraftDto.cc, + bcc: updateDraftDto.bcc, + replyTo: updateDraftDto.replyTo, + headers: updateDraftDto.headers, + subject: updateDraftDto.subject, + text: updateDraftDto.text, + html: updateDraftDto.html, + attachments: updateDraftDto.attachments, + meta: updateDraftDto.meta, + sess: updateDraftDto.sess, + ip: updateDraftDto.ip, + reference: updateDraftDto.reference, + isDraft: true, + uploadOnly: true, + draft: { + mailbox: draftsMailboxId, + id: messageId, + }, + }; + + const response = await firstValueFrom(this.mailServerService.submission.submitMessage(userEmailId, draftData)); + + this.logger.log(`Draft updated successfully: ${response.id}`); + + return { + message: EmailMessage.DRAFT_UPDATED_SUCCESSFULLY, + messageId: response.id, + from: response.from, + to: response.to, + subject: response.subject || "Draft", + updated: response.created, + isDraft: true, + }; + } catch (error) { + this.logger.error(`Failed to update draft ${messageId} for user ${userEmailId}: ${error instanceof Error ? error.message : "Unknown error"}`); + throw error; + } + } + + //============================================== + async sendDraft(userId: string, messageId: number) { + this.logger.log(`Sending draft ${messageId} for user: ${userId}`); + + try { + const draftsMailboxId = await this.mailboxResolverService.getDraftsMailboxId(userId); + const result = await firstValueFrom( + this.mailServerService.messages.submitDraft(userId, draftsMailboxId, messageId, { + deleteFiles: false, + }), + ); + + this.logger.log(`Draft ${messageId} sent successfully`); + + return { + message: EmailMessage.DRAFT_SENT_SUCCESSFULLY, + messageId: result.id, + queueId: result.queueId, + result, + }; + } catch (error) { + this.logger.error(`Failed to send draft ${messageId} for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); + throw error; + } + } + + //============================================== + async deleteDraft(userId: string, messageId: number) { + this.logger.log(`Deleting draft ${messageId} for user: ${userId}`); + + try { + const draftsMailboxId = await this.mailboxResolverService.getDraftsMailboxId(userId); + const result = await firstValueFrom(this.mailServerService.messages.deleteMessage(userId, draftsMailboxId, messageId)); + + this.logger.log(`Draft ${messageId} deleted successfully`); + + return { + message: EmailMessage.DRAFT_DELETED_SUCCESSFULLY, + result, + }; + } catch (error) { + this.logger.error(`Failed to delete draft ${messageId} for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); + throw error; + } + } } diff --git a/src/modules/email/services/mailbox-resolver.service.ts b/src/modules/email/services/mailbox-resolver.service.ts new file mode 100644 index 0000000..3b91161 --- /dev/null +++ b/src/modules/email/services/mailbox-resolver.service.ts @@ -0,0 +1,158 @@ +import { Injectable, Logger, NotFoundException } from "@nestjs/common"; +import { firstValueFrom } from "rxjs"; + +import { MailboxEnum } from "../../mail-server/enums/mailbox.enum"; +import { MailServerService } from "../../mail-server/services/mail-server.service"; + +export interface UserMailboxIds { + inbox: string; + sent: string; + drafts: string; + trash: string; + junk?: string; + archive?: string; +} + +@Injectable() +export class MailboxResolverService { + private readonly logger = new Logger(MailboxResolverService.name); + private readonly mailboxCache = new Map(); + private readonly cacheExpiry = new Map(); + private readonly CACHE_DURATION = 5 * 60 * 1000; // 5 minutes + + constructor(private readonly mailServerService: MailServerService) {} + + /** + * Get user mailbox IDs with caching + */ + async getUserMailboxIds(userId: string): Promise { + const cached = this.getCachedMailboxIds(userId); + if (cached) { + return cached; + } + + this.logger.log(`Fetching mailbox IDs for user: ${userId}`); + + try { + const mailboxes = await firstValueFrom(this.mailServerService.mailboxes.listMailboxes(userId)); + + const mailboxIds: UserMailboxIds = { + inbox: this.findMailboxId(mailboxes.results, MailboxEnum.INBOX), + sent: this.findMailboxId(mailboxes.results, MailboxEnum.SENT), + drafts: this.findMailboxId(mailboxes.results, MailboxEnum.DRAFTS), + trash: this.findMailboxId(mailboxes.results, MailboxEnum.TRASH), + junk: this.findMailboxId(mailboxes.results, MailboxEnum.Junk, false), + archive: this.findMailboxId(mailboxes.results, MailboxEnum.ARCHIVE, false), + }; + + this.cacheMailboxIds(userId, mailboxIds); + + this.logger.log(`Mailbox IDs cached for user: ${userId}`); + return mailboxIds; + } catch (error) { + this.logger.error(`Failed to fetch mailbox IDs for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); + throw error; + } + } + + /** + * Get specific mailbox ID + */ + async getMailboxId(userId: string, mailboxType: keyof UserMailboxIds): Promise { + const mailboxIds = await this.getUserMailboxIds(userId); + const mailboxId = mailboxIds[mailboxType]; + + if (!mailboxId) { + throw new NotFoundException(`${mailboxType} mailbox not found for user ${userId}`); + } + + return mailboxId; + } + + /** + * Get drafts mailbox ID + */ + async getDraftsMailboxId(userId: string): Promise { + return this.getMailboxId(userId, "drafts"); + } + + /** + * Get inbox mailbox ID + */ + async getInboxMailboxId(userId: string): Promise { + return this.getMailboxId(userId, "inbox"); + } + + /** + * Get sent mailbox ID + */ + async getSentMailboxId(userId: string): Promise { + return this.getMailboxId(userId, "sent"); + } + + /** + * Get trash mailbox ID + */ + async getTrashMailboxId(userId: string): Promise { + return this.getMailboxId(userId, "trash"); + } + + /** + * 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}`); + } + + /** + * Clear all cache + */ + clearAllCache(): void { + this.mailboxCache.clear(); + this.cacheExpiry.clear(); + this.logger.log("All mailbox cache cleared"); + } + + /** + * 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); + + if (cached && expiry && Date.now() < expiry) { + this.logger.debug(`Using cached mailbox IDs for user: ${userId}`); + return cached; + } + + if (cached) { + this.logger.debug(`Cache expired for user: ${userId}`); + this.clearUserCache(userId); + } + + return null; + } + + /** + * 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); + } + + /** + * Find mailbox ID by name + */ + private findMailboxId(mailboxes: any[], mailboxName: string, required: boolean = true): string { + const mailbox = mailboxes.find((mb) => mb.name === mailboxName || mb.path === mailboxName || mb.specialUse === mailboxName); + + if (!mailbox && required) { + throw new NotFoundException(`${mailboxName} mailbox not found`); + } + + return mailbox?.id || ""; + } +} diff --git a/src/modules/mail-server/enums/mailbox.enum.ts b/src/modules/mail-server/enums/mailbox.enum.ts new file mode 100644 index 0000000..ff98cb1 --- /dev/null +++ b/src/modules/mail-server/enums/mailbox.enum.ts @@ -0,0 +1,9 @@ +export enum MailboxEnum { + INBOX = "INBOX", + DRAFTS = "Drafts", + ARCHIVE = "Archive", + Junk = "Junk", + SENT = "Sent Mail", + TRASH = "Trash", + SPAM = "spam", +}