organify-email 1.0.0 → 1.1.2

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.
@@ -1,13 +1,30 @@
1
1
  import { type EmailTemplateName } from './templates';
2
2
  export interface BrevoEmailConfig {
3
3
  apiKey: string;
4
+ mailerSendApiKey?: string;
4
5
  senderName?: string;
5
6
  senderEmail?: string;
7
+ mailerSendSenderName?: string;
8
+ mailerSendSenderEmail?: string;
6
9
  /** Daily send limit (default: 300) */
7
10
  dailyLimit?: number;
8
11
  /** Enable sending (set false for dev/test to just log) */
9
12
  enabled?: boolean;
10
13
  }
14
+ /**
15
+ * Hardcoded Brevo provider configuration for package-level local/demo usage.
16
+ * Replace apiKey with a valid Brevo key before using in real sends.
17
+ */
18
+ export declare const HARDCODED_BREVO_PROVIDER: Readonly<{
19
+ apiKey: string;
20
+ senderName: string;
21
+ senderEmail: string;
22
+ dailyLimit: number;
23
+ enabled: boolean;
24
+ }>;
25
+ export type OrganifyEmailService = 'users' | 'workspaces' | 'notifications' | 'reports';
26
+ export declare const ORGANIFY_EMAIL_DAILY_LIMITS: Readonly<Record<OrganifyEmailService, number>>;
27
+ export declare function createOrganifyEmailClient(service: OrganifyEmailService): BrevoEmailClient;
11
28
  export interface EmailRecipient {
12
29
  email: string;
13
30
  name?: string;
@@ -53,17 +70,23 @@ export interface DailyStats {
53
70
  };
54
71
  }
55
72
  export declare class BrevoEmailClient {
56
- private readonly apiKey;
57
- private readonly senderName;
58
- private readonly senderEmail;
73
+ private readonly brevoApiKey;
74
+ private readonly mailerSendApiKey;
75
+ private readonly brevoSenderName;
76
+ private readonly brevoSenderEmail;
77
+ private readonly mailerSendSenderName;
78
+ private readonly mailerSendSenderEmail;
59
79
  private readonly dailyLimit;
60
80
  private readonly enabled;
61
81
  private dailySent;
62
82
  private dailyDate;
63
83
  private dailyByPriority;
64
84
  private static readonly API_URL;
85
+ private static readonly MAILERSEND_API_URL;
65
86
  constructor(config: BrevoEmailConfig);
66
87
  send(options: SendEmailOptions): Promise<SendResult>;
88
+ private sendViaBrevo;
89
+ private sendViaMailerSend;
67
90
  sendBatch(recipients: EmailRecipient[], options: Omit<SendEmailOptions, 'to'>): Promise<SendResult[]>;
68
91
  getStats(): DailyStats;
69
92
  private checkDayReset;
@@ -1 +1 @@
1
- {"version":3,"file":"brevo-client.d.ts","sourceRoot":"","sources":["../src/brevo-client.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIrE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACnD,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,KAAK,CAAC;IACzC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,oBAAoB;IACpB,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC;IACtB,qBAAqB;IACrB,GAAG,CAAC,EAAE,cAAc,EAAE,CAAC;IACvB,uBAAuB;IACvB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/D;AAID,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAGlC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,eAAe,CAAsC;IAE7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAyC;gBAE5D,MAAM,EAAE,gBAAgB;IAU9B,IAAI,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IA8FpD,SAAS,CACb,UAAU,EAAE,cAAc,EAAE,EAC5B,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,GACpC,OAAO,CAAC,UAAU,EAAE,CAAC;IAkBxB,QAAQ,IAAI,UAAU;IAatB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,gBAAgB;CAIzB"}
1
+ {"version":3,"file":"brevo-client.d.ts","sourceRoot":"","sources":["../src/brevo-client.ts"],"names":[],"mappings":"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"}
@@ -15,13 +15,75 @@
15
15
  // await client.send({ to, subject, template: 'report-ready', params });
16
16
  // ─────────────────────────────────────────────
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.BrevoEmailClient = void 0;
18
+ exports.BrevoEmailClient = exports.ORGANIFY_EMAIL_DAILY_LIMITS = exports.HARDCODED_BREVO_PROVIDER = void 0;
19
+ exports.createOrganifyEmailClient = createOrganifyEmailClient;
19
20
  const templates_1 = require("./templates");
21
+ function getEnvVar(name) {
22
+ const value = globalThis?.process?.env?.[name];
23
+ if (typeof value !== 'string')
24
+ return undefined;
25
+ const trimmed = value.trim();
26
+ return trimmed.length > 0 ? trimmed : undefined;
27
+ }
28
+ function parseBooleanEnv(name) {
29
+ const value = getEnvVar(name)?.toLowerCase();
30
+ if (!value)
31
+ return undefined;
32
+ if (value === 'true' || value === '1' || value === 'yes')
33
+ return true;
34
+ if (value === 'false' || value === '0' || value === 'no')
35
+ return false;
36
+ return undefined;
37
+ }
38
+ /**
39
+ * Hardcoded Brevo provider configuration for package-level local/demo usage.
40
+ * Replace apiKey with a valid Brevo key before using in real sends.
41
+ */
42
+ exports.HARDCODED_BREVO_PROVIDER = {
43
+ // Legacy fallback only. Prefer env-based configuration in createOrganifyEmailClient.
44
+ apiKey: '',
45
+ senderName: 'Organify',
46
+ senderEmail: 'noreply@organify.studio',
47
+ dailyLimit: 300,
48
+ enabled: false,
49
+ };
50
+ exports.ORGANIFY_EMAIL_DAILY_LIMITS = {
51
+ users: 50,
52
+ workspaces: 50,
53
+ notifications: 150,
54
+ reports: 300,
55
+ };
56
+ function createOrganifyEmailClient(service) {
57
+ const apiKey = getEnvVar('BREVO_API_KEY') || exports.HARDCODED_BREVO_PROVIDER.apiKey;
58
+ const mailerSendApiKey = getEnvVar('MAILERSEND_API_KEY');
59
+ const senderName = getEnvVar('BREVO_SENDER_NAME') || exports.HARDCODED_BREVO_PROVIDER.senderName;
60
+ const senderEmail = getEnvVar('BREVO_SENDER_EMAIL') || exports.HARDCODED_BREVO_PROVIDER.senderEmail;
61
+ const mailerSendSenderName = getEnvVar('MAILERSEND_SENDER_NAME') || senderName;
62
+ const mailerSendSenderEmail = getEnvVar('MAILERSEND_SENDER_EMAIL') || senderEmail;
63
+ const forcedEnabled = parseBooleanEnv('BREVO_ENABLED');
64
+ const enabled = forcedEnabled ?? Boolean(apiKey || mailerSendApiKey);
65
+ if (!apiKey && !mailerSendApiKey) {
66
+ console.warn(`[Email] BREVO_API_KEY and MAILERSEND_API_KEY are missing for service "${service}". Running in DRY RUN mode (emails not sent).`);
67
+ }
68
+ return new BrevoEmailClient({
69
+ apiKey,
70
+ mailerSendApiKey,
71
+ senderName,
72
+ senderEmail,
73
+ mailerSendSenderName,
74
+ mailerSendSenderEmail,
75
+ dailyLimit: exports.ORGANIFY_EMAIL_DAILY_LIMITS[service],
76
+ enabled,
77
+ });
78
+ }
20
79
  // ─── Client ─────────────────────────────────
21
80
  class BrevoEmailClient {
22
- apiKey;
23
- senderName;
24
- senderEmail;
81
+ brevoApiKey;
82
+ mailerSendApiKey;
83
+ brevoSenderName;
84
+ brevoSenderEmail;
85
+ mailerSendSenderName;
86
+ mailerSendSenderEmail;
25
87
  dailyLimit;
26
88
  enabled;
27
89
  // Daily counter (in-memory, resets on restart)
@@ -29,10 +91,14 @@ class BrevoEmailClient {
29
91
  dailyDate = '';
30
92
  dailyByPriority = { critical: 0, normal: 0, low: 0 };
31
93
  static API_URL = 'https://api.brevo.com/v3/smtp/email';
94
+ static MAILERSEND_API_URL = 'https://api.mailersend.com/v1/email';
32
95
  constructor(config) {
33
- this.apiKey = config.apiKey;
34
- this.senderName = config.senderName || 'Organify Team';
35
- this.senderEmail = config.senderEmail || 'noreply@organify.studio';
96
+ this.brevoApiKey = config.apiKey;
97
+ this.mailerSendApiKey = config.mailerSendApiKey || '';
98
+ this.brevoSenderName = config.senderName || 'Organify Team';
99
+ this.brevoSenderEmail = config.senderEmail || 'noreply@organify.studio';
100
+ this.mailerSendSenderName = config.mailerSendSenderName || this.brevoSenderName;
101
+ this.mailerSendSenderEmail = config.mailerSendSenderEmail || this.brevoSenderEmail;
36
102
  this.dailyLimit = config.dailyLimit || 300;
37
103
  this.enabled = config.enabled !== false;
38
104
  }
@@ -78,15 +144,55 @@ class BrevoEmailClient {
78
144
  this.incrementCounter(priority);
79
145
  return { success: true, messageId: `dry-run-${Date.now()}`, skipped: false };
80
146
  }
81
- // Build Brevo payload
147
+ // Build Brevo/MailerSend payload basis
82
148
  const recipients = Array.isArray(options.to) ? options.to : [options.to];
149
+ const recipientPayload = recipients.map((r) => ({ email: r.email, name: r.name }));
150
+ if (!this.brevoApiKey && !this.mailerSendApiKey) {
151
+ return { success: false, error: 'No email provider key configured (BREVO_API_KEY or MAILERSEND_API_KEY)' };
152
+ }
153
+ if (this.brevoApiKey) {
154
+ const brevoResult = await this.sendViaBrevo({
155
+ recipients: recipientPayload,
156
+ subject: options.subject,
157
+ htmlContent,
158
+ textContent: options.textContent,
159
+ params: options.params,
160
+ tags: options.tags,
161
+ cc: options.cc,
162
+ bcc: options.bcc,
163
+ replyTo: options.replyTo,
164
+ });
165
+ if (brevoResult.success) {
166
+ this.incrementCounter(priority);
167
+ return brevoResult;
168
+ }
169
+ console.warn(`[Email] Brevo send failed; trying MailerSend fallback: ${brevoResult.error || 'unknown error'}`);
170
+ }
171
+ if (this.mailerSendApiKey) {
172
+ const mailerSendResult = await this.sendViaMailerSend({
173
+ recipients: recipientPayload,
174
+ subject: options.subject,
175
+ htmlContent,
176
+ textContent: options.textContent,
177
+ cc: options.cc,
178
+ bcc: options.bcc,
179
+ replyTo: options.replyTo,
180
+ });
181
+ if (mailerSendResult.success) {
182
+ this.incrementCounter(priority);
183
+ }
184
+ return mailerSendResult;
185
+ }
186
+ return { success: false, error: 'Brevo failed and MAILERSEND_API_KEY is not configured for fallback' };
187
+ }
188
+ async sendViaBrevo(options) {
83
189
  const payload = {
84
- sender: { name: this.senderName, email: this.senderEmail },
85
- to: recipients.map((r) => ({ email: r.email, name: r.name })),
190
+ sender: { name: this.brevoSenderName, email: this.brevoSenderEmail },
191
+ to: options.recipients,
86
192
  subject: options.subject,
87
193
  };
88
- if (htmlContent)
89
- payload.htmlContent = htmlContent;
194
+ if (options.htmlContent)
195
+ payload.htmlContent = options.htmlContent;
90
196
  else if (options.textContent)
91
197
  payload.textContent = options.textContent;
92
198
  if (options.params)
@@ -103,8 +209,8 @@ class BrevoEmailClient {
103
209
  const response = await fetch(BrevoEmailClient.API_URL, {
104
210
  method: 'POST',
105
211
  headers: {
106
- 'accept': 'application/json',
107
- 'api-key': this.apiKey,
212
+ accept: 'application/json',
213
+ 'api-key': this.brevoApiKey,
108
214
  'content-type': 'application/json',
109
215
  },
110
216
  body: JSON.stringify(payload),
@@ -112,15 +218,70 @@ class BrevoEmailClient {
112
218
  if (!response.ok) {
113
219
  const body = await response.text();
114
220
  console.error(`[BrevoEmail] API error ${response.status}: ${body}`);
221
+ if (response.status === 401) {
222
+ console.error('[BrevoEmail] Check BREVO_API_KEY in env and ensure it is enabled for Transactional API/SMTP.');
223
+ }
115
224
  return { success: false, error: `Brevo API error: ${response.status} — ${body}` };
116
225
  }
117
226
  const data = await response.json();
118
- this.incrementCounter(priority);
119
227
  return { success: true, messageId: data.messageId };
120
228
  }
121
229
  catch (err) {
122
- console.error(`[BrevoEmail] Network error: ${err.message}`);
123
- return { success: false, error: `Network error: ${err.message}` };
230
+ const message = err instanceof Error ? err.message : String(err);
231
+ console.error(`[BrevoEmail] Network error: ${message}`);
232
+ return { success: false, error: `Brevo network error: ${message}` };
233
+ }
234
+ }
235
+ async sendViaMailerSend(options) {
236
+ const payload = {
237
+ from: { email: this.mailerSendSenderEmail, name: this.mailerSendSenderName },
238
+ to: options.recipients,
239
+ subject: options.subject,
240
+ };
241
+ if (options.htmlContent)
242
+ payload.html = options.htmlContent;
243
+ if (options.textContent)
244
+ payload.text = options.textContent;
245
+ if (!options.textContent && options.htmlContent) {
246
+ payload.text = 'Mensagem enviada pelo Organify.';
247
+ }
248
+ if (options.cc)
249
+ payload.cc = options.cc;
250
+ if (options.bcc)
251
+ payload.bcc = options.bcc;
252
+ if (options.replyTo) {
253
+ payload.reply_to = {
254
+ email: options.replyTo.email,
255
+ name: options.replyTo.name,
256
+ };
257
+ }
258
+ else {
259
+ payload.reply_to = {
260
+ email: this.mailerSendSenderEmail,
261
+ name: this.mailerSendSenderName,
262
+ };
263
+ }
264
+ try {
265
+ const response = await fetch(BrevoEmailClient.MAILERSEND_API_URL, {
266
+ method: 'POST',
267
+ headers: {
268
+ Authorization: `Bearer ${this.mailerSendApiKey}`,
269
+ 'Content-Type': 'application/json',
270
+ },
271
+ body: JSON.stringify(payload),
272
+ });
273
+ if (!response.ok) {
274
+ const body = await response.text();
275
+ console.error(`[MailerSendEmail] API error ${response.status}: ${body}`);
276
+ return { success: false, error: `MailerSend API error: ${response.status} — ${body}` };
277
+ }
278
+ const messageId = response.headers.get('x-message-id') || undefined;
279
+ return { success: true, messageId };
280
+ }
281
+ catch (err) {
282
+ const message = err instanceof Error ? err.message : String(err);
283
+ console.error(`[MailerSendEmail] Network error: ${message}`);
284
+ return { success: false, error: `MailerSend network error: ${message}` };
124
285
  }
125
286
  }
126
287
  // ─── Batch Send (same template, multiple recipients) ──
@@ -1 +1 @@
1
- {"version":3,"file":"brevo-client.js","sourceRoot":"","sources":["../src/brevo-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"brevo-client.js","sourceRoot":"","sources":["../src/brevo-client.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { BrevoEmailClient, type BrevoEmailConfig, type EmailRecipient, type SendEmailOptions, type SendResult, type DailyStats, } from './brevo-client';
1
+ export { BrevoEmailClient, HARDCODED_BREVO_PROVIDER, ORGANIFY_EMAIL_DAILY_LIMITS, createOrganifyEmailClient, type OrganifyEmailService, type BrevoEmailConfig, type EmailRecipient, type SendEmailOptions, type SendResult, type DailyStats, } from './brevo-client';
2
2
  export { emailTemplates, type EmailTemplateName, } from './templates';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,cAAc,EACd,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,2BAA2B,EAC3B,yBAAyB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,cAAc,EACd,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -3,9 +3,12 @@
3
3
  // organify-email — Public API
4
4
  // ─────────────────────────────────────────────
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.emailTemplates = exports.BrevoEmailClient = void 0;
6
+ exports.emailTemplates = exports.createOrganifyEmailClient = exports.ORGANIFY_EMAIL_DAILY_LIMITS = exports.HARDCODED_BREVO_PROVIDER = exports.BrevoEmailClient = void 0;
7
7
  var brevo_client_1 = require("./brevo-client");
8
8
  Object.defineProperty(exports, "BrevoEmailClient", { enumerable: true, get: function () { return brevo_client_1.BrevoEmailClient; } });
9
+ Object.defineProperty(exports, "HARDCODED_BREVO_PROVIDER", { enumerable: true, get: function () { return brevo_client_1.HARDCODED_BREVO_PROVIDER; } });
10
+ Object.defineProperty(exports, "ORGANIFY_EMAIL_DAILY_LIMITS", { enumerable: true, get: function () { return brevo_client_1.ORGANIFY_EMAIL_DAILY_LIMITS; } });
11
+ Object.defineProperty(exports, "createOrganifyEmailClient", { enumerable: true, get: function () { return brevo_client_1.createOrganifyEmailClient; } });
9
12
  var templates_1 = require("./templates");
10
13
  Object.defineProperty(exports, "emailTemplates", { enumerable: true, get: function () { return templates_1.emailTemplates; } });
11
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,gDAAgD;AAChD,8BAA8B;AAC9B,gDAAgD;;;AAEhD,+CAOwB;AANtB,gHAAA,gBAAgB,OAAA;AAQlB,yCAGqB;AAFnB,2GAAA,cAAc,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,gDAAgD;AAChD,8BAA8B;AAC9B,gDAAgD;;;AAEhD,+CAWwB;AAVtB,gHAAA,gBAAgB,OAAA;AAChB,wHAAA,wBAAwB,OAAA;AACxB,2HAAA,2BAA2B,OAAA;AAC3B,yHAAA,yBAAyB,OAAA;AAS3B,yCAGqB;AAFnB,2GAAA,cAAc,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "organify-email",
3
- "version": "1.0.0",
3
+ "version": "1.1.2",
4
4
  "description": "Shared email service for Organify — Brevo transactional API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -20,14 +20,88 @@ import { emailTemplates, type EmailTemplateName } from './templates';
20
20
 
21
21
  export interface BrevoEmailConfig {
22
22
  apiKey: string;
23
+ mailerSendApiKey?: string;
23
24
  senderName?: string;
24
25
  senderEmail?: string;
26
+ mailerSendSenderName?: string;
27
+ mailerSendSenderEmail?: string;
25
28
  /** Daily send limit (default: 300) */
26
29
  dailyLimit?: number;
27
30
  /** Enable sending (set false for dev/test to just log) */
28
31
  enabled?: boolean;
29
32
  }
30
33
 
34
+ function getEnvVar(name: string): string | undefined {
35
+ const value = (globalThis as any)?.process?.env?.[name];
36
+ if (typeof value !== 'string') return undefined;
37
+ const trimmed = value.trim();
38
+ return trimmed.length > 0 ? trimmed : undefined;
39
+ }
40
+
41
+ function parseBooleanEnv(name: string): boolean | undefined {
42
+ const value = getEnvVar(name)?.toLowerCase();
43
+ if (!value) return undefined;
44
+ if (value === 'true' || value === '1' || value === 'yes') return true;
45
+ if (value === 'false' || value === '0' || value === 'no') return false;
46
+ return undefined;
47
+ }
48
+
49
+ /**
50
+ * Hardcoded Brevo provider configuration for package-level local/demo usage.
51
+ * Replace apiKey with a valid Brevo key before using in real sends.
52
+ */
53
+ export const HARDCODED_BREVO_PROVIDER: Readonly<{
54
+ apiKey: string;
55
+ senderName: string;
56
+ senderEmail: string;
57
+ dailyLimit: number;
58
+ enabled: boolean;
59
+ }> = {
60
+ // Legacy fallback only. Prefer env-based configuration in createOrganifyEmailClient.
61
+ apiKey: '',
62
+ senderName: 'Organify',
63
+ senderEmail: 'noreply@organify.studio',
64
+ dailyLimit: 300,
65
+ enabled: false,
66
+ };
67
+
68
+ export type OrganifyEmailService = 'users' | 'workspaces' | 'notifications' | 'reports';
69
+
70
+ export const ORGANIFY_EMAIL_DAILY_LIMITS: Readonly<Record<OrganifyEmailService, number>> = {
71
+ users: 50,
72
+ workspaces: 50,
73
+ notifications: 150,
74
+ reports: 300,
75
+ };
76
+
77
+ export function createOrganifyEmailClient(service: OrganifyEmailService): BrevoEmailClient {
78
+ const apiKey = getEnvVar('BREVO_API_KEY') || HARDCODED_BREVO_PROVIDER.apiKey;
79
+ const mailerSendApiKey = getEnvVar('MAILERSEND_API_KEY');
80
+ const senderName = getEnvVar('BREVO_SENDER_NAME') || HARDCODED_BREVO_PROVIDER.senderName;
81
+ const senderEmail = getEnvVar('BREVO_SENDER_EMAIL') || HARDCODED_BREVO_PROVIDER.senderEmail;
82
+ const mailerSendSenderName = getEnvVar('MAILERSEND_SENDER_NAME') || senderName;
83
+ const mailerSendSenderEmail = getEnvVar('MAILERSEND_SENDER_EMAIL') || senderEmail;
84
+ const forcedEnabled = parseBooleanEnv('BREVO_ENABLED');
85
+ const enabled = forcedEnabled ?? Boolean(apiKey || mailerSendApiKey);
86
+
87
+ if (!apiKey && !mailerSendApiKey) {
88
+ console.warn(
89
+ `[Email] BREVO_API_KEY and MAILERSEND_API_KEY are missing for service "${service}". Running in DRY RUN mode (emails not sent).`,
90
+ );
91
+ }
92
+
93
+ return new BrevoEmailClient({
94
+ apiKey,
95
+ mailerSendApiKey,
96
+ senderName,
97
+ senderEmail,
98
+ mailerSendSenderName,
99
+ mailerSendSenderEmail,
100
+ dailyLimit: ORGANIFY_EMAIL_DAILY_LIMITS[service],
101
+ enabled,
102
+ });
103
+ }
104
+
31
105
  export interface EmailRecipient {
32
106
  email: string;
33
107
  name?: string;
@@ -75,9 +149,12 @@ export interface DailyStats {
75
149
  // ─── Client ─────────────────────────────────
76
150
 
77
151
  export class BrevoEmailClient {
78
- private readonly apiKey: string;
79
- private readonly senderName: string;
80
- private readonly senderEmail: string;
152
+ private readonly brevoApiKey: string;
153
+ private readonly mailerSendApiKey: string;
154
+ private readonly brevoSenderName: string;
155
+ private readonly brevoSenderEmail: string;
156
+ private readonly mailerSendSenderName: string;
157
+ private readonly mailerSendSenderEmail: string;
81
158
  private readonly dailyLimit: number;
82
159
  private readonly enabled: boolean;
83
160
 
@@ -87,11 +164,15 @@ export class BrevoEmailClient {
87
164
  private dailyByPriority = { critical: 0, normal: 0, low: 0 };
88
165
 
89
166
  private static readonly API_URL = 'https://api.brevo.com/v3/smtp/email';
167
+ private static readonly MAILERSEND_API_URL = 'https://api.mailersend.com/v1/email';
90
168
 
91
169
  constructor(config: BrevoEmailConfig) {
92
- this.apiKey = config.apiKey;
93
- this.senderName = config.senderName || 'Organify Team';
94
- this.senderEmail = config.senderEmail || 'noreply@organify.studio';
170
+ this.brevoApiKey = config.apiKey;
171
+ this.mailerSendApiKey = config.mailerSendApiKey || '';
172
+ this.brevoSenderName = config.senderName || 'Organify Team';
173
+ this.brevoSenderEmail = config.senderEmail || 'noreply@organify.studio';
174
+ this.mailerSendSenderName = config.mailerSendSenderName || this.brevoSenderName;
175
+ this.mailerSendSenderEmail = config.mailerSendSenderEmail || this.brevoSenderEmail;
95
176
  this.dailyLimit = config.dailyLimit || 300;
96
177
  this.enabled = config.enabled !== false;
97
178
  }
@@ -146,17 +227,71 @@ export class BrevoEmailClient {
146
227
  return { success: true, messageId: `dry-run-${Date.now()}`, skipped: false };
147
228
  }
148
229
 
149
- // Build Brevo payload
230
+ // Build Brevo/MailerSend payload basis
150
231
  const recipients = Array.isArray(options.to) ? options.to : [options.to];
151
- const payload: Record<string, any> = {
152
- sender: { name: this.senderName, email: this.senderEmail },
153
- to: recipients.map((r) => ({ email: r.email, name: r.name })),
232
+ const recipientPayload = recipients.map((r) => ({ email: r.email, name: r.name }));
233
+
234
+ if (!this.brevoApiKey && !this.mailerSendApiKey) {
235
+ return { success: false, error: 'No email provider key configured (BREVO_API_KEY or MAILERSEND_API_KEY)' };
236
+ }
237
+
238
+ if (this.brevoApiKey) {
239
+ const brevoResult = await this.sendViaBrevo({
240
+ recipients: recipientPayload,
241
+ subject: options.subject,
242
+ htmlContent,
243
+ textContent: options.textContent,
244
+ params: options.params,
245
+ tags: options.tags,
246
+ cc: options.cc,
247
+ bcc: options.bcc,
248
+ replyTo: options.replyTo,
249
+ });
250
+ if (brevoResult.success) {
251
+ this.incrementCounter(priority);
252
+ return brevoResult;
253
+ }
254
+ console.warn(`[Email] Brevo send failed; trying MailerSend fallback: ${brevoResult.error || 'unknown error'}`);
255
+ }
256
+
257
+ if (this.mailerSendApiKey) {
258
+ const mailerSendResult = await this.sendViaMailerSend({
259
+ recipients: recipientPayload,
260
+ subject: options.subject,
261
+ htmlContent,
262
+ textContent: options.textContent,
263
+ cc: options.cc,
264
+ bcc: options.bcc,
265
+ replyTo: options.replyTo,
266
+ });
267
+ if (mailerSendResult.success) {
268
+ this.incrementCounter(priority);
269
+ }
270
+ return mailerSendResult;
271
+ }
272
+
273
+ return { success: false, error: 'Brevo failed and MAILERSEND_API_KEY is not configured for fallback' };
274
+ }
275
+
276
+ private async sendViaBrevo(options: {
277
+ recipients: Array<{ email: string; name?: string }>;
278
+ subject: string;
279
+ htmlContent?: string;
280
+ textContent?: string;
281
+ params?: Record<string, string | number | boolean>;
282
+ tags?: string[];
283
+ cc?: EmailRecipient[];
284
+ bcc?: EmailRecipient[];
285
+ replyTo?: EmailRecipient;
286
+ }): Promise<SendResult> {
287
+ const payload: Record<string, unknown> = {
288
+ sender: { name: this.brevoSenderName, email: this.brevoSenderEmail },
289
+ to: options.recipients,
154
290
  subject: options.subject,
155
291
  };
156
292
 
157
- if (htmlContent) payload.htmlContent = htmlContent;
293
+ if (options.htmlContent) payload.htmlContent = options.htmlContent;
158
294
  else if (options.textContent) payload.textContent = options.textContent;
159
-
160
295
  if (options.params) payload.params = options.params;
161
296
  if (options.tags) payload.tags = options.tags;
162
297
  if (options.cc) payload.cc = options.cc;
@@ -167,8 +302,8 @@ export class BrevoEmailClient {
167
302
  const response = await fetch(BrevoEmailClient.API_URL, {
168
303
  method: 'POST',
169
304
  headers: {
170
- 'accept': 'application/json',
171
- 'api-key': this.apiKey,
305
+ accept: 'application/json',
306
+ 'api-key': this.brevoApiKey,
172
307
  'content-type': 'application/json',
173
308
  },
174
309
  body: JSON.stringify(payload),
@@ -177,16 +312,77 @@ export class BrevoEmailClient {
177
312
  if (!response.ok) {
178
313
  const body = await response.text();
179
314
  console.error(`[BrevoEmail] API error ${response.status}: ${body}`);
315
+ if (response.status === 401) {
316
+ console.error('[BrevoEmail] Check BREVO_API_KEY in env and ensure it is enabled for Transactional API/SMTP.');
317
+ }
180
318
  return { success: false, error: `Brevo API error: ${response.status} — ${body}` };
181
319
  }
182
320
 
183
321
  const data = await response.json() as { messageId?: string };
184
- this.incrementCounter(priority);
185
-
186
322
  return { success: true, messageId: data.messageId };
187
- } catch (err: any) {
188
- console.error(`[BrevoEmail] Network error: ${err.message}`);
189
- return { success: false, error: `Network error: ${err.message}` };
323
+ } catch (err: unknown) {
324
+ const message = err instanceof Error ? err.message : String(err);
325
+ console.error(`[BrevoEmail] Network error: ${message}`);
326
+ return { success: false, error: `Brevo network error: ${message}` };
327
+ }
328
+ }
329
+
330
+ private async sendViaMailerSend(options: {
331
+ recipients: Array<{ email: string; name?: string }>;
332
+ subject: string;
333
+ htmlContent?: string;
334
+ textContent?: string;
335
+ cc?: EmailRecipient[];
336
+ bcc?: EmailRecipient[];
337
+ replyTo?: EmailRecipient;
338
+ }): Promise<SendResult> {
339
+ const payload: Record<string, unknown> = {
340
+ from: { email: this.mailerSendSenderEmail, name: this.mailerSendSenderName },
341
+ to: options.recipients,
342
+ subject: options.subject,
343
+ };
344
+
345
+ if (options.htmlContent) payload.html = options.htmlContent;
346
+ if (options.textContent) payload.text = options.textContent;
347
+ if (!options.textContent && options.htmlContent) {
348
+ payload.text = 'Mensagem enviada pelo Organify.';
349
+ }
350
+ if (options.cc) payload.cc = options.cc;
351
+ if (options.bcc) payload.bcc = options.bcc;
352
+ if (options.replyTo) {
353
+ payload.reply_to = {
354
+ email: options.replyTo.email,
355
+ name: options.replyTo.name,
356
+ };
357
+ } else {
358
+ payload.reply_to = {
359
+ email: this.mailerSendSenderEmail,
360
+ name: this.mailerSendSenderName,
361
+ };
362
+ }
363
+
364
+ try {
365
+ const response = await fetch(BrevoEmailClient.MAILERSEND_API_URL, {
366
+ method: 'POST',
367
+ headers: {
368
+ Authorization: `Bearer ${this.mailerSendApiKey}`,
369
+ 'Content-Type': 'application/json',
370
+ },
371
+ body: JSON.stringify(payload),
372
+ });
373
+
374
+ if (!response.ok) {
375
+ const body = await response.text();
376
+ console.error(`[MailerSendEmail] API error ${response.status}: ${body}`);
377
+ return { success: false, error: `MailerSend API error: ${response.status} — ${body}` };
378
+ }
379
+
380
+ const messageId = response.headers.get('x-message-id') || undefined;
381
+ return { success: true, messageId };
382
+ } catch (err: unknown) {
383
+ const message = err instanceof Error ? err.message : String(err);
384
+ console.error(`[MailerSendEmail] Network error: ${message}`);
385
+ return { success: false, error: `MailerSend network error: ${message}` };
190
386
  }
191
387
  }
192
388
 
package/src/index.ts CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  export {
6
6
  BrevoEmailClient,
7
+ HARDCODED_BREVO_PROVIDER,
8
+ ORGANIFY_EMAIL_DAILY_LIMITS,
9
+ createOrganifyEmailClient,
10
+ type OrganifyEmailService,
7
11
  type BrevoEmailConfig,
8
12
  type EmailRecipient,
9
13
  type SendEmailOptions,