Files
dmail-api/src/modules/mail-server/services/wildduck-messages.service.ts
T
2025-07-22 12:37:20 +03:30

174 lines
5.9 KiB
TypeScript

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<MessageListResponse> {
return this.get<MessageListResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages`, query);
}
/**
* Get message details
*/
getMessage(userId: string, mailboxId: string, messageId: number): Observable<MessageDetails> {
return this.get<MessageDetails>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`);
}
/**
* Update message details
*/
updateMessage(userId: string, mailboxId: string, messageId: number | string, data: UpdateMessageDto): Observable<MessageUpdateResponse> {
return this.put<MessageUpdateResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`, data);
}
/**
* Delete a message
*/
deleteMessage(userId: string, mailboxId: string, messageId: number): Observable<WildDuckSuccessResponse> {
return this.delete<WildDuckSuccessResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`);
}
/**
* Delete all messages from a mailbox
*/
deleteAllFromMailbox(userId: string, mailboxId: string): Observable<MessageDeleteAllResponse> {
return this.delete<MessageDeleteAllResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages`);
}
/**
* Upload message to mailbox
*/
uploadMessage(userId: string, mailboxId: string, data: UploadMessageDto): Observable<MessageUploadResponse> {
return this.post<MessageUploadResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages`, data);
}
/**
* Get message source (raw email)
*/
getMessageSource(userId: string, mailboxId: string, messageId: number): Observable<string> {
// This returns raw email content, not JSON
return this.get<string>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/message.eml`);
}
/**
* Get message attachment
*/
getMessageAttachment(userId: string, mailboxId: string, messageId: number, attachmentId: string): Observable<AttachmentResponse> {
// 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<MessageEventsResponse> {
return this.get<MessageEventsResponse>(`/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<MessageFlaggedResponse> {
return this.get<MessageFlaggedResponse>(`/users/${userId}/flagged`, query);
}
/**
* Search for messages across all mailboxes
*/
searchMessages(userId: string, query: SearchMessagesQueryDto): Observable<MessageSearchResponse> {
return this.get<MessageSearchResponse>(`/users/${userId}/search`, query);
}
/**
* Delete all messages from a mailbox
*/
deleteAllMessages(userId: string, mailboxId: string): Observable<MessageDeleteAllResponse> {
return this.delete<MessageDeleteAllResponse>(`/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<MessageForwardResponse> {
return this.post<MessageForwardResponse>(`/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<MessageSubmitResponse> {
return this.post<MessageSubmitResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/submit`, data);
}
}