@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentgrowth/content-emailing",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Unified email delivery and template management system",
6
6
  "main": "src/index.js",
@@ -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
- // Simple default wrapper
209
- // In a real usage, this might load a 'base' template from DB
210
- return `
211
- <!DOCTYPE html>
212
- <html>
213
- <head><title>${subject}</title></head>
214
- <body style="font-family: sans-serif; line-height: 1.6; color: #333;">
215
- <div style="max-width: 600px; margin: 0 auto; padding: 20px;">
216
- ${content}
217
- <div style="margin-top: 20px; font-size: 12px; color: #999;">
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, html, text, settings, metadata);
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, html, text, settings, metadata);
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, html, text, settings, metadata);
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, html, text, settings, metadata);
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
- const toBase64 = (str) => Buffer.from(str).toString('base64');
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(html),
453
- text: toBase64(text || html.replace(/<[^>]*>/g, '')),
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 }],