@serve.zone/dcrouter 2.12.4

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 (737) hide show
  1. package/.dockerignore +1 -0
  2. package/.gitea/workflows/docker_nottags.yaml +71 -0
  3. package/.gitea/workflows/docker_tags.yaml +106 -0
  4. package/.vscode/launch.json +11 -0
  5. package/.vscode/settings.json +26 -0
  6. package/Dockerfile +46 -0
  7. package/changelog.md +247 -0
  8. package/cli.child.js +4 -0
  9. package/cli.child.ts +4 -0
  10. package/cli.js +4 -0
  11. package/cli.ts.js +5 -0
  12. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  13. package/dist_ts/00_commitinfo_data.js +9 -0
  14. package/dist_ts/classes.dcrouter.d.ts +238 -0
  15. package/dist_ts/classes.dcrouter.js +1008 -0
  16. package/dist_ts/config/index.d.ts +1 -0
  17. package/dist_ts/config/index.js +3 -0
  18. package/dist_ts/config/validator.d.ts +104 -0
  19. package/dist_ts/config/validator.js +152 -0
  20. package/dist_ts/deliverability/classes.ipwarmupmanager.d.ts +253 -0
  21. package/dist_ts/deliverability/classes.ipwarmupmanager.js +639 -0
  22. package/dist_ts/deliverability/classes.senderreputationmonitor.d.ts +300 -0
  23. package/dist_ts/deliverability/classes.senderreputationmonitor.js +961 -0
  24. package/dist_ts/deliverability/index.d.ts +2 -0
  25. package/dist_ts/deliverability/index.js +3 -0
  26. package/dist_ts/errors/base.errors.d.ts +224 -0
  27. package/dist_ts/errors/base.errors.js +310 -0
  28. package/dist_ts/errors/email.errors.d.ts +175 -0
  29. package/dist_ts/errors/email.errors.js +265 -0
  30. package/dist_ts/errors/error-handler.d.ts +98 -0
  31. package/dist_ts/errors/error-handler.js +282 -0
  32. package/dist_ts/errors/error.codes.d.ts +115 -0
  33. package/dist_ts/errors/error.codes.js +136 -0
  34. package/dist_ts/errors/index.d.ts +56 -0
  35. package/dist_ts/errors/index.js +138 -0
  36. package/dist_ts/errors/mta.errors.d.ts +259 -0
  37. package/dist_ts/errors/mta.errors.js +472 -0
  38. package/dist_ts/errors/reputation.errors.d.ts +183 -0
  39. package/dist_ts/errors/reputation.errors.js +292 -0
  40. package/dist_ts/index.d.ts +4 -0
  41. package/dist_ts/index.js +6 -0
  42. package/dist_ts/logger.d.ts +17 -0
  43. package/dist_ts/logger.js +77 -0
  44. package/dist_ts/mail/core/classes.bouncemanager.d.ts +200 -0
  45. package/dist_ts/mail/core/classes.bouncemanager.js +778 -0
  46. package/dist_ts/mail/core/classes.email.d.ts +291 -0
  47. package/dist_ts/mail/core/classes.email.js +780 -0
  48. package/dist_ts/mail/core/classes.emailvalidator.d.ts +61 -0
  49. package/dist_ts/mail/core/classes.emailvalidator.js +182 -0
  50. package/dist_ts/mail/core/classes.templatemanager.d.ts +95 -0
  51. package/dist_ts/mail/core/classes.templatemanager.js +239 -0
  52. package/dist_ts/mail/core/index.d.ts +4 -0
  53. package/dist_ts/mail/core/index.js +6 -0
  54. package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
  55. package/dist_ts/mail/delivery/classes.delivery.queue.js +485 -0
  56. package/dist_ts/mail/delivery/classes.delivery.system.d.ts +186 -0
  57. package/dist_ts/mail/delivery/classes.delivery.system.js +846 -0
  58. package/dist_ts/mail/delivery/classes.emailsendjob.d.ts +84 -0
  59. package/dist_ts/mail/delivery/classes.emailsendjob.js +362 -0
  60. package/dist_ts/mail/delivery/classes.emailsignjob.d.ts +18 -0
  61. package/dist_ts/mail/delivery/classes.emailsignjob.js +44 -0
  62. package/dist_ts/mail/delivery/classes.mta.config.d.ts +22 -0
  63. package/dist_ts/mail/delivery/classes.mta.config.js +51 -0
  64. package/dist_ts/mail/delivery/classes.ratelimiter.d.ts +98 -0
  65. package/dist_ts/mail/delivery/classes.ratelimiter.js +205 -0
  66. package/dist_ts/mail/delivery/classes.smtp.client.legacy.d.ts +275 -0
  67. package/dist_ts/mail/delivery/classes.smtp.client.legacy.js +973 -0
  68. package/dist_ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
  69. package/dist_ts/mail/delivery/classes.unified.rate.limiter.js +817 -0
  70. package/dist_ts/mail/delivery/index.d.ts +12 -0
  71. package/dist_ts/mail/delivery/index.js +18 -0
  72. package/dist_ts/mail/delivery/interfaces.d.ts +243 -0
  73. package/dist_ts/mail/delivery/interfaces.js +17 -0
  74. package/dist_ts/mail/delivery/smtpclient/auth-handler.d.ts +43 -0
  75. package/dist_ts/mail/delivery/smtpclient/auth-handler.js +188 -0
  76. package/dist_ts/mail/delivery/smtpclient/command-handler.d.ts +67 -0
  77. package/dist_ts/mail/delivery/smtpclient/command-handler.js +276 -0
  78. package/dist_ts/mail/delivery/smtpclient/connection-manager.d.ts +48 -0
  79. package/dist_ts/mail/delivery/smtpclient/connection-manager.js +238 -0
  80. package/dist_ts/mail/delivery/smtpclient/constants.d.ts +129 -0
  81. package/dist_ts/mail/delivery/smtpclient/constants.js +135 -0
  82. package/dist_ts/mail/delivery/smtpclient/create-client.d.ts +22 -0
  83. package/dist_ts/mail/delivery/smtpclient/create-client.js +86 -0
  84. package/dist_ts/mail/delivery/smtpclient/error-handler.d.ts +28 -0
  85. package/dist_ts/mail/delivery/smtpclient/error-handler.js +110 -0
  86. package/dist_ts/mail/delivery/smtpclient/index.d.ts +16 -0
  87. package/dist_ts/mail/delivery/smtpclient/index.js +21 -0
  88. package/dist_ts/mail/delivery/smtpclient/interfaces.d.ts +183 -0
  89. package/dist_ts/mail/delivery/smtpclient/interfaces.js +19 -0
  90. package/dist_ts/mail/delivery/smtpclient/smtp-client.d.ts +58 -0
  91. package/dist_ts/mail/delivery/smtpclient/smtp-client.js +279 -0
  92. package/dist_ts/mail/delivery/smtpclient/tls-handler.d.ts +33 -0
  93. package/dist_ts/mail/delivery/smtpclient/tls-handler.js +202 -0
  94. package/dist_ts/mail/delivery/smtpclient/utils/helpers.d.ts +77 -0
  95. package/dist_ts/mail/delivery/smtpclient/utils/helpers.js +196 -0
  96. package/dist_ts/mail/delivery/smtpclient/utils/logging.d.ts +46 -0
  97. package/dist_ts/mail/delivery/smtpclient/utils/logging.js +153 -0
  98. package/dist_ts/mail/delivery/smtpclient/utils/validation.d.ts +38 -0
  99. package/dist_ts/mail/delivery/smtpclient/utils/validation.js +139 -0
  100. package/dist_ts/mail/delivery/smtpserver/certificate-utils.d.ts +45 -0
  101. package/dist_ts/mail/delivery/smtpserver/certificate-utils.js +345 -0
  102. package/dist_ts/mail/delivery/smtpserver/command-handler.d.ts +156 -0
  103. package/dist_ts/mail/delivery/smtpserver/command-handler.js +1159 -0
  104. package/dist_ts/mail/delivery/smtpserver/connection-manager.d.ts +159 -0
  105. package/dist_ts/mail/delivery/smtpserver/connection-manager.js +894 -0
  106. package/dist_ts/mail/delivery/smtpserver/constants.d.ts +130 -0
  107. package/dist_ts/mail/delivery/smtpserver/constants.js +162 -0
  108. package/dist_ts/mail/delivery/smtpserver/create-server.d.ts +14 -0
  109. package/dist_ts/mail/delivery/smtpserver/create-server.js +28 -0
  110. package/dist_ts/mail/delivery/smtpserver/data-handler.d.ts +123 -0
  111. package/dist_ts/mail/delivery/smtpserver/data-handler.js +1148 -0
  112. package/dist_ts/mail/delivery/smtpserver/index.d.ts +20 -0
  113. package/dist_ts/mail/delivery/smtpserver/index.js +27 -0
  114. package/dist_ts/mail/delivery/smtpserver/interfaces.d.ts +530 -0
  115. package/dist_ts/mail/delivery/smtpserver/interfaces.js +10 -0
  116. package/dist_ts/mail/delivery/smtpserver/secure-server.d.ts +15 -0
  117. package/dist_ts/mail/delivery/smtpserver/secure-server.js +79 -0
  118. package/dist_ts/mail/delivery/smtpserver/security-handler.d.ts +86 -0
  119. package/dist_ts/mail/delivery/smtpserver/security-handler.js +234 -0
  120. package/dist_ts/mail/delivery/smtpserver/session-manager.d.ts +140 -0
  121. package/dist_ts/mail/delivery/smtpserver/session-manager.js +469 -0
  122. package/dist_ts/mail/delivery/smtpserver/smtp-server.d.ts +137 -0
  123. package/dist_ts/mail/delivery/smtpserver/smtp-server.js +666 -0
  124. package/dist_ts/mail/delivery/smtpserver/starttls-handler.d.ts +21 -0
  125. package/dist_ts/mail/delivery/smtpserver/starttls-handler.js +207 -0
  126. package/dist_ts/mail/delivery/smtpserver/tls-handler.d.ts +66 -0
  127. package/dist_ts/mail/delivery/smtpserver/tls-handler.js +261 -0
  128. package/dist_ts/mail/delivery/smtpserver/utils/adaptive-logging.d.ts +117 -0
  129. package/dist_ts/mail/delivery/smtpserver/utils/adaptive-logging.js +411 -0
  130. package/dist_ts/mail/delivery/smtpserver/utils/helpers.d.ts +78 -0
  131. package/dist_ts/mail/delivery/smtpserver/utils/helpers.js +208 -0
  132. package/dist_ts/mail/delivery/smtpserver/utils/logging.d.ts +106 -0
  133. package/dist_ts/mail/delivery/smtpserver/utils/logging.js +181 -0
  134. package/dist_ts/mail/delivery/smtpserver/utils/validation.d.ts +69 -0
  135. package/dist_ts/mail/delivery/smtpserver/utils/validation.js +360 -0
  136. package/dist_ts/mail/index.d.ts +8 -0
  137. package/dist_ts/mail/index.js +13 -0
  138. package/dist_ts/mail/routing/classes.dns.manager.d.ts +65 -0
  139. package/dist_ts/mail/routing/classes.dns.manager.js +413 -0
  140. package/dist_ts/mail/routing/classes.dnsmanager.d.ts +165 -0
  141. package/dist_ts/mail/routing/classes.dnsmanager.js +430 -0
  142. package/dist_ts/mail/routing/classes.domain.registry.d.ts +54 -0
  143. package/dist_ts/mail/routing/classes.domain.registry.js +118 -0
  144. package/dist_ts/mail/routing/classes.email.config.d.ts +64 -0
  145. package/dist_ts/mail/routing/classes.email.config.js +2 -0
  146. package/dist_ts/mail/routing/classes.email.router.d.ts +171 -0
  147. package/dist_ts/mail/routing/classes.email.router.js +491 -0
  148. package/dist_ts/mail/routing/classes.unified.email.server.d.ts +426 -0
  149. package/dist_ts/mail/routing/classes.unified.email.server.js +1454 -0
  150. package/dist_ts/mail/routing/index.d.ts +5 -0
  151. package/dist_ts/mail/routing/index.js +7 -0
  152. package/dist_ts/mail/routing/interfaces.d.ts +187 -0
  153. package/dist_ts/mail/routing/interfaces.js +2 -0
  154. package/dist_ts/mail/security/classes.dkimcreator.d.ts +68 -0
  155. package/dist_ts/mail/security/classes.dkimcreator.js +346 -0
  156. package/dist_ts/mail/security/classes.dkimverifier.d.ts +46 -0
  157. package/dist_ts/mail/security/classes.dkimverifier.js +317 -0
  158. package/dist_ts/mail/security/classes.dmarcverifier.d.ts +123 -0
  159. package/dist_ts/mail/security/classes.dmarcverifier.js +365 -0
  160. package/dist_ts/mail/security/classes.spfverifier.d.ts +103 -0
  161. package/dist_ts/mail/security/classes.spfverifier.js +492 -0
  162. package/dist_ts/mail/security/index.d.ts +4 -0
  163. package/dist_ts/mail/security/index.js +6 -0
  164. package/dist_ts/opsserver/classes.opsserver.d.ts +14 -0
  165. package/dist_ts/opsserver/classes.opsserver.js +37 -0
  166. package/dist_ts/opsserver/index.d.ts +1 -0
  167. package/dist_ts/opsserver/index.js +2 -0
  168. package/dist_ts/paths.d.ts +14 -0
  169. package/dist_ts/paths.js +39 -0
  170. package/dist_ts/plugins.d.ts +43 -0
  171. package/dist_ts/plugins.js +50 -0
  172. package/dist_ts/security/classes.contentscanner.d.ts +160 -0
  173. package/dist_ts/security/classes.contentscanner.js +634 -0
  174. package/dist_ts/security/classes.ipreputationchecker.d.ts +150 -0
  175. package/dist_ts/security/classes.ipreputationchecker.js +508 -0
  176. package/dist_ts/security/classes.securitylogger.d.ts +140 -0
  177. package/dist_ts/security/classes.securitylogger.js +232 -0
  178. package/dist_ts/security/index.d.ts +3 -0
  179. package/dist_ts/security/index.js +4 -0
  180. package/dist_ts/sms/classes.smsservice.d.ts +15 -0
  181. package/dist_ts/sms/classes.smsservice.js +72 -0
  182. package/dist_ts/sms/config/sms.config.d.ts +93 -0
  183. package/dist_ts/sms/config/sms.config.js +2 -0
  184. package/dist_ts/sms/config/sms.schema.d.ts +5 -0
  185. package/dist_ts/sms/config/sms.schema.js +121 -0
  186. package/dist_ts/sms/index.d.ts +1 -0
  187. package/dist_ts/sms/index.js +2 -0
  188. package/dist_ts/storage/classes.storagemanager.d.ts +82 -0
  189. package/dist_ts/storage/classes.storagemanager.js +341 -0
  190. package/dist_ts/storage/index.d.ts +1 -0
  191. package/dist_ts/storage/index.js +3 -0
  192. package/dist_ts/ts/00_commitinfo_data.d.ts +8 -0
  193. package/dist_ts/ts/00_commitinfo_data.js +9 -0
  194. package/dist_ts/ts/classes.dcrouter.d.ts +238 -0
  195. package/dist_ts/ts/classes.dcrouter.js +1008 -0
  196. package/dist_ts/ts/config/index.d.ts +1 -0
  197. package/dist_ts/ts/config/index.js +3 -0
  198. package/dist_ts/ts/config/validator.d.ts +104 -0
  199. package/dist_ts/ts/config/validator.js +152 -0
  200. package/dist_ts/ts/deliverability/classes.ipwarmupmanager.d.ts +253 -0
  201. package/dist_ts/ts/deliverability/classes.ipwarmupmanager.js +639 -0
  202. package/dist_ts/ts/deliverability/classes.senderreputationmonitor.d.ts +300 -0
  203. package/dist_ts/ts/deliverability/classes.senderreputationmonitor.js +961 -0
  204. package/dist_ts/ts/deliverability/index.d.ts +2 -0
  205. package/dist_ts/ts/deliverability/index.js +3 -0
  206. package/dist_ts/ts/errors/base.errors.d.ts +224 -0
  207. package/dist_ts/ts/errors/base.errors.js +310 -0
  208. package/dist_ts/ts/errors/email.errors.d.ts +175 -0
  209. package/dist_ts/ts/errors/email.errors.js +265 -0
  210. package/dist_ts/ts/errors/error-handler.d.ts +98 -0
  211. package/dist_ts/ts/errors/error-handler.js +282 -0
  212. package/dist_ts/ts/errors/error.codes.d.ts +115 -0
  213. package/dist_ts/ts/errors/error.codes.js +136 -0
  214. package/dist_ts/ts/errors/index.d.ts +56 -0
  215. package/dist_ts/ts/errors/index.js +138 -0
  216. package/dist_ts/ts/errors/mta.errors.d.ts +259 -0
  217. package/dist_ts/ts/errors/mta.errors.js +472 -0
  218. package/dist_ts/ts/errors/reputation.errors.d.ts +183 -0
  219. package/dist_ts/ts/errors/reputation.errors.js +292 -0
  220. package/dist_ts/ts/index.d.ts +4 -0
  221. package/dist_ts/ts/index.js +6 -0
  222. package/dist_ts/ts/logger.d.ts +17 -0
  223. package/dist_ts/ts/logger.js +77 -0
  224. package/dist_ts/ts/mail/core/classes.bouncemanager.d.ts +200 -0
  225. package/dist_ts/ts/mail/core/classes.bouncemanager.js +778 -0
  226. package/dist_ts/ts/mail/core/classes.email.d.ts +291 -0
  227. package/dist_ts/ts/mail/core/classes.email.js +780 -0
  228. package/dist_ts/ts/mail/core/classes.emailvalidator.d.ts +61 -0
  229. package/dist_ts/ts/mail/core/classes.emailvalidator.js +182 -0
  230. package/dist_ts/ts/mail/core/classes.templatemanager.d.ts +95 -0
  231. package/dist_ts/ts/mail/core/classes.templatemanager.js +239 -0
  232. package/dist_ts/ts/mail/core/index.d.ts +4 -0
  233. package/dist_ts/ts/mail/core/index.js +6 -0
  234. package/dist_ts/ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
  235. package/dist_ts/ts/mail/delivery/classes.delivery.queue.js +485 -0
  236. package/dist_ts/ts/mail/delivery/classes.delivery.system.d.ts +186 -0
  237. package/dist_ts/ts/mail/delivery/classes.delivery.system.js +846 -0
  238. package/dist_ts/ts/mail/delivery/classes.emailsendjob.d.ts +84 -0
  239. package/dist_ts/ts/mail/delivery/classes.emailsendjob.js +362 -0
  240. package/dist_ts/ts/mail/delivery/classes.emailsignjob.d.ts +18 -0
  241. package/dist_ts/ts/mail/delivery/classes.emailsignjob.js +44 -0
  242. package/dist_ts/ts/mail/delivery/classes.mta.config.d.ts +22 -0
  243. package/dist_ts/ts/mail/delivery/classes.mta.config.js +51 -0
  244. package/dist_ts/ts/mail/delivery/classes.ratelimiter.d.ts +98 -0
  245. package/dist_ts/ts/mail/delivery/classes.ratelimiter.js +205 -0
  246. package/dist_ts/ts/mail/delivery/classes.smtp.client.legacy.d.ts +275 -0
  247. package/dist_ts/ts/mail/delivery/classes.smtp.client.legacy.js +973 -0
  248. package/dist_ts/ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
  249. package/dist_ts/ts/mail/delivery/classes.unified.rate.limiter.js +817 -0
  250. package/dist_ts/ts/mail/delivery/index.d.ts +12 -0
  251. package/dist_ts/ts/mail/delivery/index.js +18 -0
  252. package/dist_ts/ts/mail/delivery/interfaces.d.ts +243 -0
  253. package/dist_ts/ts/mail/delivery/interfaces.js +17 -0
  254. package/dist_ts/ts/mail/delivery/smtpclient/auth-handler.d.ts +43 -0
  255. package/dist_ts/ts/mail/delivery/smtpclient/auth-handler.js +188 -0
  256. package/dist_ts/ts/mail/delivery/smtpclient/command-handler.d.ts +67 -0
  257. package/dist_ts/ts/mail/delivery/smtpclient/command-handler.js +276 -0
  258. package/dist_ts/ts/mail/delivery/smtpclient/connection-manager.d.ts +48 -0
  259. package/dist_ts/ts/mail/delivery/smtpclient/connection-manager.js +238 -0
  260. package/dist_ts/ts/mail/delivery/smtpclient/constants.d.ts +129 -0
  261. package/dist_ts/ts/mail/delivery/smtpclient/constants.js +135 -0
  262. package/dist_ts/ts/mail/delivery/smtpclient/create-client.d.ts +22 -0
  263. package/dist_ts/ts/mail/delivery/smtpclient/create-client.js +86 -0
  264. package/dist_ts/ts/mail/delivery/smtpclient/error-handler.d.ts +28 -0
  265. package/dist_ts/ts/mail/delivery/smtpclient/error-handler.js +110 -0
  266. package/dist_ts/ts/mail/delivery/smtpclient/index.d.ts +16 -0
  267. package/dist_ts/ts/mail/delivery/smtpclient/index.js +21 -0
  268. package/dist_ts/ts/mail/delivery/smtpclient/interfaces.d.ts +183 -0
  269. package/dist_ts/ts/mail/delivery/smtpclient/interfaces.js +19 -0
  270. package/dist_ts/ts/mail/delivery/smtpclient/smtp-client.d.ts +58 -0
  271. package/dist_ts/ts/mail/delivery/smtpclient/smtp-client.js +279 -0
  272. package/dist_ts/ts/mail/delivery/smtpclient/tls-handler.d.ts +33 -0
  273. package/dist_ts/ts/mail/delivery/smtpclient/tls-handler.js +202 -0
  274. package/dist_ts/ts/mail/delivery/smtpclient/utils/helpers.d.ts +77 -0
  275. package/dist_ts/ts/mail/delivery/smtpclient/utils/helpers.js +196 -0
  276. package/dist_ts/ts/mail/delivery/smtpclient/utils/logging.d.ts +46 -0
  277. package/dist_ts/ts/mail/delivery/smtpclient/utils/logging.js +153 -0
  278. package/dist_ts/ts/mail/delivery/smtpclient/utils/validation.d.ts +38 -0
  279. package/dist_ts/ts/mail/delivery/smtpclient/utils/validation.js +139 -0
  280. package/dist_ts/ts/mail/delivery/smtpserver/certificate-utils.d.ts +45 -0
  281. package/dist_ts/ts/mail/delivery/smtpserver/certificate-utils.js +345 -0
  282. package/dist_ts/ts/mail/delivery/smtpserver/command-handler.d.ts +156 -0
  283. package/dist_ts/ts/mail/delivery/smtpserver/command-handler.js +1159 -0
  284. package/dist_ts/ts/mail/delivery/smtpserver/connection-manager.d.ts +159 -0
  285. package/dist_ts/ts/mail/delivery/smtpserver/connection-manager.js +894 -0
  286. package/dist_ts/ts/mail/delivery/smtpserver/constants.d.ts +130 -0
  287. package/dist_ts/ts/mail/delivery/smtpserver/constants.js +162 -0
  288. package/dist_ts/ts/mail/delivery/smtpserver/create-server.d.ts +14 -0
  289. package/dist_ts/ts/mail/delivery/smtpserver/create-server.js +28 -0
  290. package/dist_ts/ts/mail/delivery/smtpserver/data-handler.d.ts +123 -0
  291. package/dist_ts/ts/mail/delivery/smtpserver/data-handler.js +1148 -0
  292. package/dist_ts/ts/mail/delivery/smtpserver/index.d.ts +20 -0
  293. package/dist_ts/ts/mail/delivery/smtpserver/index.js +27 -0
  294. package/dist_ts/ts/mail/delivery/smtpserver/interfaces.d.ts +530 -0
  295. package/dist_ts/ts/mail/delivery/smtpserver/interfaces.js +10 -0
  296. package/dist_ts/ts/mail/delivery/smtpserver/secure-server.d.ts +15 -0
  297. package/dist_ts/ts/mail/delivery/smtpserver/secure-server.js +79 -0
  298. package/dist_ts/ts/mail/delivery/smtpserver/security-handler.d.ts +86 -0
  299. package/dist_ts/ts/mail/delivery/smtpserver/security-handler.js +234 -0
  300. package/dist_ts/ts/mail/delivery/smtpserver/session-manager.d.ts +140 -0
  301. package/dist_ts/ts/mail/delivery/smtpserver/session-manager.js +469 -0
  302. package/dist_ts/ts/mail/delivery/smtpserver/smtp-server.d.ts +137 -0
  303. package/dist_ts/ts/mail/delivery/smtpserver/smtp-server.js +666 -0
  304. package/dist_ts/ts/mail/delivery/smtpserver/starttls-handler.d.ts +21 -0
  305. package/dist_ts/ts/mail/delivery/smtpserver/starttls-handler.js +207 -0
  306. package/dist_ts/ts/mail/delivery/smtpserver/tls-handler.d.ts +66 -0
  307. package/dist_ts/ts/mail/delivery/smtpserver/tls-handler.js +261 -0
  308. package/dist_ts/ts/mail/delivery/smtpserver/utils/adaptive-logging.d.ts +117 -0
  309. package/dist_ts/ts/mail/delivery/smtpserver/utils/adaptive-logging.js +411 -0
  310. package/dist_ts/ts/mail/delivery/smtpserver/utils/helpers.d.ts +78 -0
  311. package/dist_ts/ts/mail/delivery/smtpserver/utils/helpers.js +208 -0
  312. package/dist_ts/ts/mail/delivery/smtpserver/utils/logging.d.ts +106 -0
  313. package/dist_ts/ts/mail/delivery/smtpserver/utils/logging.js +181 -0
  314. package/dist_ts/ts/mail/delivery/smtpserver/utils/validation.d.ts +69 -0
  315. package/dist_ts/ts/mail/delivery/smtpserver/utils/validation.js +360 -0
  316. package/dist_ts/ts/mail/index.d.ts +8 -0
  317. package/dist_ts/ts/mail/index.js +13 -0
  318. package/dist_ts/ts/mail/routing/classes.dns.manager.d.ts +65 -0
  319. package/dist_ts/ts/mail/routing/classes.dns.manager.js +413 -0
  320. package/dist_ts/ts/mail/routing/classes.dnsmanager.d.ts +165 -0
  321. package/dist_ts/ts/mail/routing/classes.dnsmanager.js +430 -0
  322. package/dist_ts/ts/mail/routing/classes.domain.registry.d.ts +54 -0
  323. package/dist_ts/ts/mail/routing/classes.domain.registry.js +118 -0
  324. package/dist_ts/ts/mail/routing/classes.email.config.d.ts +64 -0
  325. package/dist_ts/ts/mail/routing/classes.email.config.js +2 -0
  326. package/dist_ts/ts/mail/routing/classes.email.router.d.ts +171 -0
  327. package/dist_ts/ts/mail/routing/classes.email.router.js +491 -0
  328. package/dist_ts/ts/mail/routing/classes.unified.email.server.d.ts +426 -0
  329. package/dist_ts/ts/mail/routing/classes.unified.email.server.js +1454 -0
  330. package/dist_ts/ts/mail/routing/index.d.ts +5 -0
  331. package/dist_ts/ts/mail/routing/index.js +7 -0
  332. package/dist_ts/ts/mail/routing/interfaces.d.ts +187 -0
  333. package/dist_ts/ts/mail/routing/interfaces.js +2 -0
  334. package/dist_ts/ts/mail/security/classes.dkimcreator.d.ts +68 -0
  335. package/dist_ts/ts/mail/security/classes.dkimcreator.js +346 -0
  336. package/dist_ts/ts/mail/security/classes.dkimverifier.d.ts +46 -0
  337. package/dist_ts/ts/mail/security/classes.dkimverifier.js +317 -0
  338. package/dist_ts/ts/mail/security/classes.dmarcverifier.d.ts +123 -0
  339. package/dist_ts/ts/mail/security/classes.dmarcverifier.js +365 -0
  340. package/dist_ts/ts/mail/security/classes.spfverifier.d.ts +103 -0
  341. package/dist_ts/ts/mail/security/classes.spfverifier.js +492 -0
  342. package/dist_ts/ts/mail/security/index.d.ts +4 -0
  343. package/dist_ts/ts/mail/security/index.js +6 -0
  344. package/dist_ts/ts/opsserver/classes.opsserver.d.ts +20 -0
  345. package/dist_ts/ts/opsserver/classes.opsserver.js +44 -0
  346. package/dist_ts/ts/opsserver/handlers/admin.handler.d.ts +31 -0
  347. package/dist_ts/ts/opsserver/handlers/admin.handler.js +177 -0
  348. package/dist_ts/ts/opsserver/handlers/config.handler.d.ts +10 -0
  349. package/dist_ts/ts/opsserver/handlers/config.handler.js +100 -0
  350. package/dist_ts/ts/opsserver/handlers/index.d.ts +5 -0
  351. package/dist_ts/ts/opsserver/handlers/index.js +6 -0
  352. package/dist_ts/ts/opsserver/handlers/logs.handler.d.ts +10 -0
  353. package/dist_ts/ts/opsserver/handlers/logs.handler.js +121 -0
  354. package/dist_ts/ts/opsserver/handlers/security.handler.d.ts +11 -0
  355. package/dist_ts/ts/opsserver/handlers/security.handler.js +118 -0
  356. package/dist_ts/ts/opsserver/handlers/stats.handler.d.ts +13 -0
  357. package/dist_ts/ts/opsserver/handlers/stats.handler.js +233 -0
  358. package/dist_ts/ts/opsserver/helpers/guards.d.ts +25 -0
  359. package/dist_ts/ts/opsserver/helpers/guards.js +41 -0
  360. package/dist_ts/ts/opsserver/index.d.ts +1 -0
  361. package/dist_ts/ts/opsserver/index.js +2 -0
  362. package/dist_ts/ts/paths.d.ts +14 -0
  363. package/dist_ts/ts/paths.js +39 -0
  364. package/dist_ts/ts/plugins.d.ts +46 -0
  365. package/dist_ts/ts/plugins.js +53 -0
  366. package/dist_ts/ts/security/classes.contentscanner.d.ts +160 -0
  367. package/dist_ts/ts/security/classes.contentscanner.js +634 -0
  368. package/dist_ts/ts/security/classes.ipreputationchecker.d.ts +150 -0
  369. package/dist_ts/ts/security/classes.ipreputationchecker.js +508 -0
  370. package/dist_ts/ts/security/classes.securitylogger.d.ts +140 -0
  371. package/dist_ts/ts/security/classes.securitylogger.js +232 -0
  372. package/dist_ts/ts/security/index.d.ts +3 -0
  373. package/dist_ts/ts/security/index.js +4 -0
  374. package/dist_ts/ts/sms/classes.smsservice.d.ts +15 -0
  375. package/dist_ts/ts/sms/classes.smsservice.js +72 -0
  376. package/dist_ts/ts/sms/config/sms.config.d.ts +93 -0
  377. package/dist_ts/ts/sms/config/sms.config.js +2 -0
  378. package/dist_ts/ts/sms/config/sms.schema.d.ts +5 -0
  379. package/dist_ts/ts/sms/config/sms.schema.js +121 -0
  380. package/dist_ts/ts/sms/index.d.ts +1 -0
  381. package/dist_ts/ts/sms/index.js +2 -0
  382. package/dist_ts/ts/storage/classes.storagemanager.d.ts +82 -0
  383. package/dist_ts/ts/storage/classes.storagemanager.js +341 -0
  384. package/dist_ts/ts/storage/index.d.ts +1 -0
  385. package/dist_ts/ts/storage/index.js +3 -0
  386. package/dist_ts/ts_interfaces/data/auth.d.ts +8 -0
  387. package/dist_ts/ts_interfaces/data/auth.js +2 -0
  388. package/dist_ts/ts_interfaces/data/index.d.ts +2 -0
  389. package/dist_ts/ts_interfaces/data/index.js +3 -0
  390. package/dist_ts/ts_interfaces/data/stats.d.ts +93 -0
  391. package/dist_ts/ts_interfaces/data/stats.js +2 -0
  392. package/dist_ts/ts_interfaces/index.d.ts +5 -0
  393. package/dist_ts/ts_interfaces/index.js +8 -0
  394. package/dist_ts/ts_interfaces/plugins.d.ts +2 -0
  395. package/dist_ts/ts_interfaces/plugins.js +4 -0
  396. package/dist_ts/ts_interfaces/requests/admin.d.ts +31 -0
  397. package/dist_ts/ts_interfaces/requests/admin.js +3 -0
  398. package/dist_ts/ts_interfaces/requests/config.d.ts +25 -0
  399. package/dist_ts/ts_interfaces/requests/config.js +3 -0
  400. package/dist_ts/ts_interfaces/requests/index.d.ts +4 -0
  401. package/dist_ts/ts_interfaces/requests/index.js +5 -0
  402. package/dist_ts/ts_interfaces/requests/logs.d.ts +34 -0
  403. package/dist_ts/ts_interfaces/requests/logs.js +4 -0
  404. package/dist_ts/ts_interfaces/requests/stats.d.ts +131 -0
  405. package/dist_ts/ts_interfaces/requests/stats.js +4 -0
  406. package/html/index.html +121 -0
  407. package/npmextra.json +45 -0
  408. package/package.json +83 -0
  409. package/readme.hints.md +906 -0
  410. package/readme.md +1253 -0
  411. package/readme.opsserver.md +351 -0
  412. package/test/helpers/server.loader.ts +347 -0
  413. package/test/helpers/smtp.client.ts +209 -0
  414. package/test/helpers/utils.ts +311 -0
  415. package/test/readme.md +443 -0
  416. package/test/suite/smtpclient_commands/test.ccmd-01.ehlo-helo-sending.ts +168 -0
  417. package/test/suite/smtpclient_commands/test.ccmd-02.mail-from-parameters.ts +277 -0
  418. package/test/suite/smtpclient_commands/test.ccmd-03.rcpt-to-multiple.ts +283 -0
  419. package/test/suite/smtpclient_commands/test.ccmd-04.data-transmission.ts +274 -0
  420. package/test/suite/smtpclient_commands/test.ccmd-05.auth-mechanisms.ts +306 -0
  421. package/test/suite/smtpclient_commands/test.ccmd-06.command-pipelining.ts +233 -0
  422. package/test/suite/smtpclient_commands/test.ccmd-07.response-parsing.ts +243 -0
  423. package/test/suite/smtpclient_commands/test.ccmd-08.rset-command.ts +333 -0
  424. package/test/suite/smtpclient_commands/test.ccmd-09.noop-command.ts +339 -0
  425. package/test/suite/smtpclient_commands/test.ccmd-10.vrfy-expn.ts +457 -0
  426. package/test/suite/smtpclient_commands/test.ccmd-11.help-command.ts +409 -0
  427. package/test/suite/smtpclient_connection/test.ccm-01.basic-tcp-connection.ts +150 -0
  428. package/test/suite/smtpclient_connection/test.ccm-02.tls-connection.ts +140 -0
  429. package/test/suite/smtpclient_connection/test.ccm-03.starttls-upgrade.ts +208 -0
  430. package/test/suite/smtpclient_connection/test.ccm-04.connection-pooling.ts +250 -0
  431. package/test/suite/smtpclient_connection/test.ccm-05.connection-reuse.ts +288 -0
  432. package/test/suite/smtpclient_connection/test.ccm-06.connection-timeout.ts +267 -0
  433. package/test/suite/smtpclient_connection/test.ccm-07.automatic-reconnection.ts +324 -0
  434. package/test/suite/smtpclient_connection/test.ccm-08.dns-resolution.ts +139 -0
  435. package/test/suite/smtpclient_connection/test.ccm-09.ipv6-dual-stack.ts +167 -0
  436. package/test/suite/smtpclient_connection/test.ccm-10.proxy-support.ts +305 -0
  437. package/test/suite/smtpclient_connection/test.ccm-11.keepalive.ts +299 -0
  438. package/test/suite/smtpclient_edge-cases/test.cedge-01.unusual-server-responses.ts +529 -0
  439. package/test/suite/smtpclient_edge-cases/test.cedge-02.malformed-commands.ts +438 -0
  440. package/test/suite/smtpclient_edge-cases/test.cedge-03.protocol-violations.ts +446 -0
  441. package/test/suite/smtpclient_edge-cases/test.cedge-04.resource-constraints.ts +530 -0
  442. package/test/suite/smtpclient_edge-cases/test.cedge-05.encoding-issues.ts +145 -0
  443. package/test/suite/smtpclient_edge-cases/test.cedge-06.large-headers.ts +180 -0
  444. package/test/suite/smtpclient_edge-cases/test.cedge-07.concurrent-operations.ts +204 -0
  445. package/test/suite/smtpclient_email-composition/test.cep-01.basic-headers.ts +245 -0
  446. package/test/suite/smtpclient_email-composition/test.cep-02.mime-multipart.ts +321 -0
  447. package/test/suite/smtpclient_email-composition/test.cep-03.attachment-encoding.ts +334 -0
  448. package/test/suite/smtpclient_email-composition/test.cep-04.bcc-handling.ts +187 -0
  449. package/test/suite/smtpclient_email-composition/test.cep-05.reply-to-return-path.ts +277 -0
  450. package/test/suite/smtpclient_email-composition/test.cep-06.utf8-international.ts +235 -0
  451. package/test/suite/smtpclient_email-composition/test.cep-07.html-inline-images.ts +489 -0
  452. package/test/suite/smtpclient_email-composition/test.cep-08.custom-headers.ts +293 -0
  453. package/test/suite/smtpclient_email-composition/test.cep-09.priority-importance.ts +314 -0
  454. package/test/suite/smtpclient_email-composition/test.cep-10.receipts-dsn.ts +411 -0
  455. package/test/suite/smtpclient_error-handling/test.cerr-01.4xx-errors.ts +232 -0
  456. package/test/suite/smtpclient_error-handling/test.cerr-02.5xx-errors.ts +309 -0
  457. package/test/suite/smtpclient_error-handling/test.cerr-03.network-failures.ts +299 -0
  458. package/test/suite/smtpclient_error-handling/test.cerr-04.greylisting-handling.ts +255 -0
  459. package/test/suite/smtpclient_error-handling/test.cerr-05.quota-exceeded.ts +273 -0
  460. package/test/suite/smtpclient_error-handling/test.cerr-06.invalid-recipients.ts +320 -0
  461. package/test/suite/smtpclient_error-handling/test.cerr-07.message-size-limits.ts +320 -0
  462. package/test/suite/smtpclient_error-handling/test.cerr-08.rate-limiting.ts +261 -0
  463. package/test/suite/smtpclient_error-handling/test.cerr-09.connection-pool-errors.ts +299 -0
  464. package/test/suite/smtpclient_error-handling/test.cerr-10.partial-failure.ts +373 -0
  465. package/test/suite/smtpclient_performance/test.cperf-01.bulk-sending.ts +332 -0
  466. package/test/suite/smtpclient_performance/test.cperf-02.message-throughput.ts +304 -0
  467. package/test/suite/smtpclient_performance/test.cperf-03.memory-usage.ts +332 -0
  468. package/test/suite/smtpclient_performance/test.cperf-04.cpu-utilization.ts +373 -0
  469. package/test/suite/smtpclient_performance/test.cperf-05.network-efficiency.ts +181 -0
  470. package/test/suite/smtpclient_performance/test.cperf-06.caching-strategies.ts +190 -0
  471. package/test/suite/smtpclient_performance/test.cperf-07.queue-management.ts +171 -0
  472. package/test/suite/smtpclient_performance/test.cperf-08.dns-caching.ts +50 -0
  473. package/test/suite/smtpclient_reliability/test.crel-01.reconnection-logic.ts +305 -0
  474. package/test/suite/smtpclient_reliability/test.crel-02.network-interruption.ts +207 -0
  475. package/test/suite/smtpclient_reliability/test.crel-03.queue-persistence.ts +469 -0
  476. package/test/suite/smtpclient_reliability/test.crel-04.crash-recovery.ts +520 -0
  477. package/test/suite/smtpclient_reliability/test.crel-05.memory-leaks.ts +503 -0
  478. package/test/suite/smtpclient_reliability/test.crel-06.concurrency-safety.ts +558 -0
  479. package/test/suite/smtpclient_reliability/test.crel-07.resource-cleanup.ts +52 -0
  480. package/test/suite/smtpclient_rfc-compliance/test.crfc-01.rfc5321-client.ts +283 -0
  481. package/test/suite/smtpclient_rfc-compliance/test.crfc-02.esmtp-compliance.ts +77 -0
  482. package/test/suite/smtpclient_rfc-compliance/test.crfc-03.command-syntax.ts +67 -0
  483. package/test/suite/smtpclient_rfc-compliance/test.crfc-04.response-codes.ts +54 -0
  484. package/test/suite/smtpclient_rfc-compliance/test.crfc-05.state-machine.ts +703 -0
  485. package/test/suite/smtpclient_rfc-compliance/test.crfc-06.protocol-negotiation.ts +688 -0
  486. package/test/suite/smtpclient_rfc-compliance/test.crfc-07.interoperability.ts +728 -0
  487. package/test/suite/smtpclient_rfc-compliance/test.crfc-08.smtp-extensions.ts +656 -0
  488. package/test/suite/smtpclient_security/test.csec-01.tls-verification.ts +88 -0
  489. package/test/suite/smtpclient_security/test.csec-02.oauth2-authentication.ts +132 -0
  490. package/test/suite/smtpclient_security/test.csec-03.dkim-signing.ts +138 -0
  491. package/test/suite/smtpclient_security/test.csec-04.spf-compliance.ts +163 -0
  492. package/test/suite/smtpclient_security/test.csec-05.dmarc-policy.ts +200 -0
  493. package/test/suite/smtpclient_security/test.csec-06.certificate-validation.ts +145 -0
  494. package/test/suite/smtpclient_security/test.csec-07.cipher-suites.ts +153 -0
  495. package/test/suite/smtpclient_security/test.csec-08.authentication-fallback.ts +154 -0
  496. package/test/suite/smtpclient_security/test.csec-09.relay-restrictions.ts +166 -0
  497. package/test/suite/smtpclient_security/test.csec-10.anti-spam-measures.ts +196 -0
  498. package/test/suite/smtpserver_commands/test.cmd-01.ehlo-command.ts +193 -0
  499. package/test/suite/smtpserver_commands/test.cmd-02.mail-from.ts +330 -0
  500. package/test/suite/smtpserver_commands/test.cmd-03.rcpt-to.ts +296 -0
  501. package/test/suite/smtpserver_commands/test.cmd-04.data-command.ts +395 -0
  502. package/test/suite/smtpserver_commands/test.cmd-05.noop-command.ts +320 -0
  503. package/test/suite/smtpserver_commands/test.cmd-06.rset-command.ts +399 -0
  504. package/test/suite/smtpserver_commands/test.cmd-07.vrfy-command.ts +391 -0
  505. package/test/suite/smtpserver_commands/test.cmd-08.expn-command.ts +450 -0
  506. package/test/suite/smtpserver_commands/test.cmd-09.size-extension.ts +465 -0
  507. package/test/suite/smtpserver_commands/test.cmd-10.help-command.ts +454 -0
  508. package/test/suite/smtpserver_commands/test.cmd-11.command-pipelining.ts +334 -0
  509. package/test/suite/smtpserver_commands/test.cmd-12.helo-command.ts +420 -0
  510. package/test/suite/smtpserver_commands/test.cmd-13.quit-command.ts +384 -0
  511. package/test/suite/smtpserver_connection/test.cm-01.tls-connection.ts +61 -0
  512. package/test/suite/smtpserver_connection/test.cm-02.multiple-connections.ts +112 -0
  513. package/test/suite/smtpserver_connection/test.cm-03.connection-timeout.ts +134 -0
  514. package/test/suite/smtpserver_connection/test.cm-04.connection-limits.ts +374 -0
  515. package/test/suite/smtpserver_connection/test.cm-05.connection-rejection.ts +296 -0
  516. package/test/suite/smtpserver_connection/test.cm-06.starttls-upgrade.ts +468 -0
  517. package/test/suite/smtpserver_connection/test.cm-07.abrupt-disconnection.ts +321 -0
  518. package/test/suite/smtpserver_connection/test.cm-08.tls-versions.ts +361 -0
  519. package/test/suite/smtpserver_connection/test.cm-09.tls-ciphers.ts +556 -0
  520. package/test/suite/smtpserver_connection/test.cm-10.plain-connection.ts +293 -0
  521. package/test/suite/smtpserver_connection/test.cm-11.keepalive.ts +382 -0
  522. package/test/suite/smtpserver_edge-cases/test.edge-01.very-large-email.ts +239 -0
  523. package/test/suite/smtpserver_edge-cases/test.edge-02.very-small-email.ts +389 -0
  524. package/test/suite/smtpserver_edge-cases/test.edge-03.invalid-character-handling.ts +479 -0
  525. package/test/suite/smtpserver_edge-cases/test.edge-04.empty-commands.ts +430 -0
  526. package/test/suite/smtpserver_edge-cases/test.edge-05.extremely-long-lines.ts +425 -0
  527. package/test/suite/smtpserver_edge-cases/test.edge-06.extremely-long-headers.ts +404 -0
  528. package/test/suite/smtpserver_edge-cases/test.edge-07.unusual-mime-types.ts +333 -0
  529. package/test/suite/smtpserver_edge-cases/test.edge-08.nested-mime-structures.ts +379 -0
  530. package/test/suite/smtpserver_email-processing/test.ep-01.basic-email-sending.ts +338 -0
  531. package/test/suite/smtpserver_email-processing/test.ep-02.invalid-email-addresses.ts +315 -0
  532. package/test/suite/smtpserver_email-processing/test.ep-03.multiple-recipients.ts +493 -0
  533. package/test/suite/smtpserver_email-processing/test.ep-04.large-email.ts +528 -0
  534. package/test/suite/smtpserver_email-processing/test.ep-05.mime-handling.ts +515 -0
  535. package/test/suite/smtpserver_email-processing/test.ep-06.attachment-handling.ts +629 -0
  536. package/test/suite/smtpserver_email-processing/test.ep-07.special-character-handling.ts +462 -0
  537. package/test/suite/smtpserver_email-processing/test.ep-08.email-routing.ts +527 -0
  538. package/test/suite/smtpserver_email-processing/test.ep-09.delivery-status-notifications.ts +486 -0
  539. package/test/suite/smtpserver_error-handling/test.err-01.syntax-errors.ts +475 -0
  540. package/test/suite/smtpserver_error-handling/test.err-02.invalid-sequence.ts +450 -0
  541. package/test/suite/smtpserver_error-handling/test.err-03.temporary-failures.ts +453 -0
  542. package/test/suite/smtpserver_error-handling/test.err-04.permanent-failures.ts +325 -0
  543. package/test/suite/smtpserver_error-handling/test.err-05.resource-exhaustion.ts +302 -0
  544. package/test/suite/smtpserver_error-handling/test.err-06.malformed-mime.ts +374 -0
  545. package/test/suite/smtpserver_error-handling/test.err-07.exception-handling.ts +333 -0
  546. package/test/suite/smtpserver_error-handling/test.err-08.error-logging.ts +324 -0
  547. package/test/suite/smtpserver_performance/test.perf-01.throughput.ts +183 -0
  548. package/test/suite/smtpserver_performance/test.perf-02.concurrency.ts +388 -0
  549. package/test/suite/smtpserver_performance/test.perf-03.cpu-utilization.ts +245 -0
  550. package/test/suite/smtpserver_performance/test.perf-04.memory-usage.ts +238 -0
  551. package/test/suite/smtpserver_performance/test.perf-05.connection-processing-time.ts +363 -0
  552. package/test/suite/smtpserver_performance/test.perf-06.message-processing-time.ts +252 -0
  553. package/test/suite/smtpserver_performance/test.perf-07.resource-cleanup.ts +317 -0
  554. package/test/suite/smtpserver_reliability/test.rel-01.long-running-operation.ts +344 -0
  555. package/test/suite/smtpserver_reliability/test.rel-02.restart-recovery.ts +328 -0
  556. package/test/suite/smtpserver_reliability/test.rel-03.resource-leak-detection.ts +394 -0
  557. package/test/suite/smtpserver_reliability/test.rel-04.error-recovery.ts +401 -0
  558. package/test/suite/smtpserver_reliability/test.rel-05.dns-resolution-failure.ts +335 -0
  559. package/test/suite/smtpserver_reliability/test.rel-06.network-interruption.ts +410 -0
  560. package/test/suite/smtpserver_rfc-compliance/test.rfc-01.rfc5321-compliance.ts +382 -0
  561. package/test/suite/smtpserver_rfc-compliance/test.rfc-02.rfc5322-compliance.ts +428 -0
  562. package/test/suite/smtpserver_rfc-compliance/test.rfc-03.rfc7208-spf-compliance.ts +330 -0
  563. package/test/suite/smtpserver_rfc-compliance/test.rfc-04.rfc6376-dkim-compliance.ts +450 -0
  564. package/test/suite/smtpserver_rfc-compliance/test.rfc-05.rfc7489-dmarc-compliance.ts +408 -0
  565. package/test/suite/smtpserver_rfc-compliance/test.rfc-06.rfc8314-tls-compliance.ts +366 -0
  566. package/test/suite/smtpserver_rfc-compliance/test.rfc-07.rfc3461-dsn-compliance.ts +399 -0
  567. package/test/suite/smtpserver_security/test.sec-01.authentication.ts +218 -0
  568. package/test/suite/smtpserver_security/test.sec-02.authorization.ts +286 -0
  569. package/test/suite/smtpserver_security/test.sec-03.dkim-processing.ts +414 -0
  570. package/test/suite/smtpserver_security/test.sec-04.spf-checking.ts +280 -0
  571. package/test/suite/smtpserver_security/test.sec-05.dmarc-policy.ts +374 -0
  572. package/test/suite/smtpserver_security/test.sec-06.ip-reputation.ts +303 -0
  573. package/test/suite/smtpserver_security/test.sec-07.content-scanning.ts +409 -0
  574. package/test/suite/smtpserver_security/test.sec-08.rate-limiting.ts +324 -0
  575. package/test/suite/smtpserver_security/test.sec-09.tls-certificate-validation.ts +312 -0
  576. package/test/suite/smtpserver_security/test.sec-10.header-injection-prevention.ts +332 -0
  577. package/test/suite/smtpserver_security/test.sec-11.bounce-management.ts +363 -0
  578. package/test/test.base.ts +65 -0
  579. package/test/test.bouncemanager.ts +196 -0
  580. package/test/test.config.md +175 -0
  581. package/test/test.contentscanner.ts +265 -0
  582. package/test/test.dcrouter.email.ts +201 -0
  583. package/test/test.deliverability.ts +55 -0
  584. package/test/test.dns-manager-creation.ts +141 -0
  585. package/test/test.dns-mode-switching.ts +257 -0
  586. package/test/test.dns-server-config.ts +140 -0
  587. package/test/test.dns-socket-handler.ts +169 -0
  588. package/test/test.dns-validation.ts +283 -0
  589. package/test/test.email-socket-handler.ts +228 -0
  590. package/test/test.email.integration.ts +377 -0
  591. package/test/test.email.router.ts +283 -0
  592. package/test/test.emailauth.ts +195 -0
  593. package/test/test.errors.ts +408 -0
  594. package/test/test.integration.storage.ts +313 -0
  595. package/test/test.integration.ts +75 -0
  596. package/test/test.ipreputationchecker.ts +179 -0
  597. package/test/test.ipwarmupmanager.ts +323 -0
  598. package/test/test.jwt-auth.ts +130 -0
  599. package/test/test.minimal.ts +66 -0
  600. package/test/test.opsserver-api.ts +83 -0
  601. package/test/test.protected-endpoint.ts +115 -0
  602. package/test/test.rate-limiting-integration.ts +236 -0
  603. package/test/test.ratelimiter.ts +141 -0
  604. package/test/test.reputationmonitor.ts +262 -0
  605. package/test/test.smartmail.ts +248 -0
  606. package/test/test.smtp.client.compatibility.ts +154 -0
  607. package/test/test.smtp.client.ts +191 -0
  608. package/test/test.smtp.server.ts +180 -0
  609. package/test/test.socket-handler-integration.ts +240 -0
  610. package/test/test.socket-handler-unit.ts +198 -0
  611. package/test/test.storagemanager.ts +289 -0
  612. package/ts/00_commitinfo_data.ts +8 -0
  613. package/ts/classes.dcrouter.ts +1310 -0
  614. package/ts/config/index.ts +2 -0
  615. package/ts/config/validator.ts +266 -0
  616. package/ts/deliverability/classes.ipwarmupmanager.ts +896 -0
  617. package/ts/deliverability/classes.senderreputationmonitor.ts +1244 -0
  618. package/ts/deliverability/index.ts +13 -0
  619. package/ts/errors/base.errors.ts +525 -0
  620. package/ts/errors/email.errors.ts +383 -0
  621. package/ts/errors/error-handler.ts +412 -0
  622. package/ts/errors/error.codes.ts +165 -0
  623. package/ts/errors/index.ts +195 -0
  624. package/ts/errors/mta.errors.ts +681 -0
  625. package/ts/errors/reputation.errors.ts +422 -0
  626. package/ts/index.ts +7 -0
  627. package/ts/logger.ts +91 -0
  628. package/ts/mail/core/classes.bouncemanager.ts +965 -0
  629. package/ts/mail/core/classes.email.ts +941 -0
  630. package/ts/mail/core/classes.emailvalidator.ts +239 -0
  631. package/ts/mail/core/classes.templatemanager.ts +320 -0
  632. package/ts/mail/core/index.ts +5 -0
  633. package/ts/mail/delivery/classes.delivery.queue.ts +645 -0
  634. package/ts/mail/delivery/classes.delivery.system.ts +1089 -0
  635. package/ts/mail/delivery/classes.emailsendjob.ts +447 -0
  636. package/ts/mail/delivery/classes.emailsendjob.ts.backup +691 -0
  637. package/ts/mail/delivery/classes.emailsignjob.ts +67 -0
  638. package/ts/mail/delivery/classes.mta.config.ts +73 -0
  639. package/ts/mail/delivery/classes.ratelimiter.ts +281 -0
  640. package/ts/mail/delivery/classes.smtp.client.legacy.ts +1422 -0
  641. package/ts/mail/delivery/classes.unified.rate.limiter.ts +1053 -0
  642. package/ts/mail/delivery/index.ts +24 -0
  643. package/ts/mail/delivery/interfaces.ts +291 -0
  644. package/ts/mail/delivery/smtpclient/auth-handler.ts +232 -0
  645. package/ts/mail/delivery/smtpclient/command-handler.ts +343 -0
  646. package/ts/mail/delivery/smtpclient/connection-manager.ts +289 -0
  647. package/ts/mail/delivery/smtpclient/constants.ts +145 -0
  648. package/ts/mail/delivery/smtpclient/create-client.ts +94 -0
  649. package/ts/mail/delivery/smtpclient/error-handler.ts +141 -0
  650. package/ts/mail/delivery/smtpclient/index.ts +24 -0
  651. package/ts/mail/delivery/smtpclient/interfaces.ts +242 -0
  652. package/ts/mail/delivery/smtpclient/smtp-client.ts +357 -0
  653. package/ts/mail/delivery/smtpclient/tls-handler.ts +254 -0
  654. package/ts/mail/delivery/smtpclient/utils/helpers.ts +224 -0
  655. package/ts/mail/delivery/smtpclient/utils/logging.ts +212 -0
  656. package/ts/mail/delivery/smtpclient/utils/validation.ts +170 -0
  657. package/ts/mail/delivery/smtpserver/certificate-utils.ts +398 -0
  658. package/ts/mail/delivery/smtpserver/command-handler.ts +1340 -0
  659. package/ts/mail/delivery/smtpserver/connection-manager.ts +1045 -0
  660. package/ts/mail/delivery/smtpserver/constants.ts +181 -0
  661. package/ts/mail/delivery/smtpserver/create-server.ts +31 -0
  662. package/ts/mail/delivery/smtpserver/data-handler.ts +1283 -0
  663. package/ts/mail/delivery/smtpserver/index.ts +32 -0
  664. package/ts/mail/delivery/smtpserver/interfaces.ts +655 -0
  665. package/ts/mail/delivery/smtpserver/secure-server.ts +97 -0
  666. package/ts/mail/delivery/smtpserver/security-handler.ts +345 -0
  667. package/ts/mail/delivery/smtpserver/session-manager.ts +557 -0
  668. package/ts/mail/delivery/smtpserver/smtp-server.ts +804 -0
  669. package/ts/mail/delivery/smtpserver/starttls-handler.ts +262 -0
  670. package/ts/mail/delivery/smtpserver/tls-handler.ts +346 -0
  671. package/ts/mail/delivery/smtpserver/utils/adaptive-logging.ts +514 -0
  672. package/ts/mail/delivery/smtpserver/utils/helpers.ts +246 -0
  673. package/ts/mail/delivery/smtpserver/utils/logging.ts +246 -0
  674. package/ts/mail/delivery/smtpserver/utils/validation.ts +436 -0
  675. package/ts/mail/index.ts +19 -0
  676. package/ts/mail/routing/classes.dns.manager.ts +563 -0
  677. package/ts/mail/routing/classes.dnsmanager.ts +559 -0
  678. package/ts/mail/routing/classes.domain.registry.ts +139 -0
  679. package/ts/mail/routing/classes.email.config.ts +82 -0
  680. package/ts/mail/routing/classes.email.router.ts +575 -0
  681. package/ts/mail/routing/classes.unified.email.server.ts +1873 -0
  682. package/ts/mail/routing/index.ts +6 -0
  683. package/ts/mail/routing/interfaces.ts +202 -0
  684. package/ts/mail/security/classes.dkimcreator.ts +431 -0
  685. package/ts/mail/security/classes.dkimverifier.ts +382 -0
  686. package/ts/mail/security/classes.dmarcverifier.ts +478 -0
  687. package/ts/mail/security/classes.spfverifier.ts +606 -0
  688. package/ts/mail/security/index.ts +5 -0
  689. package/ts/opsserver/classes.opsserver.ts +65 -0
  690. package/ts/opsserver/handlers/admin.handler.ts +240 -0
  691. package/ts/opsserver/handlers/config.handler.ts +150 -0
  692. package/ts/opsserver/handlers/index.ts +5 -0
  693. package/ts/opsserver/handlers/logs.handler.ts +195 -0
  694. package/ts/opsserver/handlers/security.handler.ts +208 -0
  695. package/ts/opsserver/handlers/stats.handler.ts +344 -0
  696. package/ts/opsserver/helpers/guards.ts +56 -0
  697. package/ts/opsserver/index.ts +1 -0
  698. package/ts/paths.ts +48 -0
  699. package/ts/plugins.ts +94 -0
  700. package/ts/security/classes.contentscanner.ts +739 -0
  701. package/ts/security/classes.ipreputationchecker.ts +592 -0
  702. package/ts/security/classes.securitylogger.ts +299 -0
  703. package/ts/security/index.ts +21 -0
  704. package/ts/sms/classes.smsservice.ts +98 -0
  705. package/ts/sms/config/sms.config.ts +109 -0
  706. package/ts/sms/config/sms.schema.ts +122 -0
  707. package/ts/sms/index.ts +1 -0
  708. package/ts/storage/classes.storagemanager.ts +400 -0
  709. package/ts/storage/index.ts +2 -0
  710. package/ts/tspublish.json +3 -0
  711. package/ts_interfaces/data/auth.ts +8 -0
  712. package/ts_interfaces/data/index.ts +2 -0
  713. package/ts_interfaces/data/stats.ts +101 -0
  714. package/ts_interfaces/index.ts +9 -0
  715. package/ts_interfaces/plugins.ts +6 -0
  716. package/ts_interfaces/requests/admin.ts +46 -0
  717. package/ts_interfaces/requests/config.ts +35 -0
  718. package/ts_interfaces/requests/index.ts +4 -0
  719. package/ts_interfaces/requests/logs.ts +44 -0
  720. package/ts_interfaces/requests/stats.ts +162 -0
  721. package/ts_interfaces/tspublish.json +3 -0
  722. package/ts_web/00_commitinfo_data.ts +8 -0
  723. package/ts_web/appstate.ts +361 -0
  724. package/ts_web/elements/index.ts +7 -0
  725. package/ts_web/elements/ops-dashboard.ts +165 -0
  726. package/ts_web/elements/ops-view-config.ts +268 -0
  727. package/ts_web/elements/ops-view-logs.ts +207 -0
  728. package/ts_web/elements/ops-view-overview.ts +222 -0
  729. package/ts_web/elements/ops-view-security.ts +471 -0
  730. package/ts_web/elements/ops-view-stats.ts +299 -0
  731. package/ts_web/elements/shared/css.ts +10 -0
  732. package/ts_web/elements/shared/index.ts +2 -0
  733. package/ts_web/elements/shared/ops-sectionheading.ts +42 -0
  734. package/ts_web/index.ts +9 -0
  735. package/ts_web/plugins.ts +11 -0
  736. package/ts_web/tspublish.json +3 -0
  737. package/tsconfig.json +15 -0
@@ -0,0 +1,961 @@
1
+ import * as plugins from '../plugins.js';
2
+ import * as paths from '../paths.js';
3
+ import { logger } from '../logger.js';
4
+ /**
5
+ * Default configuration
6
+ */
7
+ const DEFAULT_CONFIG = {
8
+ enabled: true,
9
+ domains: [],
10
+ updateFrequency: 24 * 60 * 60 * 1000, // Daily
11
+ dataSources: {
12
+ spamLists: [
13
+ 'zen.spamhaus.org',
14
+ 'bl.spamcop.net',
15
+ 'dnsbl.sorbs.net',
16
+ 'b.barracudacentral.org'
17
+ ],
18
+ deliverabilityMonitor: null
19
+ },
20
+ alertThresholds: {
21
+ minReputationScore: 70,
22
+ maxComplaintRate: 0.1, // 0.1%
23
+ maxBounceRate: 5, // 5%
24
+ minOpenRate: 15 // 15%
25
+ }
26
+ };
27
+ /**
28
+ * Class for monitoring and tracking sender reputation for domains
29
+ */
30
+ export class SenderReputationMonitor {
31
+ /**
32
+ * Constructor for SenderReputationMonitor
33
+ * @param config Configuration options
34
+ * @param storageManager Optional StorageManager instance
35
+ */
36
+ constructor(config = {}, storageManager) {
37
+ this.reputationData = new Map();
38
+ this.updateTimer = null;
39
+ this.isInitialized = false;
40
+ // Merge with default config
41
+ this.config = {
42
+ ...DEFAULT_CONFIG,
43
+ ...config,
44
+ dataSources: {
45
+ ...DEFAULT_CONFIG.dataSources,
46
+ ...config.dataSources
47
+ },
48
+ alertThresholds: {
49
+ ...DEFAULT_CONFIG.alertThresholds,
50
+ ...config.alertThresholds
51
+ }
52
+ };
53
+ this.storageManager = storageManager;
54
+ // If no storage manager provided, log warning
55
+ if (!storageManager) {
56
+ logger.log('warn', '⚠️ WARNING: SenderReputationMonitor initialized without StorageManager.\n' +
57
+ ' Reputation data will only be stored to filesystem.\n' +
58
+ ' Consider passing a StorageManager instance for better storage flexibility.');
59
+ }
60
+ // Initialize (async, but we don't await here to avoid blocking constructor)
61
+ this.initialize().catch(error => {
62
+ logger.log('error', `Failed to initialize SenderReputationMonitor: ${error.message}`, {
63
+ stack: error.stack
64
+ });
65
+ });
66
+ }
67
+ /**
68
+ * Get the singleton instance
69
+ * @param config Configuration options
70
+ * @param storageManager Optional StorageManager instance
71
+ * @returns Singleton instance
72
+ */
73
+ static getInstance(config = {}, storageManager) {
74
+ if (!SenderReputationMonitor.instance) {
75
+ SenderReputationMonitor.instance = new SenderReputationMonitor(config, storageManager);
76
+ }
77
+ return SenderReputationMonitor.instance;
78
+ }
79
+ /**
80
+ * Initialize the reputation monitor
81
+ */
82
+ async initialize() {
83
+ if (this.isInitialized)
84
+ return;
85
+ try {
86
+ // Only load data if not running in a test environment
87
+ const isTestEnvironment = process.env.NODE_ENV === 'test' || !!process.env.JEST_WORKER_ID;
88
+ if (!isTestEnvironment) {
89
+ // Load existing reputation data
90
+ await this.loadReputationData();
91
+ }
92
+ // Initialize data for any new domains
93
+ for (const domain of this.config.domains) {
94
+ if (!this.reputationData.has(domain)) {
95
+ this.initializeDomainData(domain);
96
+ }
97
+ }
98
+ // Schedule updates if enabled and not in test environment
99
+ if (this.config.enabled && !isTestEnvironment) {
100
+ this.scheduleUpdates();
101
+ }
102
+ this.isInitialized = true;
103
+ logger.log('info', `Sender Reputation Monitor initialized for ${this.config.domains.length} domains`);
104
+ }
105
+ catch (error) {
106
+ logger.log('error', `Failed to initialize Sender Reputation Monitor: ${error.message}`, {
107
+ stack: error.stack
108
+ });
109
+ }
110
+ }
111
+ /**
112
+ * Initialize reputation data for a new domain
113
+ * @param domain Domain to initialize
114
+ */
115
+ initializeDomainData(domain) {
116
+ // Create new domain reputation metrics with default values
117
+ const newMetrics = {
118
+ domain,
119
+ lastUpdated: new Date(),
120
+ volume: {
121
+ sent: 0,
122
+ delivered: 0,
123
+ hardBounces: 0,
124
+ softBounces: 0,
125
+ dailySendVolume: {}
126
+ },
127
+ engagement: {
128
+ opens: 0,
129
+ clicks: 0,
130
+ openRate: 0,
131
+ clickRate: 0,
132
+ clickToOpenRate: 0
133
+ },
134
+ complaints: {
135
+ total: 0,
136
+ rate: 0,
137
+ topDomains: []
138
+ },
139
+ authentication: {
140
+ spfPassRate: 100, // Assume perfect initially
141
+ dkimPassRate: 100,
142
+ dmarcPassRate: 100,
143
+ failures: []
144
+ },
145
+ blocklist: {
146
+ listed: false,
147
+ activeListings: [],
148
+ recentDelistings: []
149
+ },
150
+ inboxPlacement: {
151
+ overall: 95, // Start with optimistic estimate
152
+ providers: {
153
+ gmail: 95,
154
+ outlook: 95,
155
+ yahoo: 95,
156
+ aol: 95,
157
+ other: 95
158
+ }
159
+ },
160
+ historical: {
161
+ reputationScores: {},
162
+ trends: {
163
+ openRate: 0,
164
+ complaintRate: 0,
165
+ bounceRate: 0,
166
+ spamListings: 0
167
+ }
168
+ }
169
+ };
170
+ // Generate some initial historical data points
171
+ const today = new Date();
172
+ for (let i = 0; i < 30; i++) {
173
+ const date = new Date(today);
174
+ date.setDate(date.getDate() - i);
175
+ const dateKey = date.toISOString().split('T')[0];
176
+ newMetrics.historical.reputationScores[dateKey] = 95; // Default good score
177
+ newMetrics.volume.dailySendVolume[dateKey] = 0;
178
+ }
179
+ // Save the new metrics
180
+ this.reputationData.set(domain, newMetrics);
181
+ logger.log('info', `Initialized reputation data for domain ${domain}`);
182
+ }
183
+ /**
184
+ * Schedule regular reputation data updates
185
+ */
186
+ scheduleUpdates() {
187
+ if (this.updateTimer) {
188
+ clearTimeout(this.updateTimer);
189
+ }
190
+ this.updateTimer = setTimeout(async () => {
191
+ await this.updateAllDomainMetrics();
192
+ this.scheduleUpdates(); // Reschedule for next update
193
+ }, this.config.updateFrequency);
194
+ logger.log('info', `Scheduled reputation updates every ${this.config.updateFrequency / (60 * 60 * 1000)} hours`);
195
+ }
196
+ /**
197
+ * Update metrics for all monitored domains
198
+ */
199
+ async updateAllDomainMetrics() {
200
+ if (!this.config.enabled)
201
+ return;
202
+ logger.log('info', 'Starting reputation metrics update for all domains');
203
+ for (const domain of this.config.domains) {
204
+ try {
205
+ await this.updateDomainMetrics(domain);
206
+ logger.log('info', `Updated reputation metrics for ${domain}`);
207
+ }
208
+ catch (error) {
209
+ logger.log('error', `Error updating metrics for ${domain}: ${error.message}`, {
210
+ stack: error.stack
211
+ });
212
+ }
213
+ }
214
+ // Save all updated data
215
+ await this.saveReputationData();
216
+ logger.log('info', 'Completed reputation metrics update for all domains');
217
+ }
218
+ /**
219
+ * Update reputation metrics for a specific domain
220
+ * @param domain Domain to update
221
+ */
222
+ async updateDomainMetrics(domain) {
223
+ const metrics = this.reputationData.get(domain);
224
+ if (!metrics) {
225
+ logger.log('warn', `No reputation data found for domain ${domain}`);
226
+ return;
227
+ }
228
+ try {
229
+ // Update last updated timestamp
230
+ metrics.lastUpdated = new Date();
231
+ // Check blocklist status
232
+ await this.checkBlocklistStatus(domain, metrics);
233
+ // Update historical data
234
+ this.updateHistoricalData(metrics);
235
+ // Calculate current reputation score
236
+ const reputationScore = this.calculateReputationScore(metrics);
237
+ // Save current reputation score to historical data
238
+ const today = new Date().toISOString().split('T')[0];
239
+ metrics.historical.reputationScores[today] = reputationScore;
240
+ // Calculate trends
241
+ this.calculateTrends(metrics);
242
+ // Check alert thresholds
243
+ this.checkAlertThresholds(metrics);
244
+ }
245
+ catch (error) {
246
+ logger.log('error', `Error in updateDomainMetrics for ${domain}: ${error.message}`, {
247
+ stack: error.stack
248
+ });
249
+ }
250
+ }
251
+ /**
252
+ * Check domain blocklist status
253
+ * @param domain Domain to check
254
+ * @param metrics Metrics to update
255
+ */
256
+ async checkBlocklistStatus(domain, metrics) {
257
+ // Skip DNS lookups in test environment
258
+ const isTestEnvironment = process.env.NODE_ENV === 'test' || !!process.env.JEST_WORKER_ID;
259
+ if (isTestEnvironment || !this.config.dataSources.spamLists?.length) {
260
+ return;
261
+ }
262
+ const previouslyListed = metrics.blocklist.listed;
263
+ const previousListings = new Set(metrics.blocklist.activeListings.map(l => l.list));
264
+ // Store current listings to detect changes
265
+ const currentListings = [];
266
+ // Check each blocklist
267
+ for (const list of this.config.dataSources.spamLists) {
268
+ try {
269
+ const isListed = await this.checkDomainOnBlocklist(domain, list);
270
+ if (isListed) {
271
+ // If already known to be listed on this one, keep the original listing date
272
+ const existingListing = metrics.blocklist.activeListings.find(l => l.list === list);
273
+ if (existingListing) {
274
+ currentListings.push(existingListing);
275
+ }
276
+ else {
277
+ // New listing
278
+ currentListings.push({
279
+ list,
280
+ listedSince: new Date()
281
+ });
282
+ }
283
+ }
284
+ }
285
+ catch (error) {
286
+ logger.log('warn', `Error checking ${domain} on blocklist ${list}: ${error.message}`);
287
+ }
288
+ }
289
+ // Update active listings
290
+ metrics.blocklist.activeListings = currentListings;
291
+ metrics.blocklist.listed = currentListings.length > 0;
292
+ // Check for delistings
293
+ if (previouslyListed) {
294
+ const currentListsSet = new Set(currentListings.map(l => l.list));
295
+ // Convert Set to Array for compatibility with older JS versions
296
+ Array.from(previousListings).forEach(list => {
297
+ if (!currentListsSet.has(list)) {
298
+ // This list no longer contains the domain - it was delisted
299
+ const previousListing = metrics.blocklist.activeListings.find(l => l.list === list);
300
+ if (previousListing) {
301
+ metrics.blocklist.recentDelistings.push({
302
+ list,
303
+ listedFrom: previousListing.listedSince,
304
+ listedTo: new Date()
305
+ });
306
+ }
307
+ }
308
+ });
309
+ // Keep only recent delistings (last 90 days)
310
+ const ninetyDaysAgo = new Date();
311
+ ninetyDaysAgo.setDate(ninetyDaysAgo.getDate() - 90);
312
+ metrics.blocklist.recentDelistings = metrics.blocklist.recentDelistings
313
+ .filter(d => d.listedTo > ninetyDaysAgo);
314
+ }
315
+ }
316
+ /**
317
+ * Check if a domain is on a specific blocklist
318
+ * @param domain Domain to check
319
+ * @param list Blocklist to check
320
+ * @returns Whether the domain is listed
321
+ */
322
+ async checkDomainOnBlocklist(domain, list) {
323
+ try {
324
+ // Look up the domain in the blocklist (simplified)
325
+ if (list === 'zen.spamhaus.org') {
326
+ // For Spamhaus and similar lists, we check the domain MX IPs
327
+ const mxRecords = await plugins.dns.promises.resolveMx(domain);
328
+ if (mxRecords && mxRecords.length > 0) {
329
+ // Check the primary MX record
330
+ const primaryMx = mxRecords.sort((a, b) => a.priority - b.priority)[0].exchange;
331
+ // Resolve IP addresses for the MX
332
+ const ips = await plugins.dns.promises.resolve(primaryMx);
333
+ // Check the first IP
334
+ if (ips.length > 0) {
335
+ const ip = ips[0];
336
+ const reversedIp = ip.split('.').reverse().join('.');
337
+ const lookupDomain = `${reversedIp}.${list}`;
338
+ try {
339
+ await plugins.dns.promises.resolve(lookupDomain);
340
+ return true; // Listed
341
+ }
342
+ catch (err) {
343
+ if (err.code === 'ENOTFOUND') {
344
+ return false; // Not listed
345
+ }
346
+ throw err; // Other error
347
+ }
348
+ }
349
+ }
350
+ return false;
351
+ }
352
+ else {
353
+ // For domain-based blocklists
354
+ const lookupDomain = `${domain}.${list}`;
355
+ try {
356
+ await plugins.dns.promises.resolve(lookupDomain);
357
+ return true; // Listed
358
+ }
359
+ catch (err) {
360
+ if (err.code === 'ENOTFOUND') {
361
+ return false; // Not listed
362
+ }
363
+ throw err; // Other error
364
+ }
365
+ }
366
+ }
367
+ catch (error) {
368
+ logger.log('warn', `Error checking blocklist status for ${domain} on ${list}: ${error.message}`);
369
+ return false; // Assume not listed on error
370
+ }
371
+ }
372
+ /**
373
+ * Update historical data in metrics
374
+ * @param metrics Metrics to update
375
+ */
376
+ updateHistoricalData(metrics) {
377
+ // Keep only the last 30 days of data
378
+ const dates = Object.keys(metrics.historical.reputationScores)
379
+ .sort((a, b) => b.localeCompare(a)); // Sort descending
380
+ if (dates.length > 30) {
381
+ const daysToKeep = dates.slice(0, 30);
382
+ const newScores = {};
383
+ for (const day of daysToKeep) {
384
+ newScores[day] = metrics.historical.reputationScores[day];
385
+ }
386
+ metrics.historical.reputationScores = newScores;
387
+ }
388
+ // Same for daily send volume
389
+ const volumeDates = Object.keys(metrics.volume.dailySendVolume)
390
+ .sort((a, b) => b.localeCompare(a));
391
+ if (volumeDates.length > 30) {
392
+ const daysToKeep = volumeDates.slice(0, 30);
393
+ const newVolume = {};
394
+ for (const day of daysToKeep) {
395
+ newVolume[day] = metrics.volume.dailySendVolume[day];
396
+ }
397
+ metrics.volume.dailySendVolume = newVolume;
398
+ }
399
+ }
400
+ /**
401
+ * Calculate reputation score from metrics
402
+ * @param metrics Domain reputation metrics
403
+ * @returns Reputation score (0-100)
404
+ */
405
+ calculateReputationScore(metrics) {
406
+ // Calculate component scores
407
+ const components = {
408
+ engagement: this.calculateEngagementScore(metrics),
409
+ complaints: this.calculateComplaintScore(metrics),
410
+ authentication: this.calculateAuthenticationScore(metrics),
411
+ volumeStability: this.calculateVolumeStabilityScore(metrics),
412
+ infrastructure: this.calculateInfrastructureScore(metrics),
413
+ blocklist: this.calculateBlocklistScore(metrics)
414
+ };
415
+ // Apply weights to components
416
+ const weightedScore = components.engagement * 0.25 +
417
+ components.complaints * 0.25 +
418
+ components.authentication * 0.2 +
419
+ components.volumeStability * 0.1 +
420
+ components.infrastructure * 0.1 +
421
+ components.blocklist * 0.1;
422
+ // Round to 2 decimal places
423
+ return Math.round(weightedScore * 100) / 100;
424
+ }
425
+ /**
426
+ * Calculate engagement component score
427
+ * @param metrics Domain metrics
428
+ * @returns Engagement score (0-100)
429
+ */
430
+ calculateEngagementScore(metrics) {
431
+ const openRate = metrics.engagement.openRate;
432
+ const clickRate = metrics.engagement.clickRate;
433
+ // Benchmark open and click rates
434
+ // <5% open rate = poor (score: 0-30)
435
+ // 5-15% = average (score: 30-70)
436
+ // >15% = good (score: 70-100)
437
+ let openScore = 0;
438
+ if (openRate < 5) {
439
+ openScore = openRate * 6; // 0-30 scale
440
+ }
441
+ else if (openRate < 15) {
442
+ openScore = 30 + (openRate - 5) * 4; // 30-70 scale
443
+ }
444
+ else {
445
+ openScore = 70 + Math.min(30, (openRate - 15) * 2); // 70-100 scale
446
+ }
447
+ // Similarly for click rate
448
+ let clickScore = 0;
449
+ if (clickRate < 1) {
450
+ clickScore = clickRate * 30; // 0-30 scale
451
+ }
452
+ else if (clickRate < 5) {
453
+ clickScore = 30 + (clickRate - 1) * 10; // 30-70 scale
454
+ }
455
+ else {
456
+ clickScore = 70 + Math.min(30, (clickRate - 5) * 6); // 70-100 scale
457
+ }
458
+ // Combine with 60% weight to open rate, 40% to click rate
459
+ return (openScore * 0.6 + clickScore * 0.4);
460
+ }
461
+ /**
462
+ * Calculate complaint component score
463
+ * @param metrics Domain metrics
464
+ * @returns Complaint score (0-100)
465
+ */
466
+ calculateComplaintScore(metrics) {
467
+ const complaintRate = metrics.complaints.rate;
468
+ // Industry standard: complaint rate should be under 0.1%
469
+ // 0% = perfect (score: 100)
470
+ // 0.1% = threshold (score: 70)
471
+ // 0.5% = problematic (score: 30)
472
+ // 1%+ = critical (score: 0)
473
+ if (complaintRate === 0)
474
+ return 100;
475
+ if (complaintRate >= 1)
476
+ return 0;
477
+ if (complaintRate < 0.1) {
478
+ // 0-0.1% maps to 100-70
479
+ return 100 - (complaintRate / 0.1) * 30;
480
+ }
481
+ else if (complaintRate < 0.5) {
482
+ // 0.1-0.5% maps to 70-30
483
+ return 70 - ((complaintRate - 0.1) / 0.4) * 40;
484
+ }
485
+ else {
486
+ // 0.5-1% maps to 30-0
487
+ return 30 - ((complaintRate - 0.5) / 0.5) * 30;
488
+ }
489
+ }
490
+ /**
491
+ * Calculate authentication component score
492
+ * @param metrics Domain metrics
493
+ * @returns Authentication score (0-100)
494
+ */
495
+ calculateAuthenticationScore(metrics) {
496
+ const spfRate = metrics.authentication.spfPassRate;
497
+ const dkimRate = metrics.authentication.dkimPassRate;
498
+ const dmarcRate = metrics.authentication.dmarcPassRate;
499
+ // Weight SPF, DKIM, and DMARC
500
+ return (spfRate * 0.3 + dkimRate * 0.3 + dmarcRate * 0.4);
501
+ }
502
+ /**
503
+ * Calculate volume stability component score
504
+ * @param metrics Domain metrics
505
+ * @returns Volume stability score (0-100)
506
+ */
507
+ calculateVolumeStabilityScore(metrics) {
508
+ const volumes = Object.values(metrics.volume.dailySendVolume);
509
+ if (volumes.length < 2)
510
+ return 100; // Not enough data
511
+ // Calculate coefficient of variation (stdev / mean)
512
+ const mean = volumes.reduce((sum, v) => sum + v, 0) / volumes.length;
513
+ if (mean === 0)
514
+ return 100; // No sending activity
515
+ const variance = volumes.reduce((sum, v) => sum + Math.pow(v - mean, 2), 0) / volumes.length;
516
+ const stdev = Math.sqrt(variance);
517
+ const cv = stdev / mean;
518
+ // Convert to score: lower CV means more stability
519
+ // CV < 0.1 is very stable (score: 90-100)
520
+ // CV < 0.5 is normal (score: 60-90)
521
+ // CV < 1.0 is somewhat unstable (score: 30-60)
522
+ // CV >= 1.0 is unstable (score: 0-30)
523
+ if (cv < 0.1) {
524
+ return 90 + (1 - cv / 0.1) * 10;
525
+ }
526
+ else if (cv < 0.5) {
527
+ return 60 + (1 - (cv - 0.1) / 0.4) * 30;
528
+ }
529
+ else if (cv < 1.0) {
530
+ return 30 + (1 - (cv - 0.5) / 0.5) * 30;
531
+ }
532
+ else {
533
+ return Math.max(0, 30 - (cv - 1.0) * 10);
534
+ }
535
+ }
536
+ /**
537
+ * Calculate infrastructure component score
538
+ * @param metrics Domain metrics
539
+ * @returns Infrastructure score (0-100)
540
+ */
541
+ calculateInfrastructureScore(metrics) {
542
+ // This is a placeholder; in reality, this would be based on:
543
+ // - IP reputation
544
+ // - Reverse DNS configuration
545
+ // - IP warming status
546
+ // - Historical IP behavior
547
+ // For now, assume good infrastructure
548
+ return 90;
549
+ }
550
+ /**
551
+ * Calculate blocklist component score
552
+ * @param metrics Domain metrics
553
+ * @returns Blocklist score (0-100)
554
+ */
555
+ calculateBlocklistScore(metrics) {
556
+ // If currently listed on any blocklist, score is heavily impacted
557
+ if (metrics.blocklist.listed) {
558
+ // Number of active listings determines severity
559
+ const listingCount = metrics.blocklist.activeListings.length;
560
+ if (listingCount >= 3)
561
+ return 0; // Critical: listed on 3+ lists
562
+ if (listingCount === 2)
563
+ return 20; // Severe: listed on 2 lists
564
+ return 40; // Serious: listed on 1 list
565
+ }
566
+ // If recently delisted, some penalty still applies
567
+ if (metrics.blocklist.recentDelistings.length > 0) {
568
+ // Check how recent the delistings are
569
+ const now = new Date();
570
+ const mostRecent = metrics.blocklist.recentDelistings
571
+ .reduce((latest, delisting) => delisting.listedTo > latest ? delisting.listedTo : latest, new Date(0));
572
+ const daysSinceDelisting = Math.floor((now.getTime() - mostRecent.getTime()) / (24 * 60 * 60 * 1000));
573
+ // Score improves as time passes since delisting
574
+ if (daysSinceDelisting < 7)
575
+ return 60; // Delisted within last week
576
+ if (daysSinceDelisting < 30)
577
+ return 80; // Delisted within last month
578
+ return 90; // Delisted over a month ago
579
+ }
580
+ // Never listed
581
+ return 100;
582
+ }
583
+ /**
584
+ * Calculate trend metrics
585
+ * @param metrics Domain metrics to update
586
+ */
587
+ calculateTrends(metrics) {
588
+ // Get dates in descending order
589
+ const dates = Object.keys(metrics.historical.reputationScores)
590
+ .sort((a, b) => b.localeCompare(a));
591
+ if (dates.length < 7) {
592
+ // Not enough data for trends
593
+ metrics.historical.trends = {
594
+ openRate: 0,
595
+ complaintRate: 0,
596
+ bounceRate: 0,
597
+ spamListings: 0
598
+ };
599
+ return;
600
+ }
601
+ // Calculate trends over past 7 days compared to previous 7 days
602
+ const current7Days = dates.slice(0, 7);
603
+ const previous7Days = dates.slice(7, 14);
604
+ if (previous7Days.length < 7) {
605
+ // Not enough historical data
606
+ return;
607
+ }
608
+ // Calculate averages for the periods
609
+ const currentReputation = current7Days.reduce((sum, date) => sum + metrics.historical.reputationScores[date], 0) / current7Days.length;
610
+ const previousReputation = previous7Days.reduce((sum, date) => sum + metrics.historical.reputationScores[date], 0) / previous7Days.length;
611
+ // Calculate percent change
612
+ const reputationChange = ((currentReputation - previousReputation) / previousReputation) * 100;
613
+ // For now, use reputation change for all trends (in a real implementation
614
+ // we would calculate each metric's trend separately)
615
+ metrics.historical.trends = {
616
+ openRate: reputationChange,
617
+ complaintRate: -reputationChange, // Inverse for complaint rate (negative is good)
618
+ bounceRate: -reputationChange, // Inverse for bounce rate
619
+ spamListings: -reputationChange // Inverse for spam listings
620
+ };
621
+ }
622
+ /**
623
+ * Check if metrics exceed alert thresholds
624
+ * @param metrics Domain metrics to check
625
+ */
626
+ checkAlertThresholds(metrics) {
627
+ const thresholds = this.config.alertThresholds;
628
+ const today = new Date().toISOString().split('T')[0];
629
+ const todayScore = metrics.historical.reputationScores[today] || 0;
630
+ // Check reputation score
631
+ if (todayScore < thresholds.minReputationScore) {
632
+ this.sendAlert(metrics.domain, 'reputation_score', {
633
+ score: todayScore,
634
+ threshold: thresholds.minReputationScore
635
+ });
636
+ }
637
+ // Check complaint rate
638
+ if (metrics.complaints.rate > thresholds.maxComplaintRate) {
639
+ this.sendAlert(metrics.domain, 'complaint_rate', {
640
+ rate: metrics.complaints.rate,
641
+ threshold: thresholds.maxComplaintRate
642
+ });
643
+ }
644
+ // Check bounce rate
645
+ const bounceRate = (metrics.volume.hardBounces + metrics.volume.softBounces) /
646
+ Math.max(1, metrics.volume.sent) * 100;
647
+ if (bounceRate > thresholds.maxBounceRate) {
648
+ this.sendAlert(metrics.domain, 'bounce_rate', {
649
+ rate: bounceRate,
650
+ threshold: thresholds.maxBounceRate
651
+ });
652
+ }
653
+ // Check open rate
654
+ if (metrics.engagement.openRate < thresholds.minOpenRate) {
655
+ this.sendAlert(metrics.domain, 'open_rate', {
656
+ rate: metrics.engagement.openRate,
657
+ threshold: thresholds.minOpenRate
658
+ });
659
+ }
660
+ // Check blocklist status
661
+ if (metrics.blocklist.listed) {
662
+ this.sendAlert(metrics.domain, 'blocklist', {
663
+ lists: metrics.blocklist.activeListings.map(l => l.list)
664
+ });
665
+ }
666
+ }
667
+ /**
668
+ * Send an alert for a reputation issue
669
+ * @param domain Domain with the issue
670
+ * @param alertType Type of alert
671
+ * @param data Alert data
672
+ */
673
+ sendAlert(domain, alertType, data) {
674
+ logger.log('warn', `Reputation alert for ${domain}: ${alertType}`, data);
675
+ // In a real implementation, this would send alerts via email,
676
+ // notification systems, webhooks, etc.
677
+ }
678
+ /**
679
+ * Record a send event for domain reputation tracking
680
+ * @param domain The domain sending the email
681
+ * @param event Event details
682
+ */
683
+ recordSendEvent(domain, event) {
684
+ // Ensure we have metrics for this domain
685
+ if (!this.reputationData.has(domain)) {
686
+ this.initializeDomainData(domain);
687
+ }
688
+ const metrics = this.reputationData.get(domain);
689
+ const count = event.count || 1;
690
+ const today = new Date().toISOString().split('T')[0];
691
+ // Update metrics based on event type
692
+ switch (event.type) {
693
+ case 'sent':
694
+ metrics.volume.sent += count;
695
+ // Update daily send volume
696
+ metrics.volume.dailySendVolume[today] =
697
+ (metrics.volume.dailySendVolume[today] || 0) + count;
698
+ break;
699
+ case 'delivered':
700
+ metrics.volume.delivered += count;
701
+ break;
702
+ case 'bounce':
703
+ if (event.hardBounce) {
704
+ metrics.volume.hardBounces += count;
705
+ }
706
+ else {
707
+ metrics.volume.softBounces += count;
708
+ }
709
+ break;
710
+ case 'complaint':
711
+ metrics.complaints.total += count;
712
+ // Track by receiving domain
713
+ if (event.receivingDomain) {
714
+ const domainIndex = metrics.complaints.topDomains.findIndex(d => d.domain === event.receivingDomain);
715
+ if (domainIndex >= 0) {
716
+ metrics.complaints.topDomains[domainIndex].count += count;
717
+ metrics.complaints.topDomains[domainIndex].rate =
718
+ metrics.complaints.topDomains[domainIndex].count / Math.max(1, metrics.volume.sent);
719
+ }
720
+ else {
721
+ metrics.complaints.topDomains.push({
722
+ domain: event.receivingDomain,
723
+ count,
724
+ rate: count / Math.max(1, metrics.volume.sent)
725
+ });
726
+ }
727
+ // Sort by count
728
+ metrics.complaints.topDomains.sort((a, b) => b.count - a.count);
729
+ // Keep only top 10
730
+ if (metrics.complaints.topDomains.length > 10) {
731
+ metrics.complaints.topDomains = metrics.complaints.topDomains.slice(0, 10);
732
+ }
733
+ }
734
+ // Update overall complaint rate
735
+ metrics.complaints.rate =
736
+ metrics.complaints.total / Math.max(1, metrics.volume.sent);
737
+ break;
738
+ case 'open':
739
+ metrics.engagement.opens += count;
740
+ metrics.engagement.openRate =
741
+ metrics.engagement.opens / Math.max(1, metrics.volume.delivered);
742
+ break;
743
+ case 'click':
744
+ metrics.engagement.clicks += count;
745
+ metrics.engagement.clickRate =
746
+ metrics.engagement.clicks / Math.max(1, metrics.volume.delivered);
747
+ metrics.engagement.clickToOpenRate =
748
+ metrics.engagement.clicks / Math.max(1, metrics.engagement.opens);
749
+ break;
750
+ }
751
+ // Update last updated timestamp
752
+ metrics.lastUpdated = new Date();
753
+ // Save data periodically (not after every event to avoid excessive I/O)
754
+ // Skip in test environment
755
+ const isTestEnvironment = process.env.NODE_ENV === 'test' || !!process.env.JEST_WORKER_ID;
756
+ if (!isTestEnvironment && Math.random() < 0.01) { // ~1% chance to save on each event
757
+ this.saveReputationData().catch(error => {
758
+ logger.log('error', `Failed to save reputation data: ${error.message}`, {
759
+ stack: error.stack
760
+ });
761
+ });
762
+ }
763
+ }
764
+ /**
765
+ * Get reputation data for a domain
766
+ * @param domain Domain to get data for
767
+ * @returns Reputation data
768
+ */
769
+ getReputationData(domain) {
770
+ return this.reputationData.get(domain) || null;
771
+ }
772
+ /**
773
+ * Get summary reputation data for all domains
774
+ * @returns Summary data for all domains
775
+ */
776
+ getReputationSummary() {
777
+ return Array.from(this.reputationData.entries())
778
+ .map(([domain, metrics]) => {
779
+ const today = new Date().toISOString().split('T')[0];
780
+ const score = metrics.historical.reputationScores[today] || 0;
781
+ // Determine status based on score
782
+ let status;
783
+ if (score >= 90)
784
+ status = 'excellent';
785
+ else if (score >= 75)
786
+ status = 'good';
787
+ else if (score >= 60)
788
+ status = 'fair';
789
+ else if (score >= 40)
790
+ status = 'poor';
791
+ else
792
+ status = 'critical';
793
+ return {
794
+ domain,
795
+ score,
796
+ status,
797
+ listed: metrics.blocklist.listed,
798
+ trend: metrics.historical.trends.openRate // Use open rate trend as overall trend
799
+ };
800
+ })
801
+ .sort((a, b) => b.score - a.score); // Sort by score descending
802
+ }
803
+ /**
804
+ * Add a domain to monitor
805
+ * @param domain Domain to monitor
806
+ */
807
+ addDomain(domain) {
808
+ if (this.config.domains.includes(domain)) {
809
+ logger.log('info', `Domain ${domain} is already being monitored`);
810
+ return;
811
+ }
812
+ this.config.domains.push(domain);
813
+ this.initializeDomainData(domain);
814
+ this.saveReputationData().catch(error => {
815
+ logger.log('error', `Failed to save reputation data after adding domain: ${error.message}`, {
816
+ stack: error.stack
817
+ });
818
+ });
819
+ logger.log('info', `Added ${domain} to reputation monitoring`);
820
+ }
821
+ /**
822
+ * Remove a domain from monitoring
823
+ * @param domain Domain to remove
824
+ */
825
+ removeDomain(domain) {
826
+ const index = this.config.domains.indexOf(domain);
827
+ if (index === -1) {
828
+ logger.log('info', `Domain ${domain} is not being monitored`);
829
+ return;
830
+ }
831
+ this.config.domains.splice(index, 1);
832
+ this.reputationData.delete(domain);
833
+ this.saveReputationData().catch(error => {
834
+ logger.log('error', `Failed to save reputation data after removing domain: ${error.message}`, {
835
+ stack: error.stack
836
+ });
837
+ });
838
+ logger.log('info', `Removed ${domain} from reputation monitoring`);
839
+ }
840
+ /**
841
+ * Load reputation data from storage
842
+ */
843
+ async loadReputationData() {
844
+ // Skip loading in test environment to prevent file system race conditions
845
+ const isTestEnvironment = process.env.NODE_ENV === 'test' || !!process.env.JEST_WORKER_ID;
846
+ if (isTestEnvironment) {
847
+ return;
848
+ }
849
+ try {
850
+ // Try to load from storage manager first
851
+ if (this.storageManager) {
852
+ try {
853
+ const data = await this.storageManager.get('/email/reputation/domain-reputation.json');
854
+ if (data) {
855
+ const reputationEntries = JSON.parse(data);
856
+ for (const entry of reputationEntries) {
857
+ // Restore Date objects
858
+ entry.lastUpdated = new Date(entry.lastUpdated);
859
+ for (const listing of entry.blocklist.activeListings) {
860
+ listing.listedSince = new Date(listing.listedSince);
861
+ }
862
+ for (const delisting of entry.blocklist.recentDelistings) {
863
+ delisting.listedFrom = new Date(delisting.listedFrom);
864
+ delisting.listedTo = new Date(delisting.listedTo);
865
+ }
866
+ this.reputationData.set(entry.domain, entry);
867
+ }
868
+ logger.log('info', `Loaded reputation data for ${this.reputationData.size} domains from StorageManager`);
869
+ return;
870
+ }
871
+ }
872
+ catch (error) {
873
+ // Fall through to filesystem migration check
874
+ }
875
+ // Check if data exists in filesystem and migrate it to storage manager
876
+ const reputationDir = plugins.path.join(paths.dataDir, 'reputation');
877
+ const dataFile = plugins.path.join(reputationDir, 'domain_reputation.json');
878
+ if (plugins.fs.existsSync(dataFile)) {
879
+ const data = plugins.fs.readFileSync(dataFile, 'utf8');
880
+ const reputationEntries = JSON.parse(data);
881
+ for (const entry of reputationEntries) {
882
+ // Restore Date objects
883
+ entry.lastUpdated = new Date(entry.lastUpdated);
884
+ for (const listing of entry.blocklist.activeListings) {
885
+ listing.listedSince = new Date(listing.listedSince);
886
+ }
887
+ for (const delisting of entry.blocklist.recentDelistings) {
888
+ delisting.listedFrom = new Date(delisting.listedFrom);
889
+ delisting.listedTo = new Date(delisting.listedTo);
890
+ }
891
+ this.reputationData.set(entry.domain, entry);
892
+ }
893
+ // Migrate to storage manager
894
+ logger.log('info', `Migrating reputation data for ${this.reputationData.size} domains from filesystem to StorageManager`);
895
+ await this.storageManager.set('/email/reputation/domain-reputation.json', JSON.stringify(Array.from(this.reputationData.values()), null, 2));
896
+ logger.log('info', `Loaded and migrated reputation data for ${this.reputationData.size} domains`);
897
+ }
898
+ }
899
+ else {
900
+ // No storage manager, use filesystem directly
901
+ const reputationDir = plugins.path.join(paths.dataDir, 'reputation');
902
+ plugins.smartfile.fs.ensureDirSync(reputationDir);
903
+ const dataFile = plugins.path.join(reputationDir, 'domain_reputation.json');
904
+ if (plugins.fs.existsSync(dataFile)) {
905
+ const data = plugins.fs.readFileSync(dataFile, 'utf8');
906
+ const reputationEntries = JSON.parse(data);
907
+ for (const entry of reputationEntries) {
908
+ // Restore Date objects
909
+ entry.lastUpdated = new Date(entry.lastUpdated);
910
+ for (const listing of entry.blocklist.activeListings) {
911
+ listing.listedSince = new Date(listing.listedSince);
912
+ }
913
+ for (const delisting of entry.blocklist.recentDelistings) {
914
+ delisting.listedFrom = new Date(delisting.listedFrom);
915
+ delisting.listedTo = new Date(delisting.listedTo);
916
+ }
917
+ this.reputationData.set(entry.domain, entry);
918
+ }
919
+ logger.log('info', `Loaded reputation data for ${this.reputationData.size} domains from filesystem`);
920
+ }
921
+ }
922
+ }
923
+ catch (error) {
924
+ logger.log('error', `Failed to load reputation data: ${error.message}`, {
925
+ stack: error.stack
926
+ });
927
+ }
928
+ }
929
+ /**
930
+ * Save reputation data to storage
931
+ */
932
+ async saveReputationData() {
933
+ // Skip saving in test environment to prevent file system race conditions
934
+ const isTestEnvironment = process.env.NODE_ENV === 'test' || !!process.env.JEST_WORKER_ID;
935
+ if (isTestEnvironment) {
936
+ return;
937
+ }
938
+ try {
939
+ const reputationEntries = Array.from(this.reputationData.values());
940
+ // Save to storage manager if available
941
+ if (this.storageManager) {
942
+ await this.storageManager.set('/email/reputation/domain-reputation.json', JSON.stringify(reputationEntries, null, 2));
943
+ logger.log('debug', `Saved reputation data for ${reputationEntries.length} domains to StorageManager`);
944
+ }
945
+ else {
946
+ // No storage manager, use filesystem directly
947
+ const reputationDir = plugins.path.join(paths.dataDir, 'reputation');
948
+ plugins.smartfile.fs.ensureDirSync(reputationDir);
949
+ const dataFile = plugins.path.join(reputationDir, 'domain_reputation.json');
950
+ plugins.smartfile.memory.toFsSync(JSON.stringify(reputationEntries, null, 2), dataFile);
951
+ logger.log('debug', `Saved reputation data for ${reputationEntries.length} domains to filesystem`);
952
+ }
953
+ }
954
+ catch (error) {
955
+ logger.log('error', `Failed to save reputation data: ${error.message}`, {
956
+ stack: error.stack
957
+ });
958
+ }
959
+ }
960
+ }
961
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zZW5kZXJyZXB1dGF0aW9ubW9uaXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2RlbGl2ZXJhYmlsaXR5L2NsYXNzZXMuc2VuZGVycmVwdXRhdGlvbm1vbml0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxLQUFLLEtBQUssTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQTBJdEM7O0dBRUc7QUFDSCxNQUFNLGNBQWMsR0FBdUM7SUFDekQsT0FBTyxFQUFFLElBQUk7SUFDYixPQUFPLEVBQUUsRUFBRTtJQUNYLGVBQWUsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLEVBQUUsUUFBUTtJQUM5QyxXQUFXLEVBQUU7UUFDWCxTQUFTLEVBQUU7WUFDVCxrQkFBa0I7WUFDbEIsZ0JBQWdCO1lBQ2hCLGlCQUFpQjtZQUNqQix3QkFBd0I7U0FDekI7UUFDRCxxQkFBcUIsRUFBRSxJQUFJO0tBQzVCO0lBQ0QsZUFBZSxFQUFFO1FBQ2Ysa0JBQWtCLEVBQUUsRUFBRTtRQUN0QixnQkFBZ0IsRUFBRSxHQUFHLEVBQUUsT0FBTztRQUM5QixhQUFhLEVBQUUsQ0FBQyxFQUFFLEtBQUs7UUFDdkIsV0FBVyxFQUFFLEVBQUUsQ0FBQyxNQUFNO0tBQ3ZCO0NBQ0YsQ0FBQztBQUVGOztHQUVHO0FBQ0gsTUFBTSxPQUFPLHVCQUF1QjtJQVFsQzs7OztPQUlHO0lBQ0gsWUFBWSxTQUFtQyxFQUFFLEVBQUUsY0FBb0I7UUFWL0QsbUJBQWMsR0FBMEMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNsRSxnQkFBVyxHQUFtQixJQUFJLENBQUM7UUFDbkMsa0JBQWEsR0FBWSxLQUFLLENBQUM7UUFTckMsNEJBQTRCO1FBQzVCLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixH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