@blackcode_sa/metaestetics-api 1.5.50 → 1.5.52

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,308 +1,136 @@
1
- import * as mailgun from "mailgun-js";
2
1
  import * as admin from "firebase-admin";
3
- import { Logger } from "../logger";
2
+ // Import the new Mailgun types if available, or use a generic 'any' if not directly importable
3
+ // For a shared library, it's often better to define a minimal interface for what you need
4
+ // or expect the caller (Cloud Function) to pass a pre-configured client of 'any' type.
5
+ // import Mailgun from "mailgun.js"; // This might not be a direct dep of the API pkg
6
+ import { Logger } from "../logger"; // Assuming logger is in Api/src/logger
4
7
 
5
8
  /**
6
- * Mailgun client type for compatibility with new mailgun.js library
7
- * This allows us to accept both older mailgun-js and newer mailgun.js clients
9
+ * Minimal interface for the new mailgun.js client's messages API
10
+ * This helps avoid a direct dependency on mailgun.js in the API package if not desired,
11
+ * or provides clearer typing if it is.
8
12
  */
9
- interface MailgunClientCompat {
10
- messages: {
11
- create?: (domain: string, data: any) => Promise<any>;
12
- send?: (data: any, callback: (error: any, body: any) => void) => void;
13
- };
13
+ interface NewMailgunMessagesAPI {
14
+ create(domain: string, data: any): Promise<any>;
15
+ }
16
+
17
+ interface NewMailgunClient {
18
+ messages: NewMailgunMessagesAPI;
19
+ // Add other methods/properties if your BaseMailingService uses them
14
20
  }
15
21
 
16
22
  /**
17
23
  * Base mailing service class that provides common functionality for all mailing services
24
+ * This version is updated to expect a mailgun.js v10+ client.
18
25
  */
19
26
  export class BaseMailingService {
20
27
  protected db: FirebaseFirestore.Firestore;
21
- protected mailgunClient: mailgun.Mailgun | MailgunClientCompat;
22
- protected isNewMailgunClient: boolean = false;
23
- // Removed config property as it's no longer managed here
24
- // import {
25
- // getMailgunConfig,
26
- // createMailgunClient,
27
- // MailgunConfig,
28
- // } from "./mailgun.config";
28
+ protected mailgunClient: NewMailgunClient; // Expecting the new mailgun.js client
29
29
 
30
30
  /**
31
31
  * Constructor for BaseMailingService
32
32
  * @param firestore Firestore instance provided by the caller
33
- * @param mailgunClient Mailgun client instance provided by the caller
33
+ * @param mailgunClient Mailgun client instance (mailgun.js v10+) provided by the caller
34
34
  */
35
35
  constructor(
36
36
  firestore: FirebaseFirestore.Firestore,
37
- mailgunClient: mailgun.Mailgun | MailgunClientCompat // Accept either old or new client
37
+ mailgunClient: NewMailgunClient // Expect the new client
38
38
  ) {
39
- // Use provided instances
40
39
  this.db = firestore;
41
40
  this.mailgunClient = mailgunClient;
42
41
 
43
- // Validate instances
44
42
  if (!this.db) {
45
43
  Logger.error("[BaseMailingService] No Firestore instance provided");
46
44
  throw new Error("Firestore instance is required");
47
45
  }
48
46
 
49
- if (!this.mailgunClient) {
50
- Logger.error("[BaseMailingService] No Mailgun client provided");
51
- throw new Error("Mailgun client is required");
47
+ if (
48
+ !this.mailgunClient ||
49
+ typeof this.mailgunClient.messages?.create !== "function"
50
+ ) {
51
+ Logger.error(
52
+ "[BaseMailingService] Invalid Mailgun client provided (must be mailgun.js v10+ client)"
53
+ );
54
+ throw new Error("A valid mailgun.js v10+ client is required");
52
55
  }
53
56
 
54
- // Detect which type of mailgun client we're using
55
- this.isNewMailgunClient =
56
- typeof (this.mailgunClient.messages as any).create === "function";
57
+ // The new client is configured with the URL (e.g., EU endpoint) by the caller.
58
+ // Validation of this configuration can be logged if details are accessible,
59
+ // but the primary responsibility for correct endpoint is now with client setup.
57
60
  Logger.info(
58
- `[BaseMailingService] Using ${
59
- this.isNewMailgunClient ? "new" : "legacy"
60
- } Mailgun client`
61
+ "[BaseMailingService] Service initialized with mailgun.js client."
61
62
  );
62
-
63
- // Validate the Mailgun client configuration
64
- this.validateMailgunClient();
65
-
66
- // Log successful initialization
67
- Logger.info("[BaseMailingService] Service initialized successfully");
68
63
  }
69
64
 
70
65
  /**
71
- * Validates that the Mailgun client is configured correctly
72
- * Particularly checks for EU region configuration
73
- */
74
- private validateMailgunClient(): void {
75
- try {
76
- // For the legacy client, check EU region configuration
77
- if (!this.isNewMailgunClient) {
78
- const clientOptions = (this.mailgunClient as any).options || {};
79
- const host = clientOptions.host || "";
80
- const isEuRegion = host.includes("eu.mailgun.net");
81
-
82
- Logger.info("[BaseMailingService] Mailgun client configuration:", {
83
- host: host || "default",
84
- isEuRegion,
85
- domain: clientOptions.domain || "unknown",
86
- clientType: "legacy",
87
- });
88
-
89
- // Check if this appears to be an EU domain but not using EU endpoint
90
- if (
91
- clientOptions.domain &&
92
- clientOptions.domain.endsWith(".eu") &&
93
- !isEuRegion
94
- ) {
95
- Logger.warn(
96
- "[BaseMailingService] Domain appears to be in EU region but not using EU endpoint. " +
97
- "If you're getting 401 Forbidden errors, ensure the host is set to 'api.eu.mailgun.net'"
98
- );
99
- }
100
- } else {
101
- // For the new client, we can't easily check the configuration
102
- // but it should be properly configured with the URL parameter
103
- Logger.info("[BaseMailingService] Using new Mailgun client", {
104
- clientType: "mailgun.js",
105
- });
106
- }
107
- } catch (error) {
108
- // Just log the error, don't throw
109
- Logger.warn("[BaseMailingService] Could not validate Mailgun client:", {
110
- error: error instanceof Error ? error.message : String(error),
111
- });
112
- }
113
- }
114
-
115
- /**
116
- * Sends an email using Mailgun
117
- * @param data Email data to send, including the 'from' address
66
+ * Sends an email using the new Mailgun client API.
67
+ * @param domain The Mailgun domain to send from (e.g., mg.metaesthetics.net)
68
+ * @param data Email data to send, compatible with mailgun.js messages.create API
118
69
  * @returns Promise with the sending result
119
70
  */
120
71
  protected async sendEmail(
121
- data: mailgun.messages.SendData // Caller must provide 'from'
72
+ domain: string, // The new API requires the domain as the first argument to messages.create
73
+ data: any // Data format according to mailgun.js messages.create
122
74
  ): Promise<any> {
123
- try {
124
- // Validate email data fields
125
- if (!data) {
126
- throw new Error("Email data object is required");
127
- }
128
-
129
- // Ensure all required fields are provided
130
- if (!data.to) {
131
- throw new Error("Email 'to' address is required");
132
- }
133
-
134
- // Ensure 'from' field is provided by the caller
135
- if (!data.from) {
136
- throw new Error(
137
- "Email 'from' address must be provided in sendEmail data."
138
- );
139
- }
140
-
141
- if (!data.subject) {
142
- throw new Error("Email 'subject' is required");
143
- }
144
-
145
- if (!data.html && !data.text) {
146
- throw new Error("Email must have either 'html' or 'text' content");
147
- }
75
+ if (!domain) {
76
+ throw new Error("Mailgun domain is required for sending email.");
77
+ }
78
+ if (!data) {
79
+ throw new Error("Email data object is required");
80
+ }
81
+ if (!data.to) {
82
+ throw new Error("Email 'to' address is required");
83
+ }
84
+ if (!data.from) {
85
+ throw new Error("Email 'from' address is required");
86
+ }
87
+ if (!data.subject) {
88
+ throw new Error("Email 'subject' is required");
89
+ }
90
+ if (!data.html && !data.text) {
91
+ throw new Error("Email must have either 'html' or 'text' content");
92
+ }
148
93
 
149
- Logger.info("[BaseMailingService] Sending email via Mailgun", {
94
+ Logger.info(
95
+ "[BaseMailingService] Sending email via Mailgun (mailgun.js API)",
96
+ {
97
+ domain,
150
98
  to: data.to,
151
99
  from: data.from,
152
100
  subject: data.subject,
153
101
  hasHtml: !!data.html,
154
102
  hasText: !!data.text,
155
- clientType: this.isNewMailgunClient ? "mailgun.js" : "legacy",
156
- });
157
-
158
- // Use the appropriate API based on the client type
159
- if (this.isNewMailgunClient) {
160
- // New mailgun.js client
161
- try {
162
- const createMethod = (this.mailgunClient.messages as any).create;
163
- // Get domain from client if possible, or from the from address as fallback
164
- const domain =
165
- this.getDomainFromOptions() || this.getDomainFromEmail(data.from);
166
-
167
- if (!domain) {
168
- throw new Error("Could not determine domain for Mailgun API call");
169
- }
170
-
171
- Logger.info(
172
- "[BaseMailingService] Using domain for new Mailgun client:",
173
- { domain }
174
- );
175
-
176
- // Call the create method with domain and data
177
- const result = await createMethod(domain, data);
178
- Logger.info(
179
- "[BaseMailingService] Email sent successfully with new client"
180
- );
181
- return result;
182
- } catch (error) {
183
- Logger.error(
184
- "[BaseMailingService] Error sending with new Mailgun client:",
185
- {
186
- error: error instanceof Error ? error.message : String(error),
187
- stack: error instanceof Error ? error.stack : undefined,
188
- }
189
- );
190
- throw error;
191
- }
192
- } else {
193
- // Legacy mailgun-js client
194
- return await new Promise<mailgun.messages.SendResponse>(
195
- (resolve, reject) => {
196
- try {
197
- const messagesApi = this.mailgunClient.messages as any;
198
- if (!messagesApi || !messagesApi.send) {
199
- throw new Error("Could not get Mailgun messages API");
200
- }
201
-
202
- messagesApi.send(data, (error: any, body: any) => {
203
- if (error) {
204
- // Enhanced error logging for auth/region issues
205
- if (error.statusCode === 401 || error.statusCode === 403) {
206
- const clientOptions =
207
- (this.mailgunClient as any).options || {};
208
- Logger.error(
209
- "[BaseMailingService] Mailgun authentication error - possible region mismatch:",
210
- {
211
- error: error instanceof Error ? error.message : error,
212
- statusCode: error.statusCode,
213
- domain: clientOptions.domain || "unknown",
214
- host: clientOptions.host || "default api.mailgun.net",
215
- suggestion:
216
- "If using EU region domains, ensure host is set to 'api.eu.mailgun.net'",
217
- response: (error as any).response
218
- ? JSON.stringify((error as any).response)
219
- : "No response details",
220
- request: (error as any).request
221
- ? {
222
- method: (error as any).request?.method,
223
- path: (error as any).request?.path,
224
- host: (error as any).request?.host,
225
- }
226
- : "No request details",
227
- }
228
- );
229
- } else {
230
- Logger.error("[BaseMailingService] Mailgun API error:", {
231
- error: error instanceof Error ? error.message : error,
232
- statusCode: error.statusCode,
233
- stack: error instanceof Error ? error.stack : undefined,
234
- });
235
- }
236
- reject(error);
237
- } else {
238
- Logger.info(
239
- "[BaseMailingService] Email sent successfully:",
240
- body
241
- );
242
- resolve(body);
243
- }
244
- });
245
- } catch (sendError) {
246
- Logger.error(
247
- "[BaseMailingService] Error in mailgun.messages().send():",
248
- {
249
- error:
250
- sendError instanceof Error ? sendError.message : sendError,
251
- stack:
252
- sendError instanceof Error ? sendError.stack : undefined,
253
- }
254
- );
255
- reject(sendError);
256
- }
257
- }
258
- );
259
103
  }
260
- } catch (error) {
261
- Logger.error("[BaseMailingService] Error in sendEmail:", {
262
- error: error instanceof Error ? error.message : error,
263
- stack: error instanceof Error ? error.stack : undefined,
264
- });
265
- throw error;
266
- }
267
- }
268
-
269
- /**
270
- * Tries to get domain from mailgun client options
271
- * @returns Domain string or undefined
272
- */
273
- private getDomainFromOptions(): string | undefined {
274
- try {
275
- // Different ways to get domain depending on client type
276
- if (this.isNewMailgunClient) {
277
- return (this.mailgunClient as any).domain;
278
- } else {
279
- const options = (this.mailgunClient as any).options;
280
- return options?.domain;
281
- }
282
- } catch (e) {
283
- return undefined;
284
- }
285
- }
104
+ );
286
105
 
287
- /**
288
- * Extracts domain from an email address
289
- * @param email Email address
290
- * @returns Domain part or undefined
291
- */
292
- private getDomainFromEmail(email: string): string | undefined {
293
106
  try {
294
- // Extract from "Name <email@domain.com>" format
295
- const match = email.match(/<([^>]+)>/) || [null, email];
296
- const emailPart = match[1];
297
-
298
- // Get domain part
299
- const domainMatch = emailPart.match(/@([^@]+)$/);
300
- if (domainMatch && domainMatch[1]) {
301
- return domainMatch[1];
302
- }
303
- return undefined;
304
- } catch (e) {
305
- return undefined;
107
+ // Use the new mailgun.js client API: client.messages.create(domain, data)
108
+ const result = await this.mailgunClient.messages.create(domain, data);
109
+ Logger.info(
110
+ "[BaseMailingService] Email sent successfully with mailgun.js client",
111
+ result
112
+ );
113
+ return result;
114
+ } catch (error: any) {
115
+ Logger.error(
116
+ "[BaseMailingService] Error sending email with mailgun.js client",
117
+ {
118
+ errorMessage: error?.message,
119
+ errorDetails: error?.details, // mailgun.js errors often have a details field
120
+ errorStatusCode: error?.status, // and a status field for HTTP status code
121
+ stack: error?.stack,
122
+ domain,
123
+ to: data.to,
124
+ }
125
+ );
126
+ // Re-throw a more specific error or the original
127
+ const mailgunError = new Error(
128
+ `Mailgun API Error (${error?.status || "unknown"}): ${
129
+ error?.details || error?.message || "Failed to send email"
130
+ }`
131
+ );
132
+ (mailgunError as any).originalError = error;
133
+ throw mailgunError;
306
134
  }
307
135
  }
308
136
 
@@ -325,9 +153,12 @@ export class BaseMailingService {
325
153
  templateName: emailData.templateName,
326
154
  success,
327
155
  error: error
328
- ? error instanceof Error
329
- ? { message: error.message, stack: error.stack }
330
- : JSON.stringify(error)
156
+ ? {
157
+ message: error.message,
158
+ details: (error as any).details,
159
+ status: (error as any).status,
160
+ stack: error.stack,
161
+ }
331
162
  : null,
332
163
  sentAt: admin.firestore.FieldValue.serverTimestamp(),
333
164
  });
@@ -335,10 +166,10 @@ export class BaseMailingService {
335
166
  Logger.info(
336
167
  `[BaseMailingService] Email log recorded. Success: ${success}`
337
168
  );
338
- } catch (logError) {
169
+ } catch (logError: any) {
339
170
  Logger.error("[BaseMailingService] Error logging email attempt:", {
340
- error: logError instanceof Error ? logError.message : logError,
341
- stack: logError instanceof Error ? logError.stack : undefined,
171
+ errorMessage: logError.message,
172
+ stack: logError.stack,
342
173
  });
343
174
  // Don't throw here to prevent disrupting the main flow
344
175
  }
@@ -360,22 +191,17 @@ export class BaseMailingService {
360
191
 
361
192
  try {
362
193
  let rendered = template;
363
-
364
- // Replace template variables (format: {{variable_name}})
365
194
  Object.entries(variables).forEach(([key, value]) => {
366
- const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g");
195
+ const regex = new RegExp(`{{\s*${key}\s*}}`, "g");
367
196
  rendered = rendered.replace(regex, value || "");
368
197
  });
369
-
370
198
  return rendered;
371
- } catch (renderError) {
199
+ } catch (renderError: any) {
372
200
  Logger.error("[BaseMailingService] Error rendering template:", {
373
- error: renderError instanceof Error ? renderError.message : renderError,
201
+ errorMessage: renderError.message,
374
202
  });
375
203
  throw new Error(
376
- `Template rendering failed: ${
377
- renderError instanceof Error ? renderError.message : "Unknown error"
378
- }`
204
+ `Template rendering failed: ${renderError.message || "Unknown error"}`
379
205
  );
380
206
  }
381
207
  }
@@ -1,5 +1,4 @@
1
1
  import * as admin from "firebase-admin";
2
- import * as mailgun from "mailgun-js";
3
2
  import { BaseMailingService } from "../base.mailing.service";
4
3
  import { practitionerInvitationTemplate } from "./templates/invitation.template";
5
4
  import { Logger } from "../../logger";
@@ -8,9 +7,18 @@ import {
8
7
  Practitioner,
9
8
  PractitionerToken,
10
9
  PRACTITIONERS_COLLECTION,
10
+ PractitionerTokenStatus,
11
11
  } from "../../../types/practitioner";
12
12
  import { Clinic, CLINICS_COLLECTION } from "../../../types/clinic";
13
13
 
14
+ // Define a minimal interface for the mailgun.js client if not importing full types
15
+ interface NewMailgunMessagesAPI {
16
+ create(domain: string, data: any): Promise<any>;
17
+ }
18
+ interface NewMailgunClient {
19
+ messages: NewMailgunMessagesAPI;
20
+ }
21
+
14
22
  /**
15
23
  * Interface for the data required to send a practitioner invitation email
16
24
  */
@@ -43,28 +51,28 @@ export interface PractitionerInviteEmailData {
43
51
  registrationUrl?: string;
44
52
  customSubject?: string;
45
53
  fromAddress?: string;
54
+ mailgunDomain?: string;
46
55
  };
47
56
  }
48
57
 
49
58
  /**
50
- * Service for sending practitioner invitation emails
59
+ * Service for sending practitioner invitation emails, updated for mailgun.js v10+
51
60
  */
52
61
  export class PractitionerInviteMailingService extends BaseMailingService {
53
62
  private readonly DEFAULT_REGISTRATION_URL =
54
- "https://metaestetics.net/register";
63
+ "https://metaesthetics.net/register";
55
64
  private readonly DEFAULT_SUBJECT =
56
65
  "You've Been Invited to Join as a Practitioner";
57
- private readonly DEFAULT_FROM_ADDRESS =
58
- "MedClinic <no-reply@mg.metaesthetics.net>";
66
+ private readonly DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
59
67
 
60
68
  /**
61
69
  * Constructor for PractitionerInviteMailingService
62
70
  * @param firestore Firestore instance provided by the caller
63
- * @param mailgunClient Mailgun client instance provided by the caller
71
+ * @param mailgunClient Mailgun client instance (mailgun.js v10+) provided by the caller
64
72
  */
65
73
  constructor(
66
74
  firestore: FirebaseFirestore.Firestore,
67
- mailgunClient: mailgun.Mailgun
75
+ mailgunClient: NewMailgunClient
68
76
  ) {
69
77
  super(firestore, mailgunClient);
70
78
  }
@@ -74,9 +82,7 @@ export class PractitionerInviteMailingService extends BaseMailingService {
74
82
  * @param data The practitioner invitation data
75
83
  * @returns Promise resolved when email is sent
76
84
  */
77
- async sendInvitationEmail(
78
- data: PractitionerInviteEmailData
79
- ): Promise<mailgun.messages.SendResponse> {
85
+ async sendInvitationEmail(data: PractitionerInviteEmailData): Promise<any> {
80
86
  try {
81
87
  Logger.info(
82
88
  "[PractitionerInviteMailingService] Sending invitation email to",
@@ -106,7 +112,10 @@ export class PractitionerInviteMailingService extends BaseMailingService {
106
112
 
107
113
  // Determine 'from' address
108
114
  const fromAddress =
109
- data.options?.fromAddress || this.DEFAULT_FROM_ADDRESS;
115
+ data.options?.fromAddress ||
116
+ `MetaEstetics <no-reply@${
117
+ data.options?.mailgunDomain || this.DEFAULT_MAILGUN_DOMAIN
118
+ }>`;
110
119
 
111
120
  // Current year for copyright
112
121
  const currentYear = new Date().getFullYear().toString();
@@ -144,25 +153,31 @@ export class PractitionerInviteMailingService extends BaseMailingService {
144
153
  templateVariables
145
154
  );
146
155
 
147
- // Send email - ensure 'from' is included
148
- const emailData: mailgun.messages.SendData = {
156
+ // Data for the new sendEmail signature
157
+ const mailgunSendData = {
149
158
  to: data.token.email,
150
159
  from: fromAddress,
151
160
  subject,
152
161
  html,
153
162
  };
154
163
 
164
+ // Determine the domain to use for sending
165
+ const domainToSendFrom =
166
+ data.options?.mailgunDomain || this.DEFAULT_MAILGUN_DOMAIN;
167
+
155
168
  Logger.info(
156
169
  "[PractitionerInviteMailingService] Sending email with data:",
157
170
  {
158
- to: emailData.to,
159
- from: emailData.from,
160
- subject: emailData.subject,
161
- hasHtml: !!emailData.html,
171
+ domain: domainToSendFrom,
172
+ to: mailgunSendData.to,
173
+ from: mailgunSendData.from,
174
+ subject: mailgunSendData.subject,
175
+ hasHtml: !!mailgunSendData.html,
162
176
  }
163
177
  );
164
178
 
165
- const result = await this.sendEmail(emailData);
179
+ // Call the updated sendEmail method from BaseMailingService
180
+ const result = await this.sendEmail(domainToSendFrom, mailgunSendData);
166
181
 
167
182
  // Log success
168
183
  await this.logEmailAttempt(
@@ -175,12 +190,14 @@ export class PractitionerInviteMailingService extends BaseMailingService {
175
190
  );
176
191
 
177
192
  return result;
178
- } catch (error) {
193
+ } catch (error: any) {
179
194
  Logger.error(
180
195
  "[PractitionerInviteMailingService] Error sending invitation email:",
181
196
  {
182
- error: error instanceof Error ? error.message : error,
183
- stack: error instanceof Error ? error.stack : undefined,
197
+ errorMessage: error.message,
198
+ errorDetails: error.details,
199
+ errorStatus: error.status,
200
+ stack: error.stack,
184
201
  }
185
202
  );
186
203
 
@@ -205,11 +222,16 @@ export class PractitionerInviteMailingService extends BaseMailingService {
205
222
  * and sends the invitation email.
206
223
  * @param tokenData The fully typed token object including its id
207
224
  * @param fromAddress The 'from' email address to use, obtained from config
225
+ * @param mailgunDomain The mailgun domain to use for sending
208
226
  * @returns Promise resolved when the email is sent
209
227
  */
210
228
  async handleTokenCreationEvent(
211
229
  tokenData: PractitionerToken,
212
- fromAddress: string
230
+ mailgunConfig: {
231
+ fromAddress: string;
232
+ domain: string;
233
+ registrationUrl?: string;
234
+ }
213
235
  ): Promise<void> {
214
236
  try {
215
237
  Logger.info(
@@ -239,8 +261,15 @@ export class PractitionerInviteMailingService extends BaseMailingService {
239
261
  }
240
262
 
241
263
  // Validate token status (handle both enum and string values)
242
- if (!tokenData.status) {
243
- throw new Error(`Token ${tokenData.id} has no status defined`);
264
+ if (
265
+ tokenData.status !== PractitionerTokenStatus.ACTIVE &&
266
+ String(tokenData.status).toLowerCase() !== "active"
267
+ ) {
268
+ Logger.warn(
269
+ "[PractitionerInviteMailingService] Token is not active, skipping email.",
270
+ { tokenId: tokenData.id, status: tokenData.status }
271
+ );
272
+ return;
244
273
  }
245
274
 
246
275
  // Log token status to help with debugging
@@ -305,11 +334,11 @@ export class PractitionerInviteMailingService extends BaseMailingService {
305
334
  // So we'll use simple contact information from contactInfo
306
335
 
307
336
  // Validate fromAddress
308
- if (!fromAddress) {
337
+ if (!mailgunConfig.fromAddress) {
309
338
  Logger.warn(
310
339
  "[PractitionerInviteMailingService] No fromAddress provided, using default"
311
340
  );
312
- fromAddress = this.DEFAULT_FROM_ADDRESS;
341
+ mailgunConfig.fromAddress = `MetaEstetics <no-reply@${this.DEFAULT_MAILGUN_DOMAIN}>`;
313
342
  }
314
343
 
315
344
  // Prepare email data using typed data
@@ -333,7 +362,9 @@ export class PractitionerInviteMailingService extends BaseMailingService {
333
362
  contactName: "Clinic Admin",
334
363
  },
335
364
  options: {
336
- fromAddress: fromAddress,
365
+ fromAddress: mailgunConfig.fromAddress,
366
+ mailgunDomain: mailgunConfig.domain,
367
+ registrationUrl: mailgunConfig.registrationUrl,
337
368
  },
338
369
  };
339
370
 
@@ -347,12 +378,15 @@ export class PractitionerInviteMailingService extends BaseMailingService {
347
378
  Logger.info(
348
379
  "[PractitionerInviteMailingService] Invitation email sent successfully"
349
380
  );
350
- } catch (error) {
381
+ } catch (error: any) {
351
382
  Logger.error(
352
383
  "[PractitionerInviteMailingService] Error handling token creation event:",
353
384
  {
354
- error: error instanceof Error ? error.message : error,
355
- stack: error instanceof Error ? error.stack : undefined,
385
+ errorMessage: error.message,
386
+ errorDetails: error.details,
387
+ errorStatus: error.status,
388
+ stack: error.stack,
389
+ tokenId: tokenData?.id,
356
390
  }
357
391
  );
358
392
  throw error;