mjml EMail

This commit is contained in:
2026-03-16 18:00:32 -05:00
parent b9f9df74c0
commit 5a7ba66c27
9 changed files with 3248 additions and 24 deletions

View File

@@ -0,0 +1,112 @@
// src/services/email-service.js
const { SESv2Client, SendEmailCommand } = require('@aws-sdk/client-sesv2');
const nodemailer = require('nodemailer');
const mjml2html = require('mjml');
const sesClient = new SESv2Client({
region: process.env.AWS_REGION || 'us-east-2'
});
const transporter = nodemailer.createTransport({
SES: {
sesClient,
SendEmailCommand
}
});
function generateInvoiceEmailHtml(invoice, customText, melioLink) {
const formattedText = customText || '';
const buttonMjml = melioLink
? `<mj-button background-color="#2563eb" color="white" border-radius="6px" href="${melioLink}" font-weight="600" font-size="16px" padding-top="25px">
Pay Now (Free ACH)
</mj-button>`
: '';
const template = `
<mjml>
<mj-head>
<mj-attributes>
<mj-all font-family="ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif" />
</mj-attributes>
<mj-style inline="inline">
.email-body p {
margin: 0 0 14px 0 !important;
}
.email-body p:last-child {
margin-bottom: 0 !important;
}
</mj-style>
</mj-head>
<mj-body background-color="#f4f4f5">
<mj-section padding="0">
<mj-column>
<mj-spacer height="20px" />
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding="30px" border-radius="8px 8px 0 0">
<mj-column>
<mj-text font-size="22px" font-weight="700" color="#1e3a8a" padding="0">
Bay Area Affiliates, Inc.
</mj-text>
<mj-text font-size="15px" color="#64748b" padding="5px 0 0 0">
Invoice #${invoice.invoice_number || invoice.id}
</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding="0 30px 30px 30px">
<mj-column>
<mj-text css-class="email-body" font-size="15px" color="#334155" line-height="1.5" padding="0">
${formattedText}
</mj-text>
${buttonMjml}
<mj-divider border-color="#e2e8f0" border-width="1px" padding-top="30px" padding-bottom="20px" />
<mj-text font-size="14px" color="#64748b" line-height="1.5" padding="0">
<strong>Prefer to pay by check?</strong><br/>
Please make checks payable to Bay Area Affiliates, Inc. and mail to:<br/>
1001 Blucher Street<br/>
Corpus Christi, Texas 78401
</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
`;
// validationLevel: 'strict' fängt falsche Attribute ab, bevor sie an den Kunden gehen
const result = mjml2html(template, { validationLevel: 'strict' });
if (result.errors && result.errors.length > 0) {
console.error('MJML Parse Errors:', result.errors);
}
return result.html;
}
async function sendInvoiceEmail(invoice, recipientEmail, customText, melioLink, pdfBuffer) {
const htmlContent = generateInvoiceEmailHtml(invoice, customText, melioLink);
const mailOptions = {
from: '"Bay Area Affiliates Inc. Accounting" <accounting@bayarea-cc.com>',
to: recipientEmail,
subject: `Invoice #${invoice.invoice_number || invoice.id} from Bay Area Affiliates, Inc.`,
html: htmlContent,
attachments: [
{
filename: `Invoice_${invoice.invoice_number || invoice.id}_BayAreaAffiliates.pdf`,
content: pdfBuffer,
contentType: 'application/pdf'
}
]
};
return await transporter.sendMail(mailOptions);
}
module.exports = { sendInvoiceEmail };

View File

@@ -33,8 +33,9 @@ async function generatePdfFromHtml(html, options = {}) {
}
const page = await browser.newPage();
await page.setContent(html, { waitUntil: 'networkidle0', timeout: 60000 });
//await page.setContent(html, { waitUntil: 'networkidle0', timeout: 60000 });
await page.setContent(html, { waitUntil: 'load', timeout: 5000 });
const pdf = await page.pdf({
format,
printBackground,