Added account update form and e-mail verification.
This commit is contained in:
79
src/email.js
Normal file
79
src/email.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import config from 'config';
|
||||
import { Resend } from 'resend';
|
||||
|
||||
import { emailTemplates } from './email-templates.js';
|
||||
import initLogger from './logger.js';
|
||||
|
||||
const logger = initLogger();
|
||||
|
||||
const resend = (() => {
|
||||
if (config.email.enabled) {
|
||||
try {
|
||||
return new Resend(config.email.apiKey);
|
||||
}
|
||||
catch (error) {
|
||||
logger.error(`Failed to initialize Resend: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
})();
|
||||
|
||||
export async function renderEmail(template, { to, subject, props }) {
|
||||
const { html, text } = await emailTemplates.render(`${template}.vue`, { props });
|
||||
|
||||
return {
|
||||
from: config.email.from,
|
||||
to,
|
||||
subject,
|
||||
html,
|
||||
text,
|
||||
};
|
||||
}
|
||||
|
||||
// always batches, even for a single item: Resend's batch endpoint accepts a batch of one,
|
||||
// and passing batchValidation: 'permissive' means one bad recipient among many doesn't
|
||||
// sink the rest of the batch (the default 'strict' mode fails the whole call instead)
|
||||
export async function sendEmails(items) {
|
||||
if (!config.email.enabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!resend) {
|
||||
logger.warn('E-mails are enabled, but Resend is not initialized');
|
||||
return null;
|
||||
}
|
||||
|
||||
const rendered = await Promise.all(items.map(async (item) => {
|
||||
try {
|
||||
return await renderEmail(item.template, item);
|
||||
}
|
||||
catch (error) {
|
||||
logger.error(`Failed to render '${item.template}' e-mail for '${item.to}': ${error.message} — ${JSON.stringify(item.props)}`);
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
|
||||
const sentItems = items.filter((item, index) => rendered[index]);
|
||||
const emails = rendered.filter(Boolean);
|
||||
|
||||
if (emails.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { data, error } = await resend.batch.send(emails, { batchValidation: 'permissive' });
|
||||
|
||||
if (error) {
|
||||
logger.error(`Failed to send ${emails.length} e-mail(s) (${error.statusCode} ${error.name}): ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
data.errors?.forEach(({ index, message }) => {
|
||||
const item = sentItems[index];
|
||||
logger.error(`Failed to send '${item.template}' e-mail to '${item.to}': ${message} — ${JSON.stringify(item.props)}`);
|
||||
});
|
||||
|
||||
logger.info(`Sent ${emails.length - (data.errors?.length || 0)}/${items.length} e-mail(s)`);
|
||||
|
||||
return data;
|
||||
}
|
||||
Reference in New Issue
Block a user