Files
dmail-api/src/modules/email/services/email.service.ts
T
2025-07-10 10:55:35 +03:30

312 lines
12 KiB
TypeScript

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, UpdateDraftDto } from "../DTO/send-email.dto";
@Injectable()
export class EmailService {
private readonly logger = new Logger(EmailService.name);
constructor(
private readonly mailServerService: MailServerService,
private readonly mailboxResolverService: MailboxResolverService,
// private readonly userService: UsersService,
) {}
//########################################################
async sendEmail(userEmailId: string, sendEmailDto: SendEmailDto) {
// const userEmailId = await this.userService.getUserEmailIdFromId(userId);
this.logger.log(`Sending email from user ${userEmailId} to ${sendEmailDto.to.map((t) => t.address).join(", ")}`);
try {
const response = await firstValueFrom(this.mailServerService.submission.submitMessage(userEmailId, sendEmailDto));
this.logger.log(`Email sent successfully: ${response.id} (Queue: ${response.queueId})`);
return {
message: EmailMessage.EMAIL_SENDING_SUCCESS,
messageId: response.id,
queueId: response.queueId,
from: response.from,
to: response.to,
subject: response.subject,
created: response.created,
};
} catch (error) {
this.logger.error(`Failed to send email for user ${userEmailId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
//########################################################
async getEmailStatus(queueId: string) {
this.logger.log(`Getting email status for queue: ${queueId}`);
try {
const response = await firstValueFrom(this.mailServerService.submission.getQueueStatus(queueId));
this.logger.log(`Retrieved status for queue ${queueId}: ${response.status}`);
return {
message: EmailMessage.EMAIL_STATUS_RETRIEVED_SUCCESSFULLY,
...response,
};
} catch (error) {
this.logger.error(`Failed to get email status for queue ${queueId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
//########################################################
async searchMessages(userId: string, query: SearchMessagesQueryDto) {
this.logger.log(`Searching messages for user ${userId} with query: ${query.q}`);
try {
const response = await firstValueFrom(
this.mailServerService.messages.searchMessages(userId, { query: query.q || "", limit: query.limit, page: query.page }),
);
this.logger.log(`Found ${response.results.length} messages matching search for user: ${userId}`);
return {
message: EmailMessage.MESSAGES_SEARCHED_SUCCESSFULLY,
...response,
};
} catch (error) {
this.logger.error(`Failed to search messages for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
//########################################################
async listMessages(userId: string, query: MessageListQueryDto) {
try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId);
this.logger.log(`Listing messages in mailbox ${inboxMailboxId} 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,
results,
count,
paginate: true,
};
} catch (error) {
this.logger.error(`Failed to list messages for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
//########################################################
async getMessage(userId: string, messageId: number) {
try {
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}`);
return {
message,
};
} catch (error) {
this.logger.error(`Failed to get message ${messageId} for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
//########################################################
async deleteMessage(userId: string, messageId: number) {
try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId);
const result = await firstValueFrom(this.mailServerService.messages.deleteMessage(userId, inboxMailboxId, messageId));
return {
success: true,
message: EmailMessage.MESSAGE_DELETED_SUCCESSFULLY,
result,
};
} catch (error) {
this.logger.error(`Failed to delete message ${messageId} for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
//==============================================
async markMessageAsSeen(userId: string, messageId: number) {
try {
const inboxMailboxId = await this.mailboxResolverService.getInboxMailboxId(userId);
const result = await firstValueFrom(this.mailServerService.messages.updateMessage(userId, inboxMailboxId, messageId, { seen: true }));
return {
success: true,
message: EmailMessage.MESSAGE_MARKED_AS_SEEN_SUCCESSFULLY,
data: result,
};
} catch (error) {
this.logger.error(
`Failed to mark message ${messageId} as seen for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`,
);
throw error;
}
}
//==============================================
async getSentMessages(userId: string, query: MessageListQueryDto) {
try {
const sentMailboxId = await this.mailboxResolverService.getSentMailboxId(userId);
const { results: sentMails, total: count } = await firstValueFrom(this.mailServerService.messages.listMessages(userId, sentMailboxId, query));
return {
sentMails,
count,
paginate: true,
};
} catch (error) {
this.logger.error(`Failed to get sent messages for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
//==============================================
async getTrashMessages(userId: string, query: MessageListQueryDto) {
try {
const trashMailboxId = await this.mailboxResolverService.getTrashMailboxId(userId);
const { results: trashMails, total: count } = await firstValueFrom(this.mailServerService.messages.listMessages(userId, trashMailboxId, query));
return {
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;
}
}
}