fix: bug in the template
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional, PartialType } from "@nestjs/swagger";
|
import { ApiProperty, ApiPropertyOptional, PartialType } from "@nestjs/swagger";
|
||||||
import { Type } from "class-transformer";
|
import { Exclude, Type } from "class-transformer";
|
||||||
import {
|
import {
|
||||||
IsArray,
|
IsArray,
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
@@ -120,10 +120,7 @@ export class EmailEnvelopeDto {
|
|||||||
|
|
||||||
//########################################################
|
//########################################################
|
||||||
export class SendEmailDto {
|
export class SendEmailDto {
|
||||||
// @IsNotEmpty({ message: EmailMessage.FROM_ADDRESS_REQUIRED })
|
@Exclude()
|
||||||
// @ValidateNested()
|
|
||||||
// @Type(() => EmailRecipientDto)
|
|
||||||
// @ApiProperty({ description: "Address for the From: header" })
|
|
||||||
from: EmailRecipientDto;
|
from: EmailRecipientDto;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@@ -153,17 +150,9 @@ export class SendEmailDto {
|
|||||||
@ApiPropertyOptional({ description: "Addresses for the Bcc: header (optional)", type: [EmailRecipientDto] })
|
@ApiPropertyOptional({ description: "Addresses for the Bcc: header (optional)", type: [EmailRecipientDto] })
|
||||||
bcc?: EmailRecipientDto[];
|
bcc?: EmailRecipientDto[];
|
||||||
|
|
||||||
// @IsOptional()
|
@Exclude()
|
||||||
// @IsArray({ message: EmailMessage.HEADERS_MUST_BE_ARRAY })
|
|
||||||
// @ValidateNested({ each: true })
|
|
||||||
// @Type(() => EmailHeaderDto)
|
|
||||||
// @ApiPropertyOptional({
|
|
||||||
// description: "Custom headers for the message. If reference message is set then In-Reply-To and References headers are set automatically",
|
|
||||||
// type: [EmailHeaderDto],
|
|
||||||
// })
|
|
||||||
headers?: EmailHeaderDto[];
|
headers?: EmailHeaderDto[];
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
@IsNotEmpty({ message: EmailMessage.SUBJECT_REQUIRED })
|
@IsNotEmpty({ message: EmailMessage.SUBJECT_REQUIRED })
|
||||||
@IsString({ message: EmailMessage.SUBJECT_MUST_BE_STRING })
|
@IsString({ message: EmailMessage.SUBJECT_MUST_BE_STRING })
|
||||||
@ApiPropertyOptional({ description: "Message subject. If not then resolved from Reference message (optional)", example: "Test email" })
|
@ApiPropertyOptional({ description: "Message subject. If not then resolved from Reference message (optional)", example: "Test email" })
|
||||||
@@ -188,24 +177,6 @@ export class SendEmailDto {
|
|||||||
@ApiPropertyOptional({ description: "Attachments for the message (optional)", type: [EmailAttachmentDto] })
|
@ApiPropertyOptional({ description: "Attachments for the message (optional)", type: [EmailAttachmentDto] })
|
||||||
attachments?: EmailAttachmentDto[];
|
attachments?: EmailAttachmentDto[];
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@ApiPropertyOptional({ description: "Optional metadata, must be an object or JSON formatted string (optional)" })
|
|
||||||
meta?: Record<string, unknown>;
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ message: EmailMessage.SESSION_ID_MUST_BE_STRING })
|
|
||||||
@ApiPropertyOptional({ description: "Session identifier for the logs (optional)" })
|
|
||||||
sess?: string;
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ message: EmailMessage.IP_ADDRESS_MUST_BE_STRING })
|
|
||||||
@ApiPropertyOptional({ description: "IP address for the logs (optional)" })
|
|
||||||
ip?: string;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @ApiPropertyOptional({ description: "Reference message data (optional)" })
|
|
||||||
// reference?: any;
|
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsBoolean({ message: EmailMessage.IS_DRAFT_MUST_BE_BOOLEAN })
|
@IsBoolean({ message: EmailMessage.IS_DRAFT_MUST_BE_BOOLEAN })
|
||||||
@ApiPropertyOptional({ description: "Is the message a draft or not (optional)", default: false })
|
@ApiPropertyOptional({ description: "Is the message a draft or not (optional)", default: false })
|
||||||
@@ -237,62 +208,6 @@ export class SendEmailDto {
|
|||||||
@Type(() => EmailEnvelopeDto)
|
@Type(() => EmailEnvelopeDto)
|
||||||
@ApiPropertyOptional({ description: "Optional envelope (optional)" })
|
@ApiPropertyOptional({ description: "Optional envelope (optional)" })
|
||||||
envelope?: EmailEnvelopeDto;
|
envelope?: EmailEnvelopeDto;
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsEnum(EmailType, { message: "Email type must be one of: general, transactional, marketing, anti-threading" })
|
|
||||||
// @ApiPropertyOptional({
|
|
||||||
// description: "Email type for appropriate header configuration",
|
|
||||||
// enum: EmailType,
|
|
||||||
// default: EmailType.GENERAL,
|
|
||||||
// example: EmailType.TRANSACTIONAL,
|
|
||||||
// })
|
|
||||||
// emailType?: EmailType;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsString({ message: EmailMessage.HEADER_VALUE_MUST_BE_STRING })
|
|
||||||
// @ApiPropertyOptional({ description: "Transaction ID for transactional emails (optional)", example: "ORDER-123456" })
|
|
||||||
// transactionId?: string;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsString({ message: EmailMessage.HEADER_VALUE_MUST_BE_STRING })
|
|
||||||
// @ApiPropertyOptional({ description: "Category for transactional emails (optional)", example: "order-confirmation" })
|
|
||||||
// category?: string;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsString({ message: EmailMessage.HEADER_VALUE_MUST_BE_STRING })
|
|
||||||
// @ApiPropertyOptional({ description: "List ID for marketing emails (optional)", example: "newsletter-subscribers" })
|
|
||||||
// listId?: string;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsString({ message: EmailMessage.HEADER_VALUE_MUST_BE_STRING })
|
|
||||||
// @ApiPropertyOptional({ description: "Unsubscribe URL for marketing emails (optional)", example: "https://yourdomain.com/unsubscribe?token=xyz" })
|
|
||||||
// unsubscribeUrl?: string;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsString({ message: EmailMessage.HEADER_VALUE_MUST_BE_STRING })
|
|
||||||
// @ApiPropertyOptional({ description: "Campaign ID for marketing emails (optional)", example: "CAMPAIGN-2024-001" })
|
|
||||||
// campaignId?: string;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsEnum(Priority, { message: EmailMessage.PRIORITY_MUST_BE_ONE_OF_HIGH_NORMAL_LOW })
|
|
||||||
// @ApiPropertyOptional({ description: "Email priority (optional)", enum: Priority, default: Priority.Normal })
|
|
||||||
// priority?: Priority;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsBoolean({ message: EmailMessage.IS_DRAFT_MUST_BE_BOOLEAN })
|
|
||||||
// @ApiPropertyOptional({ description: "Force Gmail thread break for anti-threading emails (optional)", default: false })
|
|
||||||
// forceGmailBreak?: boolean;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsString({ message: EmailMessage.HEADER_VALUE_MUST_BE_STRING })
|
|
||||||
// @ApiPropertyOptional({ description: "Conversation breaker for anti-threading emails (optional)" })
|
|
||||||
// conversationBreaker?: string;
|
|
||||||
|
|
||||||
// @IsOptional()
|
|
||||||
// @IsNotEmpty()
|
|
||||||
// @IsString({ message: EmailMessage.MAILBOX_MUST_BE_STRING })
|
|
||||||
// @ApiPropertyOptional({ description: "ID of the Mailbox (optional)", example: "507f1f77bcf86cd799439012" })
|
|
||||||
// mailbox?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//########################################################
|
//########################################################
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { EmailMessage } from "../../../common/enums/message.enum";
|
|||||||
import { EmailNotificationService } from "../../email-utils/services/email-notification.service";
|
import { EmailNotificationService } from "../../email-utils/services/email-notification.service";
|
||||||
import { MailboxResolverService } from "../../email-utils/services/mailbox-resolver.service";
|
import { MailboxResolverService } from "../../email-utils/services/mailbox-resolver.service";
|
||||||
import { SearchMessagesMailServerQueryDto } from "../../mail-server/DTO/message.dto";
|
import { SearchMessagesMailServerQueryDto } from "../../mail-server/DTO/message.dto";
|
||||||
import { MessageHeaders } from "../../mail-server/interfaces/messages-response.interface";
|
|
||||||
import { MailServerService } from "../../mail-server/services/mail-server.service";
|
import { MailServerService } from "../../mail-server/services/mail-server.service";
|
||||||
import { TemplateProcessorService } from "../../templates/services/template-processor.service";
|
import { TemplateProcessorService } from "../../templates/services/template-processor.service";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
@@ -18,7 +17,7 @@ import { UserRepository } from "../../users/repositories/user.repository";
|
|||||||
import { EMAIL_QUEUE_CONSTANTS } from "../constants/email-events.constant";
|
import { EMAIL_QUEUE_CONSTANTS } from "../constants/email-events.constant";
|
||||||
import { BulkActionDto, BulkActionType } from "../DTO/bulk-actions.dto";
|
import { BulkActionDto, BulkActionType } from "../DTO/bulk-actions.dto";
|
||||||
import { MessageListQueryDto, SearchMessagesQueryDto } from "../DTO/email-query.dto";
|
import { MessageListQueryDto, SearchMessagesQueryDto } from "../DTO/email-query.dto";
|
||||||
import { EmailRecipientDto, SendEmailDto, UpdateDraftDto } from "../DTO/send-email.dto";
|
import { EmailAttachmentDto, EmailRecipientDto, SendEmailDto, UpdateDraftDto } from "../DTO/send-email.dto";
|
||||||
import { PriorityEnum } from "../enums/email-header.enum";
|
import { PriorityEnum } from "../enums/email-header.enum";
|
||||||
import { IEmailMap } from "../interfaces/email-map.interface";
|
import { IEmailMap } from "../interfaces/email-map.interface";
|
||||||
|
|
||||||
@@ -477,7 +476,7 @@ export class EmailService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//==============================================
|
//==============================================
|
||||||
async updateDraft(wildduckUserId: string, messageId: number, updateDraftDto: UpdateDraftDto) {
|
async updateDraft(wildduckUserId: string, messageId: number, updateDraftDto: UpdateDraftDto, generateTemplate: boolean = false) {
|
||||||
const draftsMailboxId = await this.mailboxResolverService.getDraftsMailboxId(wildduckUserId);
|
const draftsMailboxId = await this.mailboxResolverService.getDraftsMailboxId(wildduckUserId);
|
||||||
const existingDraft = await firstValueFrom(this.mailServerService.messages.getMessage(wildduckUserId, draftsMailboxId, messageId));
|
const existingDraft = await firstValueFrom(this.mailServerService.messages.getMessage(wildduckUserId, draftsMailboxId, messageId));
|
||||||
|
|
||||||
@@ -490,41 +489,41 @@ export class EmailService {
|
|||||||
cc: updateDraftDto.cc,
|
cc: updateDraftDto.cc,
|
||||||
bcc: updateDraftDto.bcc,
|
bcc: updateDraftDto.bcc,
|
||||||
replyTo: updateDraftDto.replyTo,
|
replyTo: updateDraftDto.replyTo,
|
||||||
headers: updateDraftDto.headers,
|
|
||||||
subject: updateDraftDto.subject,
|
subject: updateDraftDto.subject,
|
||||||
text: updateDraftDto.text,
|
text: updateDraftDto.text,
|
||||||
html: updateDraftDto.html,
|
html: updateDraftDto.html,
|
||||||
attachments: updateDraftDto.attachments,
|
attachments: updateDraftDto.attachments,
|
||||||
meta: updateDraftDto.meta,
|
|
||||||
sess: updateDraftDto.sess,
|
|
||||||
ip: updateDraftDto.ip,
|
|
||||||
isDraft: true,
|
isDraft: true,
|
||||||
uploadOnly: true,
|
uploadOnly: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
// const user = await this.userRepository.findOne({ wildduckUserId, deletedAt: null }, { populate: ["business"] });
|
if (generateTemplate) {
|
||||||
|
const user = await this.userRepository.findOne({ wildduckUserId, deletedAt: null }, { populate: ["business"] });
|
||||||
|
|
||||||
// if (user && user.business && (updateDraftDto.text || updateDraftDto.html)) {
|
if (!user || !user.business) throw new BadRequestException(EmailMessage.USER_NOT_FOUND);
|
||||||
// const processedTemplate = await this.templateProcessorService.processEmailContent(user.business.id, user.id, {
|
|
||||||
// text: updateDraftDto.text!,
|
|
||||||
// html: updateDraftDto.html!,
|
|
||||||
// subject: updateDraftDto.subject,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (processedTemplate.isHtml) {
|
if (updateDraftDto.text || updateDraftDto.html) {
|
||||||
// draftData.html = processedTemplate.content;
|
const processedTemplate = await this.templateProcessorService.processEmailContent(user.business.id, user.id, {
|
||||||
// draftData.text = "";
|
text: updateDraftDto.text!,
|
||||||
// } else {
|
html: updateDraftDto.html!,
|
||||||
// draftData.text = processedTemplate.content;
|
subject: updateDraftDto.subject,
|
||||||
// draftData.html = "";
|
});
|
||||||
// }
|
|
||||||
|
|
||||||
// const headers = this.generateHeadersForEmailType(user, {
|
if (processedTemplate.isHtml) {
|
||||||
// html: draftData.html,
|
draftData.html = processedTemplate.content;
|
||||||
// text: draftData.text,
|
draftData.text = "";
|
||||||
// });
|
} else {
|
||||||
// draftData.headers = [...(draftData.headers || []), ...headers];
|
draftData.text = processedTemplate.content;
|
||||||
// }
|
draftData.html = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = this.generateHeadersForEmailType(user, {
|
||||||
|
html: draftData.html,
|
||||||
|
text: draftData.text,
|
||||||
|
});
|
||||||
|
draftData.headers = [...(draftData.headers || []), ...headers];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const response = await firstValueFrom(this.mailServerService.submission.submitMessage(wildduckUserId, draftData as SendEmailDto));
|
const response = await firstValueFrom(this.mailServerService.submission.submitMessage(wildduckUserId, draftData as SendEmailDto));
|
||||||
|
|
||||||
@@ -540,38 +539,26 @@ export class EmailService {
|
|||||||
const draftsMailboxId = await this.mailboxResolverService.getDraftsMailboxId(wildduckUserId);
|
const draftsMailboxId = await this.mailboxResolverService.getDraftsMailboxId(wildduckUserId);
|
||||||
|
|
||||||
const message = await firstValueFrom(this.mailServerService.messages.getMessage(wildduckUserId, draftsMailboxId, messageId));
|
const message = await firstValueFrom(this.mailServerService.messages.getMessage(wildduckUserId, draftsMailboxId, messageId));
|
||||||
|
const updateMessage: UpdateDraftDto = {
|
||||||
const user = await this.userRepository.findOne({ wildduckUserId, deletedAt: null }, { populate: ["business"] });
|
from: message.from,
|
||||||
|
to: message.to,
|
||||||
if (!user) throw new BadRequestException(EmailMessage.USER_NOT_FOUND);
|
cc: message.cc,
|
||||||
|
bcc: message.bcc,
|
||||||
const processedTemplate = await this.templateProcessorService.processEmailContent(user.business.id, user.id, {
|
replyTo: message.inReplyTo ? { address: message.inReplyTo } : undefined,
|
||||||
text: message.text || "",
|
|
||||||
html: message.html?.[0] || "",
|
|
||||||
subject: message.subject,
|
subject: message.subject,
|
||||||
});
|
text: message.text,
|
||||||
|
|
||||||
if (processedTemplate.isHtml) {
|
|
||||||
message.html = [processedTemplate.content];
|
|
||||||
message.text = "";
|
|
||||||
} else {
|
|
||||||
message.text = processedTemplate.content;
|
|
||||||
message.html = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const headers = this.generateHeadersForEmailType(user, {
|
|
||||||
html: message.html?.[0] || "",
|
html: message.html?.[0] || "",
|
||||||
text: message.text || "",
|
attachments: message.attachments as unknown as EmailAttachmentDto[],
|
||||||
});
|
isDraft: true,
|
||||||
message.headers = { ...message.headers, ...headers } as unknown as MessageHeaders;
|
uploadOnly: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { messageId: updatedMessageId } = await this.updateDraft(wildduckUserId, messageId, updateMessage, true);
|
||||||
|
|
||||||
const result = await firstValueFrom(
|
const result = await firstValueFrom(
|
||||||
this.mailServerService.messages.submitDraft(wildduckUserId, draftsMailboxId, messageId, { deleteFiles: false }),
|
this.mailServerService.messages.submitDraft(wildduckUserId, draftsMailboxId, Number(updatedMessageId), { deleteFiles: false }),
|
||||||
);
|
);
|
||||||
|
|
||||||
await firstValueFrom(this.mailServerService.messages.deleteMessage(wildduckUserId, draftsMailboxId, messageId));
|
|
||||||
this.logger.log(`Draft message ${messageId} deleted from drafts folder after sending`);
|
|
||||||
|
|
||||||
await this.emailNotificationService.notifyEmailSentFromDraft({
|
await this.emailNotificationService.notifyEmailSentFromDraft({
|
||||||
wildduckUserId,
|
wildduckUserId,
|
||||||
userId,
|
userId,
|
||||||
|
|||||||
Reference in New Issue
Block a user