@blackcode_sa/metaestetics-api 1.5.49 → 1.5.51
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/dist/admin/index.d.mts +25 -3
- package/dist/admin/index.d.ts +25 -3
- package/dist/admin/index.js +139 -73
- package/dist/admin/index.mjs +139 -73
- package/package.json +1 -1
- package/src/admin/mailing/base.mailing.service.ts +188 -92
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +1 -1
package/dist/admin/index.d.mts
CHANGED
|
@@ -1506,18 +1506,29 @@ declare class PatientAggregationService {
|
|
|
1506
1506
|
cancelUpcomingCalendarEventsForPatient(patientId: string): Promise<void>;
|
|
1507
1507
|
}
|
|
1508
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* Mailgun client type for compatibility with new mailgun.js library
|
|
1511
|
+
* This allows us to accept both older mailgun-js and newer mailgun.js clients
|
|
1512
|
+
*/
|
|
1513
|
+
interface MailgunClientCompat {
|
|
1514
|
+
messages: {
|
|
1515
|
+
create?: (domain: string, data: any) => Promise<any>;
|
|
1516
|
+
send?: (data: any, callback: (error: any, body: any) => void) => void;
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1509
1519
|
/**
|
|
1510
1520
|
* Base mailing service class that provides common functionality for all mailing services
|
|
1511
1521
|
*/
|
|
1512
1522
|
declare class BaseMailingService {
|
|
1513
1523
|
protected db: FirebaseFirestore.Firestore;
|
|
1514
|
-
protected mailgunClient: mailgun.Mailgun;
|
|
1524
|
+
protected mailgunClient: mailgun.Mailgun | MailgunClientCompat;
|
|
1525
|
+
protected isNewMailgunClient: boolean;
|
|
1515
1526
|
/**
|
|
1516
1527
|
* Constructor for BaseMailingService
|
|
1517
1528
|
* @param firestore Firestore instance provided by the caller
|
|
1518
1529
|
* @param mailgunClient Mailgun client instance provided by the caller
|
|
1519
1530
|
*/
|
|
1520
|
-
constructor(firestore: FirebaseFirestore.Firestore, mailgunClient: mailgun.Mailgun);
|
|
1531
|
+
constructor(firestore: FirebaseFirestore.Firestore, mailgunClient: mailgun.Mailgun | MailgunClientCompat);
|
|
1521
1532
|
/**
|
|
1522
1533
|
* Validates that the Mailgun client is configured correctly
|
|
1523
1534
|
* Particularly checks for EU region configuration
|
|
@@ -1528,7 +1539,18 @@ declare class BaseMailingService {
|
|
|
1528
1539
|
* @param data Email data to send, including the 'from' address
|
|
1529
1540
|
* @returns Promise with the sending result
|
|
1530
1541
|
*/
|
|
1531
|
-
protected sendEmail(data: mailgun.messages.SendData): Promise<
|
|
1542
|
+
protected sendEmail(data: mailgun.messages.SendData): Promise<any>;
|
|
1543
|
+
/**
|
|
1544
|
+
* Tries to get domain from mailgun client options
|
|
1545
|
+
* @returns Domain string or undefined
|
|
1546
|
+
*/
|
|
1547
|
+
private getDomainFromOptions;
|
|
1548
|
+
/**
|
|
1549
|
+
* Extracts domain from an email address
|
|
1550
|
+
* @param email Email address
|
|
1551
|
+
* @returns Domain part or undefined
|
|
1552
|
+
*/
|
|
1553
|
+
private getDomainFromEmail;
|
|
1532
1554
|
/**
|
|
1533
1555
|
* Logs email sending attempt to Firestore for tracking
|
|
1534
1556
|
* @param emailData Email data that was sent
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -1506,18 +1506,29 @@ declare class PatientAggregationService {
|
|
|
1506
1506
|
cancelUpcomingCalendarEventsForPatient(patientId: string): Promise<void>;
|
|
1507
1507
|
}
|
|
1508
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* Mailgun client type for compatibility with new mailgun.js library
|
|
1511
|
+
* This allows us to accept both older mailgun-js and newer mailgun.js clients
|
|
1512
|
+
*/
|
|
1513
|
+
interface MailgunClientCompat {
|
|
1514
|
+
messages: {
|
|
1515
|
+
create?: (domain: string, data: any) => Promise<any>;
|
|
1516
|
+
send?: (data: any, callback: (error: any, body: any) => void) => void;
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1509
1519
|
/**
|
|
1510
1520
|
* Base mailing service class that provides common functionality for all mailing services
|
|
1511
1521
|
*/
|
|
1512
1522
|
declare class BaseMailingService {
|
|
1513
1523
|
protected db: FirebaseFirestore.Firestore;
|
|
1514
|
-
protected mailgunClient: mailgun.Mailgun;
|
|
1524
|
+
protected mailgunClient: mailgun.Mailgun | MailgunClientCompat;
|
|
1525
|
+
protected isNewMailgunClient: boolean;
|
|
1515
1526
|
/**
|
|
1516
1527
|
* Constructor for BaseMailingService
|
|
1517
1528
|
* @param firestore Firestore instance provided by the caller
|
|
1518
1529
|
* @param mailgunClient Mailgun client instance provided by the caller
|
|
1519
1530
|
*/
|
|
1520
|
-
constructor(firestore: FirebaseFirestore.Firestore, mailgunClient: mailgun.Mailgun);
|
|
1531
|
+
constructor(firestore: FirebaseFirestore.Firestore, mailgunClient: mailgun.Mailgun | MailgunClientCompat);
|
|
1521
1532
|
/**
|
|
1522
1533
|
* Validates that the Mailgun client is configured correctly
|
|
1523
1534
|
* Particularly checks for EU region configuration
|
|
@@ -1528,7 +1539,18 @@ declare class BaseMailingService {
|
|
|
1528
1539
|
* @param data Email data to send, including the 'from' address
|
|
1529
1540
|
* @returns Promise with the sending result
|
|
1530
1541
|
*/
|
|
1531
|
-
protected sendEmail(data: mailgun.messages.SendData): Promise<
|
|
1542
|
+
protected sendEmail(data: mailgun.messages.SendData): Promise<any>;
|
|
1543
|
+
/**
|
|
1544
|
+
* Tries to get domain from mailgun client options
|
|
1545
|
+
* @returns Domain string or undefined
|
|
1546
|
+
*/
|
|
1547
|
+
private getDomainFromOptions;
|
|
1548
|
+
/**
|
|
1549
|
+
* Extracts domain from an email address
|
|
1550
|
+
* @param email Email address
|
|
1551
|
+
* @returns Domain part or undefined
|
|
1552
|
+
*/
|
|
1553
|
+
private getDomainFromEmail;
|
|
1532
1554
|
/**
|
|
1533
1555
|
* Logs email sending attempt to Firestore for tracking
|
|
1534
1556
|
* @param emailData Email data that was sent
|
package/dist/admin/index.js
CHANGED
|
@@ -1640,6 +1640,7 @@ var BaseMailingService = class {
|
|
|
1640
1640
|
* @param mailgunClient Mailgun client instance provided by the caller
|
|
1641
1641
|
*/
|
|
1642
1642
|
constructor(firestore8, mailgunClient) {
|
|
1643
|
+
this.isNewMailgunClient = false;
|
|
1643
1644
|
this.db = firestore8;
|
|
1644
1645
|
this.mailgunClient = mailgunClient;
|
|
1645
1646
|
if (!this.db) {
|
|
@@ -1650,6 +1651,10 @@ var BaseMailingService = class {
|
|
|
1650
1651
|
Logger.error("[BaseMailingService] No Mailgun client provided");
|
|
1651
1652
|
throw new Error("Mailgun client is required");
|
|
1652
1653
|
}
|
|
1654
|
+
this.isNewMailgunClient = typeof this.mailgunClient.messages.create === "function";
|
|
1655
|
+
Logger.info(
|
|
1656
|
+
`[BaseMailingService] Using ${this.isNewMailgunClient ? "new" : "legacy"} Mailgun client`
|
|
1657
|
+
);
|
|
1653
1658
|
this.validateMailgunClient();
|
|
1654
1659
|
Logger.info("[BaseMailingService] Service initialized successfully");
|
|
1655
1660
|
}
|
|
@@ -1659,18 +1664,25 @@ var BaseMailingService = class {
|
|
|
1659
1664
|
*/
|
|
1660
1665
|
validateMailgunClient() {
|
|
1661
1666
|
try {
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1667
|
+
if (!this.isNewMailgunClient) {
|
|
1668
|
+
const clientOptions = this.mailgunClient.options || {};
|
|
1669
|
+
const host = clientOptions.host || "";
|
|
1670
|
+
const isEuRegion = host.includes("eu.mailgun.net");
|
|
1671
|
+
Logger.info("[BaseMailingService] Mailgun client configuration:", {
|
|
1672
|
+
host: host || "default",
|
|
1673
|
+
isEuRegion,
|
|
1674
|
+
domain: clientOptions.domain || "unknown",
|
|
1675
|
+
clientType: "legacy"
|
|
1676
|
+
});
|
|
1677
|
+
if (clientOptions.domain && clientOptions.domain.endsWith(".eu") && !isEuRegion) {
|
|
1678
|
+
Logger.warn(
|
|
1679
|
+
"[BaseMailingService] Domain appears to be in EU region but not using EU endpoint. If you're getting 401 Forbidden errors, ensure the host is set to 'api.eu.mailgun.net'"
|
|
1680
|
+
);
|
|
1681
|
+
}
|
|
1682
|
+
} else {
|
|
1683
|
+
Logger.info("[BaseMailingService] Using new Mailgun client", {
|
|
1684
|
+
clientType: "mailgun.js"
|
|
1685
|
+
});
|
|
1674
1686
|
}
|
|
1675
1687
|
} catch (error) {
|
|
1676
1688
|
Logger.warn("[BaseMailingService] Could not validate Mailgun client:", {
|
|
@@ -1707,73 +1719,93 @@ var BaseMailingService = class {
|
|
|
1707
1719
|
from: data.from,
|
|
1708
1720
|
subject: data.subject,
|
|
1709
1721
|
hasHtml: !!data.html,
|
|
1710
|
-
hasText: !!data.text
|
|
1722
|
+
hasText: !!data.text,
|
|
1723
|
+
clientType: this.isNewMailgunClient ? "mailgun.js" : "legacy"
|
|
1711
1724
|
});
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1725
|
+
if (this.isNewMailgunClient) {
|
|
1726
|
+
try {
|
|
1727
|
+
const createMethod = this.mailgunClient.messages.create;
|
|
1728
|
+
const domain = this.getDomainFromOptions() || this.getDomainFromEmail(data.from);
|
|
1729
|
+
if (!domain) {
|
|
1730
|
+
throw new Error("Could not determine domain for Mailgun API call");
|
|
1731
|
+
}
|
|
1732
|
+
Logger.info(
|
|
1733
|
+
"[BaseMailingService] Using domain for new Mailgun client:",
|
|
1734
|
+
{ domain }
|
|
1735
|
+
);
|
|
1736
|
+
const result = await createMethod(domain, data);
|
|
1737
|
+
Logger.info(
|
|
1738
|
+
"[BaseMailingService] Email sent successfully with new client"
|
|
1739
|
+
);
|
|
1740
|
+
return result;
|
|
1741
|
+
} catch (error) {
|
|
1742
|
+
Logger.error(
|
|
1743
|
+
"[BaseMailingService] Error sending with new Mailgun client:",
|
|
1744
|
+
{
|
|
1745
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1746
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
1718
1747
|
}
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1748
|
+
);
|
|
1749
|
+
throw error;
|
|
1750
|
+
}
|
|
1751
|
+
} else {
|
|
1752
|
+
return await new Promise(
|
|
1753
|
+
(resolve, reject) => {
|
|
1754
|
+
try {
|
|
1755
|
+
const messagesApi = this.mailgunClient.messages;
|
|
1756
|
+
if (!messagesApi || !messagesApi.send) {
|
|
1757
|
+
throw new Error("Could not get Mailgun messages API");
|
|
1758
|
+
}
|
|
1759
|
+
messagesApi.send(data, (error, body) => {
|
|
1760
|
+
var _a, _b, _c;
|
|
1761
|
+
if (error) {
|
|
1762
|
+
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
1763
|
+
const clientOptions = this.mailgunClient.options || {};
|
|
1764
|
+
Logger.error(
|
|
1765
|
+
"[BaseMailingService] Mailgun authentication error - possible region mismatch:",
|
|
1766
|
+
{
|
|
1767
|
+
error: error instanceof Error ? error.message : error,
|
|
1768
|
+
statusCode: error.statusCode,
|
|
1769
|
+
domain: clientOptions.domain || "unknown",
|
|
1770
|
+
host: clientOptions.host || "default api.mailgun.net",
|
|
1771
|
+
suggestion: "If using EU region domains, ensure host is set to 'api.eu.mailgun.net'",
|
|
1772
|
+
response: error.response ? JSON.stringify(error.response) : "No response details",
|
|
1773
|
+
request: error.request ? {
|
|
1774
|
+
method: (_a = error.request) == null ? void 0 : _a.method,
|
|
1775
|
+
path: (_b = error.request) == null ? void 0 : _b.path,
|
|
1776
|
+
host: (_c = error.request) == null ? void 0 : _c.host
|
|
1777
|
+
} : "No request details"
|
|
1778
|
+
}
|
|
1779
|
+
);
|
|
1780
|
+
} else {
|
|
1781
|
+
Logger.error("[BaseMailingService] Mailgun API error:", {
|
|
1727
1782
|
error: error instanceof Error ? error.message : error,
|
|
1728
1783
|
statusCode: error.statusCode,
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
request: error.request ? {
|
|
1734
|
-
method: (_a = error.request) == null ? void 0 : _a.method,
|
|
1735
|
-
path: (_b = error.request) == null ? void 0 : _b.path,
|
|
1736
|
-
host: (_c = error.request) == null ? void 0 : _c.host
|
|
1737
|
-
} : "No request details"
|
|
1738
|
-
}
|
|
1739
|
-
);
|
|
1740
|
-
const enhancedError = new Error(
|
|
1741
|
-
`Mailgun Authentication Error (${error.statusCode}): Possible EU region misconfiguration. Set host to 'api.eu.mailgun.net' for EU domains.`
|
|
1742
|
-
);
|
|
1743
|
-
enhancedError.originalError = error;
|
|
1744
|
-
enhancedError.mailgunConfig = {
|
|
1745
|
-
domain: clientOptions.domain,
|
|
1746
|
-
host: clientOptions.host
|
|
1747
|
-
};
|
|
1748
|
-
reject(enhancedError);
|
|
1784
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
reject(error);
|
|
1749
1788
|
} else {
|
|
1750
|
-
Logger.
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1789
|
+
Logger.info(
|
|
1790
|
+
"[BaseMailingService] Email sent successfully:",
|
|
1791
|
+
body
|
|
1792
|
+
);
|
|
1793
|
+
resolve(body);
|
|
1755
1794
|
}
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
"[BaseMailingService] Error in mailgun.messages().send():",
|
|
1768
|
-
{
|
|
1769
|
-
error: sendError instanceof Error ? sendError.message : sendError,
|
|
1770
|
-
stack: sendError instanceof Error ? sendError.stack : void 0
|
|
1771
|
-
}
|
|
1772
|
-
);
|
|
1773
|
-
reject(sendError);
|
|
1795
|
+
});
|
|
1796
|
+
} catch (sendError) {
|
|
1797
|
+
Logger.error(
|
|
1798
|
+
"[BaseMailingService] Error in mailgun.messages().send():",
|
|
1799
|
+
{
|
|
1800
|
+
error: sendError instanceof Error ? sendError.message : sendError,
|
|
1801
|
+
stack: sendError instanceof Error ? sendError.stack : void 0
|
|
1802
|
+
}
|
|
1803
|
+
);
|
|
1804
|
+
reject(sendError);
|
|
1805
|
+
}
|
|
1774
1806
|
}
|
|
1775
|
-
|
|
1776
|
-
|
|
1807
|
+
);
|
|
1808
|
+
}
|
|
1777
1809
|
} catch (error) {
|
|
1778
1810
|
Logger.error("[BaseMailingService] Error in sendEmail:", {
|
|
1779
1811
|
error: error instanceof Error ? error.message : error,
|
|
@@ -1782,6 +1814,40 @@ var BaseMailingService = class {
|
|
|
1782
1814
|
throw error;
|
|
1783
1815
|
}
|
|
1784
1816
|
}
|
|
1817
|
+
/**
|
|
1818
|
+
* Tries to get domain from mailgun client options
|
|
1819
|
+
* @returns Domain string or undefined
|
|
1820
|
+
*/
|
|
1821
|
+
getDomainFromOptions() {
|
|
1822
|
+
try {
|
|
1823
|
+
if (this.isNewMailgunClient) {
|
|
1824
|
+
return this.mailgunClient.domain;
|
|
1825
|
+
} else {
|
|
1826
|
+
const options = this.mailgunClient.options;
|
|
1827
|
+
return options == null ? void 0 : options.domain;
|
|
1828
|
+
}
|
|
1829
|
+
} catch (e) {
|
|
1830
|
+
return void 0;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Extracts domain from an email address
|
|
1835
|
+
* @param email Email address
|
|
1836
|
+
* @returns Domain part or undefined
|
|
1837
|
+
*/
|
|
1838
|
+
getDomainFromEmail(email) {
|
|
1839
|
+
try {
|
|
1840
|
+
const match = email.match(/<([^>]+)>/) || [null, email];
|
|
1841
|
+
const emailPart = match[1];
|
|
1842
|
+
const domainMatch = emailPart.match(/@([^@]+)$/);
|
|
1843
|
+
if (domainMatch && domainMatch[1]) {
|
|
1844
|
+
return domainMatch[1];
|
|
1845
|
+
}
|
|
1846
|
+
return void 0;
|
|
1847
|
+
} catch (e) {
|
|
1848
|
+
return void 0;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1785
1851
|
/**
|
|
1786
1852
|
* Logs email sending attempt to Firestore for tracking
|
|
1787
1853
|
* @param emailData Email data that was sent
|
|
@@ -1948,7 +2014,7 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1948
2014
|
super(firestore8, mailgunClient);
|
|
1949
2015
|
this.DEFAULT_REGISTRATION_URL = "https://metaestetics.net/register";
|
|
1950
2016
|
this.DEFAULT_SUBJECT = "You've Been Invited to Join as a Practitioner";
|
|
1951
|
-
this.DEFAULT_FROM_ADDRESS = "MedClinic <no-reply@mg.
|
|
2017
|
+
this.DEFAULT_FROM_ADDRESS = "MedClinic <no-reply@mg.metaesthetics.net>";
|
|
1952
2018
|
}
|
|
1953
2019
|
/**
|
|
1954
2020
|
* Sends a practitioner invitation email
|
package/dist/admin/index.mjs
CHANGED
|
@@ -1599,6 +1599,7 @@ var BaseMailingService = class {
|
|
|
1599
1599
|
* @param mailgunClient Mailgun client instance provided by the caller
|
|
1600
1600
|
*/
|
|
1601
1601
|
constructor(firestore8, mailgunClient) {
|
|
1602
|
+
this.isNewMailgunClient = false;
|
|
1602
1603
|
this.db = firestore8;
|
|
1603
1604
|
this.mailgunClient = mailgunClient;
|
|
1604
1605
|
if (!this.db) {
|
|
@@ -1609,6 +1610,10 @@ var BaseMailingService = class {
|
|
|
1609
1610
|
Logger.error("[BaseMailingService] No Mailgun client provided");
|
|
1610
1611
|
throw new Error("Mailgun client is required");
|
|
1611
1612
|
}
|
|
1613
|
+
this.isNewMailgunClient = typeof this.mailgunClient.messages.create === "function";
|
|
1614
|
+
Logger.info(
|
|
1615
|
+
`[BaseMailingService] Using ${this.isNewMailgunClient ? "new" : "legacy"} Mailgun client`
|
|
1616
|
+
);
|
|
1612
1617
|
this.validateMailgunClient();
|
|
1613
1618
|
Logger.info("[BaseMailingService] Service initialized successfully");
|
|
1614
1619
|
}
|
|
@@ -1618,18 +1623,25 @@ var BaseMailingService = class {
|
|
|
1618
1623
|
*/
|
|
1619
1624
|
validateMailgunClient() {
|
|
1620
1625
|
try {
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1626
|
+
if (!this.isNewMailgunClient) {
|
|
1627
|
+
const clientOptions = this.mailgunClient.options || {};
|
|
1628
|
+
const host = clientOptions.host || "";
|
|
1629
|
+
const isEuRegion = host.includes("eu.mailgun.net");
|
|
1630
|
+
Logger.info("[BaseMailingService] Mailgun client configuration:", {
|
|
1631
|
+
host: host || "default",
|
|
1632
|
+
isEuRegion,
|
|
1633
|
+
domain: clientOptions.domain || "unknown",
|
|
1634
|
+
clientType: "legacy"
|
|
1635
|
+
});
|
|
1636
|
+
if (clientOptions.domain && clientOptions.domain.endsWith(".eu") && !isEuRegion) {
|
|
1637
|
+
Logger.warn(
|
|
1638
|
+
"[BaseMailingService] Domain appears to be in EU region but not using EU endpoint. If you're getting 401 Forbidden errors, ensure the host is set to 'api.eu.mailgun.net'"
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
} else {
|
|
1642
|
+
Logger.info("[BaseMailingService] Using new Mailgun client", {
|
|
1643
|
+
clientType: "mailgun.js"
|
|
1644
|
+
});
|
|
1633
1645
|
}
|
|
1634
1646
|
} catch (error) {
|
|
1635
1647
|
Logger.warn("[BaseMailingService] Could not validate Mailgun client:", {
|
|
@@ -1666,73 +1678,93 @@ var BaseMailingService = class {
|
|
|
1666
1678
|
from: data.from,
|
|
1667
1679
|
subject: data.subject,
|
|
1668
1680
|
hasHtml: !!data.html,
|
|
1669
|
-
hasText: !!data.text
|
|
1681
|
+
hasText: !!data.text,
|
|
1682
|
+
clientType: this.isNewMailgunClient ? "mailgun.js" : "legacy"
|
|
1670
1683
|
});
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1684
|
+
if (this.isNewMailgunClient) {
|
|
1685
|
+
try {
|
|
1686
|
+
const createMethod = this.mailgunClient.messages.create;
|
|
1687
|
+
const domain = this.getDomainFromOptions() || this.getDomainFromEmail(data.from);
|
|
1688
|
+
if (!domain) {
|
|
1689
|
+
throw new Error("Could not determine domain for Mailgun API call");
|
|
1690
|
+
}
|
|
1691
|
+
Logger.info(
|
|
1692
|
+
"[BaseMailingService] Using domain for new Mailgun client:",
|
|
1693
|
+
{ domain }
|
|
1694
|
+
);
|
|
1695
|
+
const result = await createMethod(domain, data);
|
|
1696
|
+
Logger.info(
|
|
1697
|
+
"[BaseMailingService] Email sent successfully with new client"
|
|
1698
|
+
);
|
|
1699
|
+
return result;
|
|
1700
|
+
} catch (error) {
|
|
1701
|
+
Logger.error(
|
|
1702
|
+
"[BaseMailingService] Error sending with new Mailgun client:",
|
|
1703
|
+
{
|
|
1704
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1705
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
1677
1706
|
}
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1707
|
+
);
|
|
1708
|
+
throw error;
|
|
1709
|
+
}
|
|
1710
|
+
} else {
|
|
1711
|
+
return await new Promise(
|
|
1712
|
+
(resolve, reject) => {
|
|
1713
|
+
try {
|
|
1714
|
+
const messagesApi = this.mailgunClient.messages;
|
|
1715
|
+
if (!messagesApi || !messagesApi.send) {
|
|
1716
|
+
throw new Error("Could not get Mailgun messages API");
|
|
1717
|
+
}
|
|
1718
|
+
messagesApi.send(data, (error, body) => {
|
|
1719
|
+
var _a, _b, _c;
|
|
1720
|
+
if (error) {
|
|
1721
|
+
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
1722
|
+
const clientOptions = this.mailgunClient.options || {};
|
|
1723
|
+
Logger.error(
|
|
1724
|
+
"[BaseMailingService] Mailgun authentication error - possible region mismatch:",
|
|
1725
|
+
{
|
|
1726
|
+
error: error instanceof Error ? error.message : error,
|
|
1727
|
+
statusCode: error.statusCode,
|
|
1728
|
+
domain: clientOptions.domain || "unknown",
|
|
1729
|
+
host: clientOptions.host || "default api.mailgun.net",
|
|
1730
|
+
suggestion: "If using EU region domains, ensure host is set to 'api.eu.mailgun.net'",
|
|
1731
|
+
response: error.response ? JSON.stringify(error.response) : "No response details",
|
|
1732
|
+
request: error.request ? {
|
|
1733
|
+
method: (_a = error.request) == null ? void 0 : _a.method,
|
|
1734
|
+
path: (_b = error.request) == null ? void 0 : _b.path,
|
|
1735
|
+
host: (_c = error.request) == null ? void 0 : _c.host
|
|
1736
|
+
} : "No request details"
|
|
1737
|
+
}
|
|
1738
|
+
);
|
|
1739
|
+
} else {
|
|
1740
|
+
Logger.error("[BaseMailingService] Mailgun API error:", {
|
|
1686
1741
|
error: error instanceof Error ? error.message : error,
|
|
1687
1742
|
statusCode: error.statusCode,
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
request: error.request ? {
|
|
1693
|
-
method: (_a = error.request) == null ? void 0 : _a.method,
|
|
1694
|
-
path: (_b = error.request) == null ? void 0 : _b.path,
|
|
1695
|
-
host: (_c = error.request) == null ? void 0 : _c.host
|
|
1696
|
-
} : "No request details"
|
|
1697
|
-
}
|
|
1698
|
-
);
|
|
1699
|
-
const enhancedError = new Error(
|
|
1700
|
-
`Mailgun Authentication Error (${error.statusCode}): Possible EU region misconfiguration. Set host to 'api.eu.mailgun.net' for EU domains.`
|
|
1701
|
-
);
|
|
1702
|
-
enhancedError.originalError = error;
|
|
1703
|
-
enhancedError.mailgunConfig = {
|
|
1704
|
-
domain: clientOptions.domain,
|
|
1705
|
-
host: clientOptions.host
|
|
1706
|
-
};
|
|
1707
|
-
reject(enhancedError);
|
|
1743
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
reject(error);
|
|
1708
1747
|
} else {
|
|
1709
|
-
Logger.
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1748
|
+
Logger.info(
|
|
1749
|
+
"[BaseMailingService] Email sent successfully:",
|
|
1750
|
+
body
|
|
1751
|
+
);
|
|
1752
|
+
resolve(body);
|
|
1714
1753
|
}
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
"[BaseMailingService] Error in mailgun.messages().send():",
|
|
1727
|
-
{
|
|
1728
|
-
error: sendError instanceof Error ? sendError.message : sendError,
|
|
1729
|
-
stack: sendError instanceof Error ? sendError.stack : void 0
|
|
1730
|
-
}
|
|
1731
|
-
);
|
|
1732
|
-
reject(sendError);
|
|
1754
|
+
});
|
|
1755
|
+
} catch (sendError) {
|
|
1756
|
+
Logger.error(
|
|
1757
|
+
"[BaseMailingService] Error in mailgun.messages().send():",
|
|
1758
|
+
{
|
|
1759
|
+
error: sendError instanceof Error ? sendError.message : sendError,
|
|
1760
|
+
stack: sendError instanceof Error ? sendError.stack : void 0
|
|
1761
|
+
}
|
|
1762
|
+
);
|
|
1763
|
+
reject(sendError);
|
|
1764
|
+
}
|
|
1733
1765
|
}
|
|
1734
|
-
|
|
1735
|
-
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1736
1768
|
} catch (error) {
|
|
1737
1769
|
Logger.error("[BaseMailingService] Error in sendEmail:", {
|
|
1738
1770
|
error: error instanceof Error ? error.message : error,
|
|
@@ -1741,6 +1773,40 @@ var BaseMailingService = class {
|
|
|
1741
1773
|
throw error;
|
|
1742
1774
|
}
|
|
1743
1775
|
}
|
|
1776
|
+
/**
|
|
1777
|
+
* Tries to get domain from mailgun client options
|
|
1778
|
+
* @returns Domain string or undefined
|
|
1779
|
+
*/
|
|
1780
|
+
getDomainFromOptions() {
|
|
1781
|
+
try {
|
|
1782
|
+
if (this.isNewMailgunClient) {
|
|
1783
|
+
return this.mailgunClient.domain;
|
|
1784
|
+
} else {
|
|
1785
|
+
const options = this.mailgunClient.options;
|
|
1786
|
+
return options == null ? void 0 : options.domain;
|
|
1787
|
+
}
|
|
1788
|
+
} catch (e) {
|
|
1789
|
+
return void 0;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
/**
|
|
1793
|
+
* Extracts domain from an email address
|
|
1794
|
+
* @param email Email address
|
|
1795
|
+
* @returns Domain part or undefined
|
|
1796
|
+
*/
|
|
1797
|
+
getDomainFromEmail(email) {
|
|
1798
|
+
try {
|
|
1799
|
+
const match = email.match(/<([^>]+)>/) || [null, email];
|
|
1800
|
+
const emailPart = match[1];
|
|
1801
|
+
const domainMatch = emailPart.match(/@([^@]+)$/);
|
|
1802
|
+
if (domainMatch && domainMatch[1]) {
|
|
1803
|
+
return domainMatch[1];
|
|
1804
|
+
}
|
|
1805
|
+
return void 0;
|
|
1806
|
+
} catch (e) {
|
|
1807
|
+
return void 0;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1744
1810
|
/**
|
|
1745
1811
|
* Logs email sending attempt to Firestore for tracking
|
|
1746
1812
|
* @param emailData Email data that was sent
|
|
@@ -1907,7 +1973,7 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1907
1973
|
super(firestore8, mailgunClient);
|
|
1908
1974
|
this.DEFAULT_REGISTRATION_URL = "https://metaestetics.net/register";
|
|
1909
1975
|
this.DEFAULT_SUBJECT = "You've Been Invited to Join as a Practitioner";
|
|
1910
|
-
this.DEFAULT_FROM_ADDRESS = "MedClinic <no-reply@mg.
|
|
1976
|
+
this.DEFAULT_FROM_ADDRESS = "MedClinic <no-reply@mg.metaesthetics.net>";
|
|
1911
1977
|
}
|
|
1912
1978
|
/**
|
|
1913
1979
|
* Sends a practitioner invitation email
|
package/package.json
CHANGED
|
@@ -2,12 +2,24 @@ import * as mailgun from "mailgun-js";
|
|
|
2
2
|
import * as admin from "firebase-admin";
|
|
3
3
|
import { Logger } from "../logger";
|
|
4
4
|
|
|
5
|
+
/**
|
|
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
|
|
8
|
+
*/
|
|
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
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
/**
|
|
6
17
|
* Base mailing service class that provides common functionality for all mailing services
|
|
7
18
|
*/
|
|
8
19
|
export class BaseMailingService {
|
|
9
20
|
protected db: FirebaseFirestore.Firestore;
|
|
10
|
-
protected mailgunClient: mailgun.Mailgun;
|
|
21
|
+
protected mailgunClient: mailgun.Mailgun | MailgunClientCompat;
|
|
22
|
+
protected isNewMailgunClient: boolean = false;
|
|
11
23
|
// Removed config property as it's no longer managed here
|
|
12
24
|
// import {
|
|
13
25
|
// getMailgunConfig,
|
|
@@ -22,8 +34,7 @@ export class BaseMailingService {
|
|
|
22
34
|
*/
|
|
23
35
|
constructor(
|
|
24
36
|
firestore: FirebaseFirestore.Firestore,
|
|
25
|
-
mailgunClient: mailgun.Mailgun //
|
|
26
|
-
// mailgunConfig?: MailgunConfig // Removed config parameter
|
|
37
|
+
mailgunClient: mailgun.Mailgun | MailgunClientCompat // Accept either old or new client
|
|
27
38
|
) {
|
|
28
39
|
// Use provided instances
|
|
29
40
|
this.db = firestore;
|
|
@@ -40,6 +51,15 @@ export class BaseMailingService {
|
|
|
40
51
|
throw new Error("Mailgun client is required");
|
|
41
52
|
}
|
|
42
53
|
|
|
54
|
+
// Detect which type of mailgun client we're using
|
|
55
|
+
this.isNewMailgunClient =
|
|
56
|
+
typeof (this.mailgunClient.messages as any).create === "function";
|
|
57
|
+
Logger.info(
|
|
58
|
+
`[BaseMailingService] Using ${
|
|
59
|
+
this.isNewMailgunClient ? "new" : "legacy"
|
|
60
|
+
} Mailgun client`
|
|
61
|
+
);
|
|
62
|
+
|
|
43
63
|
// Validate the Mailgun client configuration
|
|
44
64
|
this.validateMailgunClient();
|
|
45
65
|
|
|
@@ -53,27 +73,36 @@ export class BaseMailingService {
|
|
|
53
73
|
*/
|
|
54
74
|
private validateMailgunClient(): void {
|
|
55
75
|
try {
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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");
|
|
60
81
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
Logger.info("[BaseMailingService] Mailgun client configuration:", {
|
|
83
|
+
host: host || "default",
|
|
84
|
+
isEuRegion,
|
|
85
|
+
domain: clientOptions.domain || "unknown",
|
|
86
|
+
clientType: "legacy",
|
|
87
|
+
});
|
|
66
88
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
+
});
|
|
77
106
|
}
|
|
78
107
|
} catch (error) {
|
|
79
108
|
// Just log the error, don't throw
|
|
@@ -90,7 +119,7 @@ export class BaseMailingService {
|
|
|
90
119
|
*/
|
|
91
120
|
protected async sendEmail(
|
|
92
121
|
data: mailgun.messages.SendData // Caller must provide 'from'
|
|
93
|
-
): Promise<
|
|
122
|
+
): Promise<any> {
|
|
94
123
|
try {
|
|
95
124
|
// Validate email data fields
|
|
96
125
|
if (!data) {
|
|
@@ -123,84 +152,111 @@ export class BaseMailingService {
|
|
|
123
152
|
subject: data.subject,
|
|
124
153
|
hasHtml: !!data.html,
|
|
125
154
|
hasText: !!data.text,
|
|
155
|
+
clientType: this.isNewMailgunClient ? "mailgun.js" : "legacy",
|
|
126
156
|
});
|
|
127
157
|
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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,
|
|
135
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
|
+
}
|
|
136
201
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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:", {
|
|
146
231
|
error: error instanceof Error ? error.message : error,
|
|
147
232
|
statusCode: error.statusCode,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
response: (error as any).response
|
|
153
|
-
? JSON.stringify((error as any).response)
|
|
154
|
-
: "No response details",
|
|
155
|
-
request: (error as any).request
|
|
156
|
-
? {
|
|
157
|
-
method: (error as any).request?.method,
|
|
158
|
-
path: (error as any).request?.path,
|
|
159
|
-
host: (error as any).request?.host,
|
|
160
|
-
}
|
|
161
|
-
: "No request details",
|
|
162
|
-
}
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
// Provide a more specific error object
|
|
166
|
-
const enhancedError = new Error(
|
|
167
|
-
`Mailgun Authentication Error (${error.statusCode}): Possible EU region misconfiguration. Set host to 'api.eu.mailgun.net' for EU domains.`
|
|
168
|
-
);
|
|
169
|
-
(enhancedError as any).originalError = error;
|
|
170
|
-
(enhancedError as any).mailgunConfig = {
|
|
171
|
-
domain: clientOptions.domain,
|
|
172
|
-
host: clientOptions.host,
|
|
173
|
-
};
|
|
174
|
-
reject(enhancedError);
|
|
233
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
reject(error);
|
|
175
237
|
} else {
|
|
176
|
-
Logger.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
238
|
+
Logger.info(
|
|
239
|
+
"[BaseMailingService] Email sent successfully:",
|
|
240
|
+
body
|
|
241
|
+
);
|
|
242
|
+
resolve(body);
|
|
181
243
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
error:
|
|
196
|
-
sendError instanceof Error ? sendError.message : sendError,
|
|
197
|
-
stack: sendError instanceof Error ? sendError.stack : undefined,
|
|
198
|
-
}
|
|
199
|
-
);
|
|
200
|
-
reject(sendError);
|
|
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
|
+
}
|
|
201
257
|
}
|
|
202
|
-
|
|
203
|
-
|
|
258
|
+
);
|
|
259
|
+
}
|
|
204
260
|
} catch (error) {
|
|
205
261
|
Logger.error("[BaseMailingService] Error in sendEmail:", {
|
|
206
262
|
error: error instanceof Error ? error.message : error,
|
|
@@ -210,6 +266,46 @@ export class BaseMailingService {
|
|
|
210
266
|
}
|
|
211
267
|
}
|
|
212
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
|
+
}
|
|
286
|
+
|
|
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
|
+
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;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
213
309
|
/**
|
|
214
310
|
* Logs email sending attempt to Firestore for tracking
|
|
215
311
|
* @param emailData Email data that was sent
|
|
@@ -55,7 +55,7 @@ export class PractitionerInviteMailingService extends BaseMailingService {
|
|
|
55
55
|
private readonly DEFAULT_SUBJECT =
|
|
56
56
|
"You've Been Invited to Join as a Practitioner";
|
|
57
57
|
private readonly DEFAULT_FROM_ADDRESS =
|
|
58
|
-
"MedClinic <no-reply@mg.
|
|
58
|
+
"MedClinic <no-reply@mg.metaesthetics.net>";
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Constructor for PractitionerInviteMailingService
|