@contentgrowth/content-emailing 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/backend/EmailService.js +40 -24
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { marked } from 'marked';
|
|
6
6
|
import Mustache from 'mustache';
|
|
7
|
+
import { wrapInEmailTemplate } from '../common/htmlWrapper.js';
|
|
7
8
|
|
|
8
9
|
export class EmailService {
|
|
9
10
|
/**
|
|
@@ -23,6 +24,13 @@ export class EmailService {
|
|
|
23
24
|
fromAddress: 'noreply@example.com',
|
|
24
25
|
provider: 'mailchannels'
|
|
25
26
|
},
|
|
27
|
+
// Branding configuration for email templates
|
|
28
|
+
branding: {
|
|
29
|
+
brandName: config.branding?.brandName || 'Your App',
|
|
30
|
+
portalUrl: config.branding?.portalUrl || 'https://app.example.com',
|
|
31
|
+
primaryColor: config.branding?.primaryColor || '#667eea',
|
|
32
|
+
...config.branding
|
|
33
|
+
},
|
|
26
34
|
...config
|
|
27
35
|
};
|
|
28
36
|
this.cache = cacheProvider;
|
|
@@ -204,22 +212,17 @@ export class EmailService {
|
|
|
204
212
|
return { subject, html, plainText };
|
|
205
213
|
}
|
|
206
214
|
|
|
207
|
-
wrapInBaseTemplate(content, subject, data) {
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
<p>Sent via X0 Start</p>
|
|
219
|
-
</div>
|
|
220
|
-
</div>
|
|
221
|
-
</body>
|
|
222
|
-
</html>`;
|
|
215
|
+
wrapInBaseTemplate(content, subject, data = {}) {
|
|
216
|
+
// Merge branding config with template data
|
|
217
|
+
const templateData = {
|
|
218
|
+
...data,
|
|
219
|
+
brandName: data.brandName || this.config.branding.brandName,
|
|
220
|
+
portalUrl: data.portalUrl || this.config.branding.portalUrl,
|
|
221
|
+
unsubscribeUrl: data.unsubscribeUrl || '{{unsubscribe_url}}'
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// Use the full branded HTML wrapper from common
|
|
225
|
+
return wrapInEmailTemplate(content, subject, templateData);
|
|
223
226
|
}
|
|
224
227
|
|
|
225
228
|
// --- Delivery ---
|
|
@@ -237,7 +240,11 @@ export class EmailService {
|
|
|
237
240
|
* @param {Object} [params.metadata] - Additional metadata
|
|
238
241
|
* @returns {Promise<Object>} Delivery result
|
|
239
242
|
*/
|
|
240
|
-
async sendEmail({ to, subject, html, text, provider, profile = 'system', tenantId = null, metadata = {} }) {
|
|
243
|
+
async sendEmail({ to, subject, html, htmlBody, text, textBody, provider, profile = 'system', tenantId = null, metadata = {} }) {
|
|
244
|
+
// Backward compatibility: accept htmlBody/textBody as aliases
|
|
245
|
+
const htmlContent = html || htmlBody;
|
|
246
|
+
const textContent = text || textBody;
|
|
247
|
+
|
|
241
248
|
try {
|
|
242
249
|
const settings = await this.loadSettings(profile, tenantId);
|
|
243
250
|
const useProvider = provider || settings.provider || 'mailchannels';
|
|
@@ -246,16 +253,16 @@ export class EmailService {
|
|
|
246
253
|
|
|
247
254
|
switch (useProvider) {
|
|
248
255
|
case 'mailchannels':
|
|
249
|
-
result = await this.sendViaMailChannels(to, subject,
|
|
256
|
+
result = await this.sendViaMailChannels(to, subject, htmlContent, textContent, settings, metadata);
|
|
250
257
|
break;
|
|
251
258
|
case 'sendgrid':
|
|
252
|
-
result = await this.sendViaSendGrid(to, subject,
|
|
259
|
+
result = await this.sendViaSendGrid(to, subject, htmlContent, textContent, settings, metadata);
|
|
253
260
|
break;
|
|
254
261
|
case 'resend':
|
|
255
|
-
result = await this.sendViaResend(to, subject,
|
|
262
|
+
result = await this.sendViaResend(to, subject, htmlContent, textContent, settings, metadata);
|
|
256
263
|
break;
|
|
257
264
|
case 'sendpulse':
|
|
258
|
-
result = await this.sendViaSendPulse(to, subject,
|
|
265
|
+
result = await this.sendViaSendPulse(to, subject, htmlContent, textContent, settings, metadata);
|
|
259
266
|
break;
|
|
260
267
|
default:
|
|
261
268
|
console.error(`[EmailService] Unknown provider: ${useProvider}`);
|
|
@@ -438,7 +445,16 @@ export class EmailService {
|
|
|
438
445
|
}
|
|
439
446
|
|
|
440
447
|
const { access_token } = tokenData;
|
|
441
|
-
|
|
448
|
+
|
|
449
|
+
// Safe base64 encoding
|
|
450
|
+
const toBase64 = (str) => {
|
|
451
|
+
if (!str) return '';
|
|
452
|
+
return Buffer.from(String(str)).toString('base64');
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
// Ensure html/text are strings
|
|
456
|
+
const htmlSafe = html || '';
|
|
457
|
+
const textSafe = text || (htmlSafe ? htmlSafe.replace(/<[^>]*>/g, '') : '');
|
|
442
458
|
|
|
443
459
|
// Send the email
|
|
444
460
|
const response = await fetch('https://api.sendpulse.com/smtp/emails', {
|
|
@@ -449,8 +465,8 @@ export class EmailService {
|
|
|
449
465
|
},
|
|
450
466
|
body: JSON.stringify({
|
|
451
467
|
email: {
|
|
452
|
-
html: toBase64(
|
|
453
|
-
text: toBase64(
|
|
468
|
+
html: toBase64(htmlSafe),
|
|
469
|
+
text: toBase64(textSafe),
|
|
454
470
|
subject,
|
|
455
471
|
from: { name: settings.fromName, email: settings.fromAddress },
|
|
456
472
|
to: [{ name: metadata.recipientName || '', email: to }],
|