strapi-plugin-magic-mail 1.0.1

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.
Files changed (91) hide show
  1. package/COPYRIGHT_NOTICE.txt +13 -0
  2. package/LICENSE +22 -0
  3. package/README.md +1420 -0
  4. package/admin/jsconfig.json +10 -0
  5. package/admin/src/components/AddAccountModal.jsx +1943 -0
  6. package/admin/src/components/Initializer.jsx +14 -0
  7. package/admin/src/components/LicenseGuard.jsx +475 -0
  8. package/admin/src/components/PluginIcon.jsx +5 -0
  9. package/admin/src/hooks/useAuthRefresh.js +44 -0
  10. package/admin/src/hooks/useLicense.js +158 -0
  11. package/admin/src/index.js +86 -0
  12. package/admin/src/pages/Analytics.jsx +762 -0
  13. package/admin/src/pages/App.jsx +111 -0
  14. package/admin/src/pages/EmailDesigner/EditorPage.jsx +1405 -0
  15. package/admin/src/pages/EmailDesigner/TemplateList.jsx +1807 -0
  16. package/admin/src/pages/HomePage.jsx +1233 -0
  17. package/admin/src/pages/LicensePage.jsx +424 -0
  18. package/admin/src/pages/RoutingRules.jsx +1141 -0
  19. package/admin/src/pages/Settings.jsx +603 -0
  20. package/admin/src/pluginId.js +3 -0
  21. package/admin/src/translations/de.json +71 -0
  22. package/admin/src/translations/en.json +70 -0
  23. package/admin/src/translations/es.json +71 -0
  24. package/admin/src/translations/fr.json +71 -0
  25. package/admin/src/translations/pt.json +71 -0
  26. package/admin/src/utils/fetchWithRetry.js +123 -0
  27. package/admin/src/utils/getTranslation.js +5 -0
  28. package/dist/_chunks/App-B-Gp4Vbr.js +7568 -0
  29. package/dist/_chunks/App-BymMjoGM.mjs +7543 -0
  30. package/dist/_chunks/LicensePage-Bl02myMx.mjs +342 -0
  31. package/dist/_chunks/LicensePage-CJXwPnEe.js +344 -0
  32. package/dist/_chunks/Settings-C_TmKwcz.mjs +400 -0
  33. package/dist/_chunks/Settings-zuFQ3pnn.js +402 -0
  34. package/dist/_chunks/de-CN-G9j1S.js +64 -0
  35. package/dist/_chunks/de-DS04rP54.mjs +64 -0
  36. package/dist/_chunks/en-BDc7Jk8u.js +64 -0
  37. package/dist/_chunks/en-BEFQJXvR.mjs +64 -0
  38. package/dist/_chunks/es-BpV1MIdm.js +64 -0
  39. package/dist/_chunks/es-DQHwzPpP.mjs +64 -0
  40. package/dist/_chunks/fr-BG1WfEVm.mjs +64 -0
  41. package/dist/_chunks/fr-vpziIpRp.js +64 -0
  42. package/dist/_chunks/pt-CMoGrOib.mjs +64 -0
  43. package/dist/_chunks/pt-ODpAhDNa.js +64 -0
  44. package/dist/admin/index.js +89 -0
  45. package/dist/admin/index.mjs +90 -0
  46. package/dist/server/index.js +6214 -0
  47. package/dist/server/index.mjs +6208 -0
  48. package/package.json +113 -0
  49. package/server/jsconfig.json +10 -0
  50. package/server/src/bootstrap.js +153 -0
  51. package/server/src/config/features.js +260 -0
  52. package/server/src/config/index.js +6 -0
  53. package/server/src/content-types/email-account/schema.json +93 -0
  54. package/server/src/content-types/email-event/index.js +8 -0
  55. package/server/src/content-types/email-event/schema.json +57 -0
  56. package/server/src/content-types/email-link/index.js +8 -0
  57. package/server/src/content-types/email-link/schema.json +49 -0
  58. package/server/src/content-types/email-log/index.js +8 -0
  59. package/server/src/content-types/email-log/schema.json +106 -0
  60. package/server/src/content-types/email-template/schema.json +74 -0
  61. package/server/src/content-types/email-template-version/schema.json +60 -0
  62. package/server/src/content-types/index.js +33 -0
  63. package/server/src/content-types/routing-rule/schema.json +59 -0
  64. package/server/src/controllers/accounts.js +220 -0
  65. package/server/src/controllers/analytics.js +347 -0
  66. package/server/src/controllers/controller.js +26 -0
  67. package/server/src/controllers/email-designer.js +474 -0
  68. package/server/src/controllers/index.js +21 -0
  69. package/server/src/controllers/license.js +267 -0
  70. package/server/src/controllers/oauth.js +474 -0
  71. package/server/src/controllers/routing-rules.js +122 -0
  72. package/server/src/controllers/test.js +383 -0
  73. package/server/src/destroy.js +23 -0
  74. package/server/src/index.js +25 -0
  75. package/server/src/middlewares/index.js +3 -0
  76. package/server/src/policies/index.js +3 -0
  77. package/server/src/register.js +5 -0
  78. package/server/src/routes/admin.js +469 -0
  79. package/server/src/routes/content-api.js +37 -0
  80. package/server/src/routes/index.js +9 -0
  81. package/server/src/services/account-manager.js +277 -0
  82. package/server/src/services/analytics.js +496 -0
  83. package/server/src/services/email-designer.js +870 -0
  84. package/server/src/services/email-router.js +1420 -0
  85. package/server/src/services/index.js +17 -0
  86. package/server/src/services/license-guard.js +418 -0
  87. package/server/src/services/oauth.js +515 -0
  88. package/server/src/services/service.js +7 -0
  89. package/server/src/utils/encryption.js +81 -0
  90. package/strapi-admin.js +4 -0
  91. package/strapi-server.js +4 -0
@@ -0,0 +1,57 @@
1
+ {
2
+ "kind": "collectionType",
3
+ "collectionName": "magic_mail_email_events",
4
+ "info": {
5
+ "singularName": "email-event",
6
+ "pluralName": "email-events",
7
+ "displayName": "Email Event",
8
+ "description": "Individual email tracking events (opens, clicks, bounces)"
9
+ },
10
+ "options": {
11
+ "draftAndPublish": false
12
+ },
13
+ "pluginOptions": {
14
+ "content-manager": {
15
+ "visible": false
16
+ },
17
+ "content-type-builder": {
18
+ "visible": false
19
+ }
20
+ },
21
+ "attributes": {
22
+ "emailLog": {
23
+ "type": "relation",
24
+ "relation": "manyToOne",
25
+ "target": "plugin::magic-mail.email-log",
26
+ "inversedBy": "events"
27
+ },
28
+ "type": {
29
+ "type": "enumeration",
30
+ "enum": ["open", "click", "bounce", "complaint", "unsubscribe"],
31
+ "required": true
32
+ },
33
+ "timestamp": {
34
+ "type": "datetime",
35
+ "required": true
36
+ },
37
+ "ipAddress": {
38
+ "type": "string"
39
+ },
40
+ "userAgent": {
41
+ "type": "text"
42
+ },
43
+ "location": {
44
+ "type": "json"
45
+ },
46
+ "linkUrl": {
47
+ "type": "text"
48
+ },
49
+ "linkText": {
50
+ "type": "string"
51
+ },
52
+ "metadata": {
53
+ "type": "json"
54
+ }
55
+ }
56
+ }
57
+
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ const schema = require('./schema.json');
4
+
5
+ module.exports = {
6
+ schema,
7
+ };
8
+
@@ -0,0 +1,49 @@
1
+ {
2
+ "kind": "collectionType",
3
+ "collectionName": "magic_mail_email_links",
4
+ "info": {
5
+ "singularName": "email-link",
6
+ "pluralName": "email-links",
7
+ "displayName": "Email Link",
8
+ "description": "Stores click tracking links for emails"
9
+ },
10
+ "options": {
11
+ "draftAndPublish": false
12
+ },
13
+ "pluginOptions": {
14
+ "content-manager": {
15
+ "visible": false
16
+ },
17
+ "content-type-builder": {
18
+ "visible": false
19
+ }
20
+ },
21
+ "attributes": {
22
+ "emailLog": {
23
+ "type": "relation",
24
+ "relation": "manyToOne",
25
+ "target": "plugin::magic-mail.email-log",
26
+ "inversedBy": "links"
27
+ },
28
+ "linkHash": {
29
+ "type": "string",
30
+ "required": true,
31
+ "unique": false
32
+ },
33
+ "originalUrl": {
34
+ "type": "text",
35
+ "required": true
36
+ },
37
+ "clickCount": {
38
+ "type": "integer",
39
+ "default": 0
40
+ },
41
+ "firstClickedAt": {
42
+ "type": "datetime"
43
+ },
44
+ "lastClickedAt": {
45
+ "type": "datetime"
46
+ }
47
+ }
48
+ }
49
+
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ const schema = require('./schema.json');
4
+
5
+ module.exports = {
6
+ schema,
7
+ };
8
+
@@ -0,0 +1,106 @@
1
+ {
2
+ "kind": "collectionType",
3
+ "collectionName": "magic_mail_email_logs",
4
+ "info": {
5
+ "singularName": "email-log",
6
+ "pluralName": "email-logs",
7
+ "displayName": "Email Log",
8
+ "description": "Tracks all sent emails with user association"
9
+ },
10
+ "options": {
11
+ "draftAndPublish": false
12
+ },
13
+ "pluginOptions": {
14
+ "content-manager": {
15
+ "visible": false
16
+ },
17
+ "content-type-builder": {
18
+ "visible": false
19
+ }
20
+ },
21
+ "attributes": {
22
+ "emailId": {
23
+ "type": "string",
24
+ "required": true,
25
+ "unique": true
26
+ },
27
+ "user": {
28
+ "type": "relation",
29
+ "relation": "manyToOne",
30
+ "target": "plugin::users-permissions.user"
31
+ },
32
+ "recipient": {
33
+ "type": "email",
34
+ "required": true
35
+ },
36
+ "recipientName": {
37
+ "type": "string"
38
+ },
39
+ "subject": {
40
+ "type": "string",
41
+ "required": true
42
+ },
43
+ "templateId": {
44
+ "type": "integer"
45
+ },
46
+ "templateName": {
47
+ "type": "string"
48
+ },
49
+ "accountId": {
50
+ "type": "integer"
51
+ },
52
+ "accountName": {
53
+ "type": "string"
54
+ },
55
+ "sentAt": {
56
+ "type": "datetime",
57
+ "required": true
58
+ },
59
+ "deliveredAt": {
60
+ "type": "datetime"
61
+ },
62
+ "firstOpenedAt": {
63
+ "type": "datetime"
64
+ },
65
+ "lastOpenedAt": {
66
+ "type": "datetime"
67
+ },
68
+ "openCount": {
69
+ "type": "integer",
70
+ "default": 0
71
+ },
72
+ "clickCount": {
73
+ "type": "integer",
74
+ "default": 0
75
+ },
76
+ "bounced": {
77
+ "type": "boolean",
78
+ "default": false
79
+ },
80
+ "bounceReason": {
81
+ "type": "text"
82
+ },
83
+ "unsubscribed": {
84
+ "type": "boolean",
85
+ "default": false
86
+ },
87
+ "unsubscribedAt": {
88
+ "type": "datetime"
89
+ },
90
+ "metadata": {
91
+ "type": "json"
92
+ },
93
+ "events": {
94
+ "type": "relation",
95
+ "relation": "oneToMany",
96
+ "target": "plugin::magic-mail.email-event",
97
+ "mappedBy": "emailLog"
98
+ },
99
+ "links": {
100
+ "type": "relation",
101
+ "relation": "oneToMany",
102
+ "target": "plugin::magic-mail.email-link",
103
+ "mappedBy": "emailLog"
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "kind": "collectionType",
3
+ "collectionName": "magic_mail_email_templates",
4
+ "info": {
5
+ "singularName": "email-template",
6
+ "pluralName": "email-templates",
7
+ "displayName": "Email Template",
8
+ "description": "Email templates created with the visual designer"
9
+ },
10
+ "options": {
11
+ "draftAndPublish": false,
12
+ "timestamps": true
13
+ },
14
+ "pluginOptions": {
15
+ "content-manager": {
16
+ "visible": false
17
+ },
18
+ "content-type-builder": {
19
+ "visible": false
20
+ }
21
+ },
22
+ "attributes": {
23
+ "templateReferenceId": {
24
+ "type": "integer",
25
+ "required": true,
26
+ "unique": true,
27
+ "configurable": false
28
+ },
29
+ "name": {
30
+ "type": "string",
31
+ "required": true,
32
+ "configurable": false
33
+ },
34
+ "subject": {
35
+ "type": "string",
36
+ "required": true,
37
+ "configurable": false
38
+ },
39
+ "design": {
40
+ "type": "json",
41
+ "configurable": false
42
+ },
43
+ "bodyHtml": {
44
+ "type": "text",
45
+ "configurable": false
46
+ },
47
+ "bodyText": {
48
+ "type": "text",
49
+ "configurable": false
50
+ },
51
+ "category": {
52
+ "type": "enumeration",
53
+ "enum": ["transactional", "marketing", "notification", "custom"],
54
+ "default": "custom",
55
+ "configurable": false
56
+ },
57
+ "isActive": {
58
+ "type": "boolean",
59
+ "default": true,
60
+ "configurable": false
61
+ },
62
+ "tags": {
63
+ "type": "json",
64
+ "configurable": false
65
+ },
66
+ "versions": {
67
+ "type": "relation",
68
+ "relation": "oneToMany",
69
+ "target": "plugin::magic-mail.email-template-version",
70
+ "mappedBy": "template"
71
+ }
72
+ }
73
+ }
74
+
@@ -0,0 +1,60 @@
1
+ {
2
+ "kind": "collectionType",
3
+ "collectionName": "magic_mail_email_template_versions",
4
+ "info": {
5
+ "singularName": "email-template-version",
6
+ "pluralName": "email-template-versions",
7
+ "displayName": "Email Template Version",
8
+ "description": "Version history for email templates"
9
+ },
10
+ "options": {
11
+ "draftAndPublish": false,
12
+ "timestamps": true
13
+ },
14
+ "pluginOptions": {
15
+ "content-manager": {
16
+ "visible": false
17
+ },
18
+ "content-type-builder": {
19
+ "visible": false
20
+ }
21
+ },
22
+ "attributes": {
23
+ "template": {
24
+ "type": "relation",
25
+ "relation": "manyToOne",
26
+ "target": "plugin::magic-mail.email-template",
27
+ "inversedBy": "versions"
28
+ },
29
+ "versionNumber": {
30
+ "type": "integer",
31
+ "required": true,
32
+ "configurable": false
33
+ },
34
+ "name": {
35
+ "type": "string",
36
+ "configurable": false
37
+ },
38
+ "subject": {
39
+ "type": "string",
40
+ "configurable": false
41
+ },
42
+ "design": {
43
+ "type": "json",
44
+ "configurable": false
45
+ },
46
+ "bodyHtml": {
47
+ "type": "text",
48
+ "configurable": false
49
+ },
50
+ "bodyText": {
51
+ "type": "text",
52
+ "configurable": false
53
+ },
54
+ "tags": {
55
+ "type": "json",
56
+ "configurable": false
57
+ }
58
+ }
59
+ }
60
+
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ const emailAccount = require('./email-account/schema.json');
4
+ const routingRule = require('./routing-rule/schema.json');
5
+ const emailLog = require('./email-log/schema.json');
6
+ const emailEvent = require('./email-event/schema.json');
7
+ const emailLink = require('./email-link/schema.json');
8
+ const emailTemplate = require('./email-template/schema.json');
9
+ const emailTemplateVersion = require('./email-template-version/schema.json');
10
+
11
+ module.exports = {
12
+ 'email-account': {
13
+ schema: emailAccount,
14
+ },
15
+ 'routing-rule': {
16
+ schema: routingRule,
17
+ },
18
+ 'email-log': {
19
+ schema: emailLog,
20
+ },
21
+ 'email-event': {
22
+ schema: emailEvent,
23
+ },
24
+ 'email-link': {
25
+ schema: emailLink,
26
+ },
27
+ 'email-template': {
28
+ schema: emailTemplate,
29
+ },
30
+ 'email-template-version': {
31
+ schema: emailTemplateVersion,
32
+ },
33
+ };
@@ -0,0 +1,59 @@
1
+ {
2
+ "kind": "collectionType",
3
+ "collectionName": "magic_mail_routing_rules",
4
+ "info": {
5
+ "singularName": "routing-rule",
6
+ "pluralName": "routing-rules",
7
+ "displayName": "Email Routing Rule",
8
+ "description": "Rules for routing emails to specific accounts"
9
+ },
10
+ "options": {
11
+ "draftAndPublish": false
12
+ },
13
+ "pluginOptions": {
14
+ "content-manager": {
15
+ "visible": false
16
+ },
17
+ "content-type-builder": {
18
+ "visible": false
19
+ }
20
+ },
21
+ "attributes": {
22
+ "name": {
23
+ "type": "string",
24
+ "required": true,
25
+ "unique": true
26
+ },
27
+ "description": {
28
+ "type": "text"
29
+ },
30
+ "isActive": {
31
+ "type": "boolean",
32
+ "default": true,
33
+ "required": true
34
+ },
35
+ "priority": {
36
+ "type": "integer",
37
+ "default": 1,
38
+ "min": 1
39
+ },
40
+ "matchType": {
41
+ "type": "enumeration",
42
+ "enum": ["emailType", "subject", "recipient", "template", "custom"],
43
+ "required": true,
44
+ "default": "emailType"
45
+ },
46
+ "matchValue": {
47
+ "type": "text",
48
+ "required": true
49
+ },
50
+ "accountName": {
51
+ "type": "string",
52
+ "required": true
53
+ },
54
+ "fallbackAccountName": {
55
+ "type": "string"
56
+ }
57
+ }
58
+ }
59
+
@@ -0,0 +1,220 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Accounts Controller
5
+ * Manages email accounts CRUD operations
6
+ */
7
+
8
+ module.exports = {
9
+ /**
10
+ * Get all email accounts
11
+ */
12
+ async getAll(ctx) {
13
+ try {
14
+ const accountManager = strapi.plugin('magic-mail').service('account-manager');
15
+ const accounts = await accountManager.getAllAccounts();
16
+
17
+ ctx.body = {
18
+ data: accounts,
19
+ meta: { count: accounts.length },
20
+ };
21
+ } catch (err) {
22
+ strapi.log.error('[magic-mail] Error getting accounts:', err);
23
+ ctx.throw(500, 'Error fetching email accounts');
24
+ }
25
+ },
26
+
27
+ /**
28
+ * Create new email account
29
+ */
30
+ async create(ctx) {
31
+ try {
32
+ const licenseGuard = strapi.plugin('magic-mail').service('license-guard');
33
+ const accountData = ctx.request.body;
34
+
35
+ // Check if provider is allowed by license
36
+ const providerAllowed = await licenseGuard.isProviderAllowed(accountData.provider);
37
+ if (!providerAllowed) {
38
+ ctx.throw(403, `Provider "${accountData.provider}" requires a Premium license or higher. Please upgrade your license.`);
39
+ return;
40
+ }
41
+
42
+ // Check account limit
43
+ const currentAccounts = await strapi.entityService.count('plugin::magic-mail.email-account');
44
+ const maxAccounts = await licenseGuard.getMaxAccounts();
45
+
46
+ if (maxAccounts !== -1 && currentAccounts >= maxAccounts) {
47
+ ctx.throw(403, `Account limit reached (${maxAccounts}). Upgrade your license to add more accounts.`);
48
+ return;
49
+ }
50
+
51
+ const accountManager = strapi.plugin('magic-mail').service('account-manager');
52
+ const account = await accountManager.createAccount(accountData);
53
+
54
+ ctx.body = {
55
+ data: account,
56
+ message: 'Email account created successfully',
57
+ };
58
+ } catch (err) {
59
+ strapi.log.error('[magic-mail] Error creating account:', err);
60
+ ctx.throw(err.status || 500, err.message || 'Error creating email account');
61
+ }
62
+ },
63
+
64
+ /**
65
+ * Get single account with decrypted config (for editing)
66
+ */
67
+ async getOne(ctx) {
68
+ try {
69
+ const { accountId } = ctx.params;
70
+ const accountManager = strapi.plugin('magic-mail').service('account-manager');
71
+ const account = await accountManager.getAccountWithDecryptedConfig(accountId);
72
+
73
+ ctx.body = {
74
+ data: account,
75
+ };
76
+ } catch (err) {
77
+ strapi.log.error('[magic-mail] Error getting account:', err);
78
+ ctx.throw(500, 'Error fetching email account');
79
+ }
80
+ },
81
+
82
+ /**
83
+ * Update email account
84
+ */
85
+ async update(ctx) {
86
+ try {
87
+ const { accountId } = ctx.params;
88
+ const accountManager = strapi.plugin('magic-mail').service('account-manager');
89
+ const account = await accountManager.updateAccount(accountId, ctx.request.body);
90
+
91
+ ctx.body = {
92
+ data: account,
93
+ message: 'Email account updated successfully',
94
+ };
95
+ } catch (err) {
96
+ strapi.log.error('[magic-mail] Error updating account:', err);
97
+ ctx.throw(500, err.message || 'Error updating email account');
98
+ }
99
+ },
100
+
101
+ /**
102
+ * Test email account
103
+ */
104
+ async test(ctx) {
105
+ try {
106
+ const { accountId } = ctx.params;
107
+ const { testEmail, priority, type, unsubscribeUrl } = ctx.request.body;
108
+
109
+ const testOptions = {
110
+ priority: priority || 'normal',
111
+ type: type || 'transactional',
112
+ unsubscribeUrl: unsubscribeUrl || null,
113
+ };
114
+
115
+ const accountManager = strapi.plugin('magic-mail').service('account-manager');
116
+ const result = await accountManager.testAccount(accountId, testEmail, testOptions);
117
+
118
+ ctx.body = result;
119
+ } catch (err) {
120
+ strapi.log.error('[magic-mail] Error testing account:', err);
121
+ ctx.throw(500, 'Error testing email account');
122
+ }
123
+ },
124
+
125
+ /**
126
+ * Test Strapi Email Service Integration
127
+ * Tests if MagicMail intercepts native Strapi email service
128
+ */
129
+ async testStrapiService(ctx) {
130
+ try {
131
+ const { testEmail, accountName } = ctx.request.body;
132
+
133
+ if (!testEmail) {
134
+ ctx.throw(400, 'testEmail is required');
135
+ }
136
+
137
+ strapi.log.info('[magic-mail] ๐Ÿงช Testing Strapi Email Service integration...');
138
+ strapi.log.info('[magic-mail] ๐Ÿ“ง Calling strapi.plugin("email").service("email").send()');
139
+ if (accountName) {
140
+ strapi.log.info(`[magic-mail] ๐ŸŽฏ Forcing specific account: ${accountName}`);
141
+ }
142
+
143
+ // Call native Strapi email service - should be intercepted by MagicMail!
144
+ const result = await strapi.plugin('email').service('email').send({
145
+ to: testEmail,
146
+ from: 'test@magicmail.com',
147
+ subject: 'MagicMail Integration Test',
148
+ text: 'This email was sent using Strapi\'s native email service but routed through MagicMail!',
149
+ html: `
150
+ <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
151
+ <h1 style="color: #0EA5E9;">MagicMail Integration Test</h1>
152
+ <p style="font-size: 16px; color: #374151;">
153
+ This email was sent using <strong>Strapi's native email service</strong>
154
+ but <strong>routed through MagicMail's smart routing</strong>!
155
+ </p>
156
+ <div style="background: #F0F9FF; border-left: 4px solid #0EA5E9; padding: 15px; margin: 20px 0;">
157
+ <h3 style="margin-top: 0; color: #0369A1;">Integration Working</h3>
158
+ <p style="margin: 0;">
159
+ MagicMail successfully intercepted the email and applied:
160
+ </p>
161
+ <ul style="margin: 10px 0;">
162
+ <li>Smart routing rules</li>
163
+ <li>Account selection (${accountName ? 'Forced: ' + accountName : 'Primary or by routing rules'})</li>
164
+ <li>Rate limiting</li>
165
+ <li>Email logging</li>
166
+ <li>Statistics tracking</li>
167
+ </ul>
168
+ </div>
169
+ <p style="color: #6B7280; font-size: 14px; margin-top: 30px;">
170
+ Sent at: ${new Date().toLocaleString()}<br>
171
+ Via: MagicMail Email Router
172
+ </p>
173
+ </div>
174
+ `,
175
+ type: 'transactional',
176
+ accountName: accountName || null, // Force specific account if provided
177
+ });
178
+
179
+ strapi.log.info('[magic-mail] โœ… Strapi Email Service test completed');
180
+
181
+ ctx.body = {
182
+ success: true,
183
+ message: 'Email sent via Strapi Email Service (intercepted by MagicMail)',
184
+ result,
185
+ info: {
186
+ method: 'strapi.plugin("email").service("email").send()',
187
+ intercepted: true,
188
+ routedThrough: 'MagicMail',
189
+ },
190
+ };
191
+ } catch (err) {
192
+ strapi.log.error('[magic-mail] โŒ Strapi Email Service test failed:', err);
193
+ ctx.body = {
194
+ success: false,
195
+ message: 'Failed to send test email',
196
+ error: err.message,
197
+ };
198
+ ctx.status = 500;
199
+ }
200
+ },
201
+
202
+ /**
203
+ * Delete email account
204
+ */
205
+ async delete(ctx) {
206
+ try {
207
+ const { accountId } = ctx.params;
208
+ const accountManager = strapi.plugin('magic-mail').service('account-manager');
209
+ await accountManager.deleteAccount(accountId);
210
+
211
+ ctx.body = {
212
+ message: 'Email account deleted successfully',
213
+ };
214
+ } catch (err) {
215
+ strapi.log.error('[magic-mail] Error deleting account:', err);
216
+ ctx.throw(500, 'Error deleting email account');
217
+ }
218
+ },
219
+ };
220
+