import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from "@nestjs/common"; import { ApiOperation, ApiResponse } from "@nestjs/swagger"; import { BulkActionDto } from "./DTO/bulk-actions.dto"; import { MailboxIdQueryDto, MessageParamDto, QueueIdParamDto } from "./DTO/email-params.dto"; import { MessageListQueryDto } from "./DTO/email-query.dto"; import { SearchMessagesQueryDto } from "./DTO/email-query.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"; @AuthGuards() @Controller("email") export class EmailController { constructor(private readonly emailService: EmailService) {} @Post("send") @ApiOperation({ summary: "Send an email with configurable headers based on type", description: "Send emails with automatic anti-threading and anti-spam headers. Supports different email types: general, transactional, marketing, anti-threading. Marketing emails require listId and unsubscribeUrl.", }) @ApiResponse({ status: 201, description: "Email sent successfully" }) @ApiResponse({ status: 400, description: "Invalid email data or missing required fields for email type" }) @ApiResponse({ status: 403, description: "Not authorized to send email" }) sendEmail(@UserDec("wildduckUserId") userEmailId: string, @UserDec("id") userId: string, @Body() sendEmailDto: SendEmailDto) { return this.emailService.sendEmail(userEmailId, userId, sendEmailDto); } @Get("status/:queueId") @ApiOperation({ summary: "Get email delivery status" }) @ApiResponse({ status: 200, description: "Email delivery status" }) @ApiResponse({ status: 404, description: "Email not found" }) getEmailStatus(@Param() params: QueueIdParamDto) { return this.emailService.getEmailStatus(params.queueId); } @Get("messages/: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, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.getMessage(userId, params.messageId, query.mailbox); } @Delete("messages/: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, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.deleteMessage(userId, params.messageId, query.mailbox); } @Get("search") @ApiOperation({ summary: "Search messages across all mailboxes" }) @ApiResponse({ status: 200, description: "Search results" }) searchMessages(@UserDec("wildduckUserId") userId: string, @Query() query: SearchMessagesQueryDto) { return this.emailService.searchMessages(userId, query); } @Patch("messages/:messageId/seen") @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, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.markMessageAsSeen(userId, Number(params.messageId), query.mailbox); } @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, @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, @Query() query: MessageListQueryDto) { return this.emailService.getTrashMessages(userId, query); } @Get("messages/junk") @ApiOperation({ summary: "List messages in junk mailbox" }) @ApiResponse({ status: 200, description: "List of junk messages" }) @ApiResponse({ status: 404, description: "junk mailbox not found" }) getJunkMessages(@UserDec("wildduckUserId") userId: string, @Query() query: MessageListQueryDto) { return this.emailService.getJunkMessages(userId, query); } @Get("messages/archive") @ApiOperation({ summary: "List messages in archive mailbox" }) @ApiResponse({ status: 200, description: "List of archive messages" }) @ApiResponse({ status: 404, description: "archive mailbox not found" }) getArchiveMessages(@UserDec("wildduckUserId") userId: string, @Query() query: MessageListQueryDto) { return this.emailService.getArchivedMessages(userId, query); } @Get("messages/favorite") @ApiOperation({ summary: "List messages in favorite mailbox" }) @ApiResponse({ status: 200, description: "List of favorite messages" }) @ApiResponse({ status: 404, description: "favorite mailbox not found" }) getFavoriteMessages(@UserDec("wildduckUserId") userId: string, @Query() query: MessageListQueryDto) { return this.emailService.getFavoriteMessages(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)); } @Patch("messages/:messageId/archive") @ApiOperation({ summary: "Move a message to archive mailbox" }) @ApiResponse({ status: 200, description: "Message moved to archive successfully" }) @ApiResponse({ status: 404, description: "Message not found" }) @ApiResponse({ status: 403, description: "Not authorized to move message" }) moveMessageToArchive(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.moveMessageToArchive(userId, Number(params.messageId), query.mailbox); } @Patch("messages/:messageId/favorite") @ApiOperation({ summary: "Move a message to favorite mailbox" }) @ApiResponse({ status: 200, description: "Message moved to favorite successfully" }) @ApiResponse({ status: 404, description: "Message not found" }) @ApiResponse({ status: 403, description: "Not authorized to move message" }) moveMessageToFavorite(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.moveMessageToFavorite(userId, Number(params.messageId), query.mailbox); } @Patch("messages/:messageId/trash") @ApiOperation({ summary: "Move a message to trash mailbox" }) @ApiResponse({ status: 200, description: "Message moved to trash successfully" }) @ApiResponse({ status: 404, description: "Message not found" }) @ApiResponse({ status: 403, description: "Not authorized to move message" }) moveMessageToTrash(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.moveMessageToTrash(userId, Number(params.messageId), query.mailbox); } @Patch("messages/:messageId/unarchive") @ApiOperation({ summary: "Move a message from archive back to inbox" }) @ApiResponse({ status: 200, description: "Message moved from archive to inbox successfully" }) @ApiResponse({ status: 404, description: "Message not found in archive" }) @ApiResponse({ status: 403, description: "Not authorized to move message" }) moveMessageToInboxFromArchive(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.moveMessageToInboxFromArchive(userId, Number(params.messageId), query.mailbox); } @Patch("messages/:messageId/unfavorite") @ApiOperation({ summary: "Move a message from favorite back to inbox" }) @ApiResponse({ status: 200, description: "Message moved from favorite to inbox successfully" }) @ApiResponse({ status: 404, description: "Message not found in favorite" }) @ApiResponse({ status: 403, description: "Not authorized to move message" }) moveMessageToInboxFromFavorite(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.moveMessageToInboxFromFavorite(userId, Number(params.messageId), query.mailbox); } @Patch("messages/:messageId/restore") @ApiOperation({ summary: "Restore a message from trash back to inbox" }) @ApiResponse({ status: 200, description: "Message restored from trash to inbox successfully" }) @ApiResponse({ status: 404, description: "Message not found in trash" }) @ApiResponse({ status: 403, description: "Not authorized to restore message" }) moveMessageToInboxFromTrash(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.moveMessageToInboxFromTrash(userId, Number(params.messageId), query.mailbox); } @Patch("messages/:messageId/junk") @ApiOperation({ summary: "Move a message to junk mailbox" }) @ApiResponse({ status: 200, description: "Message moved to junk successfully" }) @ApiResponse({ status: 404, description: "Message not found" }) @ApiResponse({ status: 403, description: "Not authorized to move message" }) moveMessageToJunk(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.moveMessageToJunk(userId, Number(params.messageId), query.mailbox); } @Patch("messages/:messageId/not-junk") @ApiOperation({ summary: "Move a message from junk back to inbox (not spam)" }) @ApiResponse({ status: 200, description: "Message moved from junk to inbox successfully" }) @ApiResponse({ status: 404, description: "Message not found in junk" }) @ApiResponse({ status: 403, description: "Not authorized to move message" }) moveMessageToInboxFromJunk(@UserDec("wildduckUserId") userId: string, @Param() params: MessageParamDto, @Query() query: MailboxIdQueryDto) { return this.emailService.moveMessageToInboxFromJunk(userId, Number(params.messageId), query.mailbox); } @Post("messages/bulk-action") @ApiOperation({ summary: "Perform bulk actions on multiple messages", description: "Apply actions (seen, delete, archive, unarchive, favorite, unfavorite, junk, notjunk, trash, restore) to multiple messages at once", }) @ApiResponse({ status: 200, description: "Bulk action completed successfully" }) @ApiResponse({ status: 206, description: "Bulk action partially completed" }) @ApiResponse({ status: 400, description: "Invalid bulk action data" }) @ApiResponse({ status: 403, description: "Not authorized to perform bulk action" }) performBulkAction(@UserDec("wildduckUserId") userId: string, @Body() bulkActionDto: BulkActionDto, @Query() query: MailboxIdQueryDto) { return this.emailService.performBulkAction(userId, bulkActionDto, query.mailbox); } // // Domain Access Management Endpoints // @Get("spam/domains/allowed") // @ApiOperation({ summary: "List domains in allowlist (never marked as spam)" }) // @ApiResponse({ status: 200, description: "List of allowed domains" }) // listAllowedDomains(@UserDec("id") userId: string, @Query() query: ListDomainAccessQueryDto) { // return this.emailSpamService.listAllowedDomains(userId, query); // } // @Get("spam/domains/blocked") // @ApiOperation({ summary: "List domains in blocklist (always marked as spam)" }) // @ApiResponse({ status: 200, description: "List of blocked domains" }) // listBlockedDomains(@UserDec("id") userId: string, @Query() query: ListDomainAccessQueryDto) { // return this.emailSpamService.listBlockedDomains(userId, query); // } // @Post("spam/domains/allowed") // @ApiOperation({ summary: "Add domain to allowlist" }) // @ApiResponse({ status: 201, description: "Domain added to allowlist successfully" }) // @ApiResponse({ status: 400, description: "Invalid domain data" }) // addDomainToAllowlist(@UserDec("id") userId: string, @Body() createDomainDto: CreateDomainAccessDto) { // return this.emailSpamService.addDomainToAllowlist(createDomainDto.domain, createDomainDto.description, userId); // } // @Post("spam/domains/blocked") // @ApiOperation({ summary: "Add domain to blocklist" }) // @ApiResponse({ status: 201, description: "Domain added to blocklist successfully" }) // @ApiResponse({ status: 400, description: "Invalid domain data" }) // addDomainToBlocklist(@UserDec("id") userId: string, @Body() createDomainDto: CreateDomainAccessDto) { // return this.emailSpamService.addDomainToBlocklist(createDomainDto.domain, createDomainDto.description, userId); // } // @Delete("spam/domains/allowed/:domain") // @ApiOperation({ summary: "Remove domain from allowlist" }) // @ApiResponse({ status: 200, description: "Domain removed from allowlist successfully" }) // @ApiResponse({ status: 404, description: "Domain not found in allowlist" }) // removeDomainFromAllowlist(@UserDec("id") userId: string, @Param("domain") domain: string) { // return this.emailSpamService.removeDomainFromAllowlist(domain, userId); // } // @Delete("spam/domains/blocked/:domain") // @ApiOperation({ summary: "Remove domain from blocklist" }) // @ApiResponse({ status: 200, description: "Domain removed from blocklist successfully" }) // @ApiResponse({ status: 404, description: "Domain not found in blocklist" }) // removeDomainFromBlocklist(@UserDec("id") userId: string, @Param("domain") domain: string) { // return this.emailSpamService.removeDomainFromBlocklist(domain, userId); // } }