Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/modules/emails/services/MailjetEmailService.ts
T

133 lines
4.1 KiB
TypeScript

import { MailProviderError, type MailAttachment, type MailProvider } from "@hivegrid/mail";
import {
buildTransactionalMailJob,
enqueueJob,
queueNames,
resolveRedisConnectionOptions,
resolveRedisConnectionOptionsFromProcessEnv,
type RedisConnectionEnv,
type TypedQueue,
} from "@hivegrid/queue";
import { requestScopedT as i18nT } from "~/locale/request-scoped-t";
export type SendEmailMailjetDependencies = {
env?: RedisConnectionEnv;
queue?: TypedQueue<typeof queueNames.email>;
};
export async function sendEmailMailjet(
{
data,
}: {
data: {
to: string;
subject?: string;
body?: string;
text?: string;
alias?: string;
source?: string;
data?: {
[key: string]: any;
};
tenantId?: string | null;
priorityOverride?: "critical" | "high" | "normal" | "low";
attachments?: readonly MailAttachment[];
};
},
dependencies: SendEmailMailjetDependencies = {}
) {
const mailProvider = dependencies.queue
? createTransactionalQueueProvider(dependencies.queue, data.alias, data.data, data.source)
: createTransactionalQueueProviderFromEnv(dependencies.env, data.alias, data.data, data.source);
return await mailProvider.send({
to: [data.to],
subject: data.subject,
html: data.body,
text: data.text,
tenantId: data.tenantId,
priorityOverride: data.priorityOverride,
...(data.attachments && data.attachments.length > 0 ? { attachments: data.attachments } : {}),
});
}
function createTransactionalQueueProviderFromEnv(
env?: RedisConnectionEnv,
alias?: string,
templateData?: Record<string, unknown>,
source?: string
): MailProvider {
const connection = env ? resolveRedisConnectionOptions({ env }) : resolveRedisConnectionOptionsFromProcessEnv();
if (!connection) {
return {
id: "queue",
async send() {
const warning = {
code: "missing_redis_connection",
message: i18nT("mail.queue.errors.missingRedisConnection"),
requiredEnv: ["BULLMQ_REDIS_URL", "REDIS_URL"],
};
throw new MailProviderError(warning.message, { provider: "queue", responseBody: warning });
},
};
}
return {
id: "queue",
async send(input) {
const queueRuntimeModule = "@hivegrid/queue/runtime";
const { createQueue } = (await import(/* @vite-ignore */ queueRuntimeModule)) as typeof import("@hivegrid/queue/runtime");
const queue = createQueue(queueNames.email, { connection });
try {
return await createTransactionalQueueProvider(queue, alias, templateData, source).send(input);
} finally {
await queue.close();
}
},
};
}
function createTransactionalQueueProvider(
queue: TypedQueue<typeof queueNames.email>,
alias?: string,
templateData?: Record<string, unknown>,
source?: string
): MailProvider {
return {
id: "queue",
async send(input) {
const descriptor = buildTransactionalMailJob({
to: input.to.map((recipient) => (typeof recipient === "string" ? recipient : recipient.email)),
subject: input.subject,
text: input.text,
html: input.html,
templateData,
// Forward attachments (e.g. AK-P16b booking .ics) — the payload already
// supports them; only this provider hop was dropping the field.
...(input.attachments && input.attachments.length > 0 ? { attachments: input.attachments } : {}),
...(input.tenantId !== undefined && input.tenantId !== null ? { tenantId: input.tenantId } : {}),
metadata: alias || source ? { ...(alias ? { alias } : {}), ...(source ? { source } : {}) } : undefined,
});
const job = await enqueueJob(queue, descriptor, {
...(input.tenantId !== undefined ? { tenantId: input.tenantId } : {}),
...(input.priorityOverride !== undefined ? { priorityOverride: input.priorityOverride } : {}),
});
return {
provider: "queue",
status: "queued",
messageId: job.id,
warnings: {
queueName: descriptor.queueName,
jobName: descriptor.jobName,
},
};
},
};
}
export default {
send: sendEmailMailjet,
};