import { Injectable } from "@nestjs/common"; import { Observable } from "rxjs"; import { catchError, map, throwError } from "rxjs"; import { WildDuckBaseService } from "./wildduck-base.service"; import { MailServerException } from "../../../core/exceptions/mail-server.exceptions"; import { ListMessagesQueryDto, SearchMessagesQueryDto, UpdateMessageDto, UploadMessageDto } from "../DTO/message.dto"; import { AttachmentResponse } from "../interfaces/attachment.interface"; import { MessageDeleteAllResponse, MessageDetails, MessageEventsResponse, MessageFlaggedResponse, MessageForwardResponse, MessageListResponse, MessageSearchResponse, MessageSubmitResponse, MessageUpdateResponse, MessageUploadResponse, } from "../interfaces/messages-response.interface"; import { WildDuckSuccessResponse } from "../interfaces/wildduck-response.interface"; @Injectable() export class WildDuckMessagesService extends WildDuckBaseService { /** * List messages in a mailbox */ listMessages(userId: string, mailboxId: string, query?: ListMessagesQueryDto): Observable { return this.get(`/users/${userId}/mailboxes/${mailboxId}/messages`, query); } /** * Get message details */ getMessage(userId: string, mailboxId: string, messageId: number): Observable { return this.get(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`); } /** * Update message details */ updateMessage(userId: string, mailboxId: string, messageId: number | string, data: UpdateMessageDto): Observable { return this.put(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`, data); } /** * Delete a message */ deleteMessage(userId: string, mailboxId: string, messageId: number): Observable { return this.delete(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`); } /** * Delete all messages from a mailbox */ deleteAllFromMailbox(userId: string, mailboxId: string): Observable { return this.delete(`/users/${userId}/mailboxes/${mailboxId}/messages`); } /** * Upload message to mailbox */ uploadMessage(userId: string, mailboxId: string, data: UploadMessageDto): Observable { return this.post(`/users/${userId}/mailboxes/${mailboxId}/messages`, data); } /** * Get message source (raw email) */ getMessageSource(userId: string, mailboxId: string, messageId: number): Observable { // This returns raw email content, not JSON return this.get(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/message.eml`); } /** * Get message attachment */ getMessageAttachment(userId: string, mailboxId: string, messageId: number, attachmentId: string): Observable { // This returns binary content const url = this.buildUrl(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/attachments/${attachmentId}`); this.logger.debug(`WildDuck GET: ${url}`); return this.httpService .get(url, { responseType: "stream", headers: { Accept: "*/*", }, }) .pipe( map((response) => { this.logger.debug(`HTTP ${response.status}: ${response.config?.url}`); return { success: response.data, headers: response.headers, contentType: response.headers["content-type"], contentDisposition: response.headers["content-disposition"], contentLength: response.headers["content-length"], } as AttachmentResponse; }), catchError((error) => { this.logger.error(`WildDuck API error: ${error.message}`, error.stack); if (error.response?.data?.error) { return throwError(() => new MailServerException(error.response.data.error)); } return throwError(() => error); }), ); } /** * Get message events/timeline */ getMessageEvents(userId: string, mailboxId: string, messageId: number): Observable { return this.get(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/events`); } /** * List flagged messages across all mailboxes */ listFlaggedMessages(userId: string, query?: { order?: "asc" | "desc"; limit?: number; page?: number }): Observable { return this.get(`/users/${userId}/flagged`, query); } /** * Search for messages across all mailboxes */ searchMessages(userId: string, query: SearchMessagesQueryDto): Observable { return this.get(`/users/${userId}/search`, query); } /** * Delete all messages from a mailbox */ deleteAllMessages(userId: string, mailboxId: string): Observable { return this.delete(`/users/${userId}/mailboxes/${mailboxId}/messages`); } /** * Forward stored message */ forwardMessage( userId: string, mailboxId: string, messageId: number, data: { target: number; addresses: string[]; sess?: string; ip?: string; }, ): Observable { return this.post(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/forward`, data); } /** * Submit draft for delivery */ submitDraft( userId: string, mailboxId: string, messageId: number, data?: { deleteFiles?: boolean; sess?: string; ip?: string; }, ): Observable { return this.post(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/submit`, data); } }