@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,1454 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import * as paths from '../../paths.js';
3
+ import { EventEmitter } from 'events';
4
+ import { logger } from '../../logger.js';
5
+ import { SecurityLogger, SecurityLogLevel, SecurityEventType } from '../../security/index.js';
6
+ import { DKIMCreator } from '../security/classes.dkimcreator.js';
7
+ import { IPReputationChecker } from '../../security/classes.ipreputationchecker.js';
8
+ import { IPWarmupManager, SenderReputationMonitor } from '../../deliverability/index.js';
9
+ import { EmailRouter } from './classes.email.router.js';
10
+ import { Email } from '../core/classes.email.js';
11
+ import { DomainRegistry } from './classes.domain.registry.js';
12
+ import { DnsManager } from './classes.dns.manager.js';
13
+ import { BounceManager, BounceType, BounceCategory } from '../core/classes.bouncemanager.js';
14
+ import { createSmtpServer } from '../delivery/smtpserver/index.js';
15
+ import { createPooledSmtpClient } from '../delivery/smtpclient/create-client.js';
16
+ import { MultiModeDeliverySystem } from '../delivery/classes.delivery.system.js';
17
+ import { UnifiedDeliveryQueue } from '../delivery/classes.delivery.queue.js';
18
+ import { UnifiedRateLimiter } from '../delivery/classes.unified.rate.limiter.js';
19
+ import { SmtpState } from '../delivery/interfaces.js';
20
+ /**
21
+ * Unified email server that handles all email traffic with pattern-based routing
22
+ */
23
+ export class UnifiedEmailServer extends EventEmitter {
24
+ constructor(dcRouter, options) {
25
+ super();
26
+ this.servers = [];
27
+ this.dkimKeys = new Map(); // domain -> private key
28
+ this.smtpClients = new Map(); // host:port -> client
29
+ this.dcRouter = dcRouter;
30
+ // Set default options
31
+ this.options = {
32
+ ...options,
33
+ banner: options.banner || `${options.hostname} ESMTP UnifiedEmailServer`,
34
+ maxMessageSize: options.maxMessageSize || 10 * 1024 * 1024, // 10MB
35
+ maxClients: options.maxClients || 100,
36
+ maxConnections: options.maxConnections || 1000,
37
+ connectionTimeout: options.connectionTimeout || 60000, // 1 minute
38
+ socketTimeout: options.socketTimeout || 60000 // 1 minute
39
+ };
40
+ // Initialize DKIM creator with storage manager
41
+ this.dkimCreator = new DKIMCreator(paths.keysDir, dcRouter.storageManager);
42
+ // Initialize IP reputation checker with storage manager
43
+ this.ipReputationChecker = IPReputationChecker.getInstance({
44
+ enableLocalCache: true,
45
+ enableDNSBL: true,
46
+ enableIPInfo: true
47
+ }, dcRouter.storageManager);
48
+ // Initialize bounce manager with storage manager
49
+ this.bounceManager = new BounceManager({
50
+ maxCacheSize: 10000,
51
+ cacheTTL: 30 * 24 * 60 * 60 * 1000, // 30 days
52
+ storageManager: dcRouter.storageManager
53
+ });
54
+ // Initialize IP warmup manager
55
+ this.ipWarmupManager = IPWarmupManager.getInstance(options.ipWarmupConfig || {
56
+ enabled: true,
57
+ ipAddresses: [],
58
+ targetDomains: []
59
+ });
60
+ // Initialize sender reputation monitor with storage manager
61
+ this.senderReputationMonitor = SenderReputationMonitor.getInstance(options.reputationMonitorConfig || {
62
+ enabled: true,
63
+ domains: []
64
+ }, dcRouter.storageManager);
65
+ // Initialize domain registry
66
+ this.domainRegistry = new DomainRegistry(options.domains, options.defaults);
67
+ // Initialize email router with routes and storage manager
68
+ this.emailRouter = new EmailRouter(options.routes || [], {
69
+ storageManager: dcRouter.storageManager,
70
+ persistChanges: true
71
+ });
72
+ // Initialize rate limiter
73
+ this.rateLimiter = new UnifiedRateLimiter(options.rateLimits || {
74
+ global: {
75
+ maxConnectionsPerIP: 10,
76
+ maxMessagesPerMinute: 100,
77
+ maxRecipientsPerMessage: 50,
78
+ maxErrorsPerIP: 10,
79
+ maxAuthFailuresPerIP: 5,
80
+ blockDuration: 300000 // 5 minutes
81
+ }
82
+ });
83
+ // Initialize delivery components
84
+ const queueOptions = {
85
+ storageType: 'memory', // Default to memory storage
86
+ maxRetries: 3,
87
+ baseRetryDelay: 300000, // 5 minutes
88
+ maxRetryDelay: 3600000 // 1 hour
89
+ };
90
+ this.deliveryQueue = new UnifiedDeliveryQueue(queueOptions);
91
+ const deliveryOptions = {
92
+ globalRateLimit: 100, // Default to 100 emails per minute
93
+ concurrentDeliveries: 10,
94
+ processBounces: true,
95
+ bounceHandler: {
96
+ processSmtpFailure: this.processSmtpFailure.bind(this)
97
+ },
98
+ onDeliverySuccess: async (item, _result) => {
99
+ // Record delivery success event for reputation monitoring
100
+ const email = item.processingResult;
101
+ const senderDomain = email.from.split('@')[1];
102
+ if (senderDomain) {
103
+ this.recordReputationEvent(senderDomain, {
104
+ type: 'delivered',
105
+ count: email.to.length
106
+ });
107
+ }
108
+ }
109
+ };
110
+ this.deliverySystem = new MultiModeDeliverySystem(this.deliveryQueue, deliveryOptions, this);
111
+ // Initialize statistics
112
+ this.stats = {
113
+ startTime: new Date(),
114
+ connections: {
115
+ current: 0,
116
+ total: 0
117
+ },
118
+ messages: {
119
+ processed: 0,
120
+ delivered: 0,
121
+ failed: 0
122
+ },
123
+ processingTime: {
124
+ avg: 0,
125
+ max: 0,
126
+ min: 0
127
+ }
128
+ };
129
+ // We'll create the SMTP servers during the start() method
130
+ }
131
+ /**
132
+ * Get or create an SMTP client for the given host and port
133
+ * Uses connection pooling for efficiency
134
+ */
135
+ getSmtpClient(host, port = 25) {
136
+ const clientKey = `${host}:${port}`;
137
+ // Check if we already have a client for this destination
138
+ let client = this.smtpClients.get(clientKey);
139
+ if (!client) {
140
+ // Create a new pooled SMTP client
141
+ client = createPooledSmtpClient({
142
+ host,
143
+ port,
144
+ secure: port === 465,
145
+ connectionTimeout: this.options.outbound?.connectionTimeout || 30000,
146
+ socketTimeout: this.options.outbound?.socketTimeout || 120000,
147
+ maxConnections: this.options.outbound?.maxConnections || 10,
148
+ maxMessages: 1000, // Messages per connection before reconnect
149
+ pool: true,
150
+ debug: false
151
+ });
152
+ this.smtpClients.set(clientKey, client);
153
+ logger.log('info', `Created new SMTP client pool for ${clientKey}`);
154
+ }
155
+ return client;
156
+ }
157
+ /**
158
+ * Start the unified email server
159
+ */
160
+ async start() {
161
+ logger.log('info', `Starting UnifiedEmailServer on ports: ${this.options.ports.join(', ')}`);
162
+ try {
163
+ // Initialize the delivery queue
164
+ await this.deliveryQueue.initialize();
165
+ logger.log('info', 'Email delivery queue initialized');
166
+ // Start the delivery system
167
+ await this.deliverySystem.start();
168
+ logger.log('info', 'Email delivery system started');
169
+ // Set up DKIM for all domains
170
+ await this.setupDkimForDomains();
171
+ logger.log('info', 'DKIM configuration completed for all domains');
172
+ // Create DNS manager and ensure all DNS records are created
173
+ const dnsManager = new DnsManager(this.dcRouter);
174
+ await dnsManager.ensureDnsRecords(this.domainRegistry.getAllConfigs(), this.dkimCreator);
175
+ logger.log('info', 'DNS records ensured for all configured domains');
176
+ // Apply per-domain rate limits
177
+ this.applyDomainRateLimits();
178
+ logger.log('info', 'Per-domain rate limits configured');
179
+ // Check and rotate DKIM keys if needed
180
+ await this.checkAndRotateDkimKeys();
181
+ logger.log('info', 'DKIM key rotation check completed');
182
+ // Skip server creation in socket-handler mode
183
+ if (this.options.useSocketHandler) {
184
+ logger.log('info', 'UnifiedEmailServer started in socket-handler mode (no port listening)');
185
+ this.emit('started');
186
+ return;
187
+ }
188
+ // Ensure we have the necessary TLS options
189
+ const hasTlsConfig = this.options.tls?.keyPath && this.options.tls?.certPath;
190
+ // Prepare the certificate and key if available
191
+ let key;
192
+ let cert;
193
+ if (hasTlsConfig) {
194
+ try {
195
+ key = plugins.fs.readFileSync(this.options.tls.keyPath, 'utf8');
196
+ cert = plugins.fs.readFileSync(this.options.tls.certPath, 'utf8');
197
+ logger.log('info', 'TLS certificates loaded successfully');
198
+ }
199
+ catch (error) {
200
+ logger.log('warn', `Failed to load TLS certificates: ${error.message}`);
201
+ }
202
+ }
203
+ // Create a SMTP server for each port
204
+ for (const port of this.options.ports) {
205
+ // Create a reference object to hold the MTA service during setup
206
+ const mtaRef = {
207
+ config: {
208
+ smtp: {
209
+ hostname: this.options.hostname
210
+ },
211
+ security: {
212
+ checkIPReputation: false,
213
+ verifyDkim: true,
214
+ verifySpf: true,
215
+ verifyDmarc: true
216
+ }
217
+ },
218
+ // These will be implemented in the real integration:
219
+ dkimVerifier: {
220
+ verify: async () => ({ isValid: true, domain: '' })
221
+ },
222
+ spfVerifier: {
223
+ verifyAndApply: async () => true
224
+ },
225
+ dmarcVerifier: {
226
+ verify: async () => ({}),
227
+ applyPolicy: () => true
228
+ },
229
+ processIncomingEmail: async (email) => {
230
+ // Process email using the new route-based system
231
+ await this.processEmailByMode(email, {
232
+ id: 'session-' + Math.random().toString(36).substring(2),
233
+ state: SmtpState.FINISHED,
234
+ mailFrom: email.from,
235
+ rcptTo: email.to,
236
+ emailData: email.toRFC822String(), // Use the proper method to get the full email content
237
+ useTLS: false,
238
+ connectionEnded: true,
239
+ remoteAddress: '127.0.0.1',
240
+ clientHostname: '',
241
+ secure: false,
242
+ authenticated: false,
243
+ envelope: {
244
+ mailFrom: { address: email.from, args: {} },
245
+ rcptTo: email.to.map(recipient => ({ address: recipient, args: {} }))
246
+ }
247
+ });
248
+ return true;
249
+ }
250
+ };
251
+ // Create server options
252
+ const serverOptions = {
253
+ port,
254
+ hostname: this.options.hostname,
255
+ key,
256
+ cert
257
+ };
258
+ // Create and start the SMTP server
259
+ const smtpServer = createSmtpServer(mtaRef, serverOptions);
260
+ this.servers.push(smtpServer);
261
+ // Start the server
262
+ await new Promise((resolve, reject) => {
263
+ try {
264
+ // Leave this empty for now, smtpServer.start() is handled by the SMTPServer class internally
265
+ // The server is started when it's created
266
+ logger.log('info', `UnifiedEmailServer listening on port ${port}`);
267
+ // Event handlers are managed internally by the SmtpServer class
268
+ // No need to access the private server property
269
+ resolve();
270
+ }
271
+ catch (err) {
272
+ if (err.code === 'EADDRINUSE') {
273
+ logger.log('error', `Port ${port} is already in use`);
274
+ reject(new Error(`Port ${port} is already in use`));
275
+ }
276
+ else {
277
+ logger.log('error', `Error starting server on port ${port}: ${err.message}`);
278
+ reject(err);
279
+ }
280
+ }
281
+ });
282
+ }
283
+ logger.log('info', 'UnifiedEmailServer started successfully');
284
+ this.emit('started');
285
+ }
286
+ catch (error) {
287
+ logger.log('error', `Failed to start UnifiedEmailServer: ${error.message}`);
288
+ throw error;
289
+ }
290
+ }
291
+ /**
292
+ * Handle a socket from smartproxy in socket-handler mode
293
+ * @param socket The socket to handle
294
+ * @param port The port this connection is for (25, 587, 465)
295
+ */
296
+ async handleSocket(socket, port) {
297
+ if (!this.options.useSocketHandler) {
298
+ logger.log('error', 'handleSocket called but useSocketHandler is not enabled');
299
+ socket.destroy();
300
+ return;
301
+ }
302
+ logger.log('info', `Handling socket for port ${port}`);
303
+ // Create a temporary SMTP server instance for this connection
304
+ // We need a full server instance because the SMTP protocol handler needs all components
305
+ const smtpServerOptions = {
306
+ port,
307
+ hostname: this.options.hostname,
308
+ key: this.options.tls?.keyPath ? plugins.fs.readFileSync(this.options.tls.keyPath, 'utf8') : undefined,
309
+ cert: this.options.tls?.certPath ? plugins.fs.readFileSync(this.options.tls.certPath, 'utf8') : undefined
310
+ };
311
+ // Create the SMTP server instance
312
+ const smtpServer = createSmtpServer(this, smtpServerOptions);
313
+ // Get the connection manager from the server
314
+ const connectionManager = smtpServer.connectionManager;
315
+ if (!connectionManager) {
316
+ logger.log('error', 'Could not get connection manager from SMTP server');
317
+ socket.destroy();
318
+ return;
319
+ }
320
+ // Determine if this is a secure connection
321
+ // Port 465 uses implicit TLS, so the socket is already secure
322
+ const isSecure = port === 465 || socket instanceof plugins.tls.TLSSocket;
323
+ // Pass the socket to the connection manager
324
+ try {
325
+ await connectionManager.handleConnection(socket, isSecure);
326
+ }
327
+ catch (error) {
328
+ logger.log('error', `Error handling socket connection: ${error.message}`);
329
+ socket.destroy();
330
+ }
331
+ }
332
+ /**
333
+ * Stop the unified email server
334
+ */
335
+ async stop() {
336
+ logger.log('info', 'Stopping UnifiedEmailServer');
337
+ try {
338
+ // Clear the servers array - servers will be garbage collected
339
+ this.servers = [];
340
+ // Stop the delivery system
341
+ if (this.deliverySystem) {
342
+ await this.deliverySystem.stop();
343
+ logger.log('info', 'Email delivery system stopped');
344
+ }
345
+ // Shut down the delivery queue
346
+ if (this.deliveryQueue) {
347
+ await this.deliveryQueue.shutdown();
348
+ logger.log('info', 'Email delivery queue shut down');
349
+ }
350
+ // Close all SMTP client connections
351
+ for (const [clientKey, client] of this.smtpClients) {
352
+ try {
353
+ await client.close();
354
+ logger.log('info', `Closed SMTP client pool for ${clientKey}`);
355
+ }
356
+ catch (error) {
357
+ logger.log('warn', `Error closing SMTP client for ${clientKey}: ${error.message}`);
358
+ }
359
+ }
360
+ this.smtpClients.clear();
361
+ logger.log('info', 'UnifiedEmailServer stopped successfully');
362
+ this.emit('stopped');
363
+ }
364
+ catch (error) {
365
+ logger.log('error', `Error stopping UnifiedEmailServer: ${error.message}`);
366
+ throw error;
367
+ }
368
+ }
369
+ /**
370
+ * Process email based on routing rules
371
+ */
372
+ async processEmailByMode(emailData, session) {
373
+ // Convert Buffer to Email if needed
374
+ let email;
375
+ if (Buffer.isBuffer(emailData)) {
376
+ // Parse the email data buffer into an Email object
377
+ try {
378
+ const parsed = await plugins.mailparser.simpleParser(emailData);
379
+ email = new Email({
380
+ from: parsed.from?.value[0]?.address || session.envelope.mailFrom.address,
381
+ to: session.envelope.rcptTo[0]?.address || '',
382
+ subject: parsed.subject || '',
383
+ text: parsed.text || '',
384
+ html: parsed.html || undefined,
385
+ attachments: parsed.attachments?.map(att => ({
386
+ filename: att.filename || '',
387
+ content: att.content,
388
+ contentType: att.contentType
389
+ })) || []
390
+ });
391
+ }
392
+ catch (error) {
393
+ logger.log('error', `Error parsing email data: ${error.message}`);
394
+ throw new Error(`Error parsing email data: ${error.message}`);
395
+ }
396
+ }
397
+ else {
398
+ email = emailData;
399
+ }
400
+ // First check if this is a bounce notification email
401
+ // Look for common bounce notification subject patterns
402
+ const subject = email.subject || '';
403
+ const isBounceLike = /mail delivery|delivery (failed|status|notification)|failure notice|returned mail|undeliverable|delivery problem/i.test(subject);
404
+ if (isBounceLike) {
405
+ logger.log('info', `Email subject matches bounce notification pattern: "${subject}"`);
406
+ // Try to process as a bounce
407
+ const isBounce = await this.processBounceNotification(email);
408
+ if (isBounce) {
409
+ logger.log('info', 'Successfully processed as bounce notification, skipping regular processing');
410
+ return email;
411
+ }
412
+ logger.log('info', 'Not a valid bounce notification, continuing with regular processing');
413
+ }
414
+ // Find matching route
415
+ const context = { email, session };
416
+ const route = await this.emailRouter.evaluateRoutes(context);
417
+ if (!route) {
418
+ // No matching route - reject
419
+ throw new Error('No matching route for email');
420
+ }
421
+ // Store matched route in session
422
+ session.matchedRoute = route;
423
+ // Execute action based on route
424
+ await this.executeAction(route.action, email, context);
425
+ // Return the processed email
426
+ return email;
427
+ }
428
+ /**
429
+ * Execute action based on route configuration
430
+ */
431
+ async executeAction(action, email, context) {
432
+ switch (action.type) {
433
+ case 'forward':
434
+ await this.handleForwardAction(action, email, context);
435
+ break;
436
+ case 'process':
437
+ await this.handleProcessAction(action, email, context);
438
+ break;
439
+ case 'deliver':
440
+ await this.handleDeliverAction(action, email, context);
441
+ break;
442
+ case 'reject':
443
+ await this.handleRejectAction(action, email, context);
444
+ break;
445
+ default:
446
+ throw new Error(`Unknown action type: ${action.type}`);
447
+ }
448
+ }
449
+ /**
450
+ * Handle forward action
451
+ */
452
+ async handleForwardAction(_action, email, context) {
453
+ if (!_action.forward) {
454
+ throw new Error('Forward action requires forward configuration');
455
+ }
456
+ const { host, port = 25, auth, addHeaders } = _action.forward;
457
+ logger.log('info', `Forwarding email to ${host}:${port}`);
458
+ // Add forwarding headers
459
+ if (addHeaders) {
460
+ for (const [key, value] of Object.entries(addHeaders)) {
461
+ email.headers[key] = value;
462
+ }
463
+ }
464
+ // Add standard forwarding headers
465
+ email.headers['X-Forwarded-For'] = context.session.remoteAddress || 'unknown';
466
+ email.headers['X-Forwarded-To'] = email.to.join(', ');
467
+ email.headers['X-Forwarded-Date'] = new Date().toISOString();
468
+ // Get SMTP client
469
+ const client = this.getSmtpClient(host, port);
470
+ try {
471
+ // Send email
472
+ await client.sendMail(email);
473
+ logger.log('info', `Successfully forwarded email to ${host}:${port}`);
474
+ SecurityLogger.getInstance().logEvent({
475
+ level: SecurityLogLevel.INFO,
476
+ type: SecurityEventType.EMAIL_FORWARDING,
477
+ message: 'Email forwarded successfully',
478
+ ipAddress: context.session.remoteAddress,
479
+ details: {
480
+ sessionId: context.session.id,
481
+ routeName: context.session.matchedRoute?.name,
482
+ targetHost: host,
483
+ targetPort: port,
484
+ recipients: email.to
485
+ },
486
+ success: true
487
+ });
488
+ }
489
+ catch (error) {
490
+ logger.log('error', `Failed to forward email: ${error.message}`);
491
+ SecurityLogger.getInstance().logEvent({
492
+ level: SecurityLogLevel.ERROR,
493
+ type: SecurityEventType.EMAIL_FORWARDING,
494
+ message: 'Email forwarding failed',
495
+ ipAddress: context.session.remoteAddress,
496
+ details: {
497
+ sessionId: context.session.id,
498
+ routeName: context.session.matchedRoute?.name,
499
+ targetHost: host,
500
+ targetPort: port,
501
+ error: error.message
502
+ },
503
+ success: false
504
+ });
505
+ // Handle as bounce
506
+ for (const recipient of email.getAllRecipients()) {
507
+ await this.bounceManager.processSmtpFailure(recipient, error.message, {
508
+ sender: email.from,
509
+ originalEmailId: email.headers['Message-ID']
510
+ });
511
+ }
512
+ throw error;
513
+ }
514
+ }
515
+ /**
516
+ * Handle process action
517
+ */
518
+ async handleProcessAction(action, email, context) {
519
+ logger.log('info', `Processing email with action options`);
520
+ // Apply scanning if requested
521
+ if (action.process?.scan) {
522
+ // Use existing content scanner
523
+ // Note: ContentScanner integration would go here
524
+ logger.log('info', 'Content scanning requested');
525
+ }
526
+ // Note: DKIM signing will be applied at delivery time to ensure signature validity
527
+ // Queue for delivery
528
+ const queue = action.process?.queue || 'normal';
529
+ await this.deliveryQueue.enqueue(email, 'process', context.session.matchedRoute);
530
+ logger.log('info', `Email queued for delivery in ${queue} queue`);
531
+ }
532
+ /**
533
+ * Handle deliver action
534
+ */
535
+ async handleDeliverAction(_action, email, context) {
536
+ logger.log('info', `Delivering email locally`);
537
+ // Queue for local delivery
538
+ await this.deliveryQueue.enqueue(email, 'mta', context.session.matchedRoute);
539
+ logger.log('info', 'Email queued for local delivery');
540
+ }
541
+ /**
542
+ * Handle reject action
543
+ */
544
+ async handleRejectAction(action, email, context) {
545
+ const code = action.reject?.code || 550;
546
+ const message = action.reject?.message || 'Message rejected';
547
+ logger.log('info', `Rejecting email with code ${code}: ${message}`);
548
+ SecurityLogger.getInstance().logEvent({
549
+ level: SecurityLogLevel.WARN,
550
+ type: SecurityEventType.EMAIL_PROCESSING,
551
+ message: 'Email rejected by routing rule',
552
+ ipAddress: context.session.remoteAddress,
553
+ details: {
554
+ sessionId: context.session.id,
555
+ routeName: context.session.matchedRoute?.name,
556
+ rejectCode: code,
557
+ rejectMessage: message,
558
+ from: email.from,
559
+ to: email.to
560
+ },
561
+ success: false
562
+ });
563
+ // Throw error with SMTP code and message
564
+ const error = new Error(message);
565
+ error.responseCode = code;
566
+ throw error;
567
+ }
568
+ /**
569
+ * Handle email in MTA mode (programmatic processing)
570
+ */
571
+ async _handleMtaMode(email, session) {
572
+ logger.log('info', `Handling email in MTA mode for session ${session.id}`);
573
+ try {
574
+ // Apply MTA rule options if provided
575
+ if (session.matchedRoute?.action.options?.mtaOptions) {
576
+ const options = session.matchedRoute.action.options.mtaOptions;
577
+ // Apply DKIM signing if enabled
578
+ if (options.dkimSign && options.dkimOptions) {
579
+ // Sign the email with DKIM
580
+ logger.log('info', `Signing email with DKIM for domain ${options.dkimOptions.domainName}`);
581
+ try {
582
+ // Ensure DKIM keys exist for the domain
583
+ await this.dkimCreator.handleDKIMKeysForDomain(options.dkimOptions.domainName);
584
+ // Convert Email to raw format for signing
585
+ const rawEmail = email.toRFC822String();
586
+ // Create headers object
587
+ const headers = {};
588
+ for (const [key, value] of Object.entries(email.headers)) {
589
+ headers[key] = value;
590
+ }
591
+ // Sign the email
592
+ const signResult = await plugins.dkimSign(rawEmail, {
593
+ canonicalization: 'relaxed/relaxed',
594
+ algorithm: 'rsa-sha256',
595
+ signTime: new Date(),
596
+ signatureData: [
597
+ {
598
+ signingDomain: options.dkimOptions.domainName,
599
+ selector: options.dkimOptions.keySelector || 'mta',
600
+ privateKey: (await this.dkimCreator.readDKIMKeys(options.dkimOptions.domainName)).privateKey,
601
+ algorithm: 'rsa-sha256',
602
+ canonicalization: 'relaxed/relaxed'
603
+ }
604
+ ]
605
+ });
606
+ // Add the DKIM-Signature header to the email
607
+ if (signResult.signatures) {
608
+ email.addHeader('DKIM-Signature', signResult.signatures);
609
+ logger.log('info', `Successfully added DKIM signature for ${options.dkimOptions.domainName}`);
610
+ }
611
+ }
612
+ catch (error) {
613
+ logger.log('error', `Failed to sign email with DKIM: ${error.message}`);
614
+ }
615
+ }
616
+ }
617
+ // Get email content for logging/processing
618
+ const subject = email.subject;
619
+ const recipients = email.getAllRecipients().join(', ');
620
+ logger.log('info', `Email processed by MTA: ${subject} to ${recipients}`);
621
+ SecurityLogger.getInstance().logEvent({
622
+ level: SecurityLogLevel.INFO,
623
+ type: SecurityEventType.EMAIL_PROCESSING,
624
+ message: 'Email processed by MTA',
625
+ ipAddress: session.remoteAddress,
626
+ details: {
627
+ sessionId: session.id,
628
+ ruleName: session.matchedRoute?.name || 'default',
629
+ subject,
630
+ recipients
631
+ },
632
+ success: true
633
+ });
634
+ }
635
+ catch (error) {
636
+ logger.log('error', `Failed to process email in MTA mode: ${error.message}`);
637
+ SecurityLogger.getInstance().logEvent({
638
+ level: SecurityLogLevel.ERROR,
639
+ type: SecurityEventType.EMAIL_PROCESSING,
640
+ message: 'MTA processing failed',
641
+ ipAddress: session.remoteAddress,
642
+ details: {
643
+ sessionId: session.id,
644
+ ruleName: session.matchedRoute?.name || 'default',
645
+ error: error.message
646
+ },
647
+ success: false
648
+ });
649
+ throw error;
650
+ }
651
+ }
652
+ /**
653
+ * Handle email in process mode (store-and-forward with scanning)
654
+ */
655
+ async _handleProcessMode(email, session) {
656
+ logger.log('info', `Handling email in process mode for session ${session.id}`);
657
+ try {
658
+ const route = session.matchedRoute;
659
+ // Apply content scanning if enabled
660
+ if (route?.action.options?.contentScanning && route.action.options.scanners && route.action.options.scanners.length > 0) {
661
+ logger.log('info', 'Performing content scanning');
662
+ // Apply each scanner
663
+ for (const scanner of route.action.options.scanners) {
664
+ switch (scanner.type) {
665
+ case 'spam':
666
+ logger.log('info', 'Scanning for spam content');
667
+ // Implement spam scanning
668
+ break;
669
+ case 'virus':
670
+ logger.log('info', 'Scanning for virus content');
671
+ // Implement virus scanning
672
+ break;
673
+ case 'attachment':
674
+ logger.log('info', 'Scanning attachments');
675
+ // Check for blocked extensions
676
+ if (scanner.blockedExtensions && scanner.blockedExtensions.length > 0) {
677
+ for (const attachment of email.attachments) {
678
+ const ext = this.getFileExtension(attachment.filename);
679
+ if (scanner.blockedExtensions.includes(ext)) {
680
+ if (scanner.action === 'reject') {
681
+ throw new Error(`Blocked attachment type: ${ext}`);
682
+ }
683
+ else { // tag
684
+ email.addHeader('X-Attachment-Warning', `Potentially unsafe attachment: ${attachment.filename}`);
685
+ }
686
+ }
687
+ }
688
+ }
689
+ break;
690
+ }
691
+ }
692
+ }
693
+ // Apply transformations if defined
694
+ if (route?.action.options?.transformations && route.action.options.transformations.length > 0) {
695
+ logger.log('info', 'Applying email transformations');
696
+ for (const transform of route.action.options.transformations) {
697
+ switch (transform.type) {
698
+ case 'addHeader':
699
+ if (transform.header && transform.value) {
700
+ email.addHeader(transform.header, transform.value);
701
+ }
702
+ break;
703
+ }
704
+ }
705
+ }
706
+ logger.log('info', `Email successfully processed in store-and-forward mode`);
707
+ SecurityLogger.getInstance().logEvent({
708
+ level: SecurityLogLevel.INFO,
709
+ type: SecurityEventType.EMAIL_PROCESSING,
710
+ message: 'Email processed and queued',
711
+ ipAddress: session.remoteAddress,
712
+ details: {
713
+ sessionId: session.id,
714
+ ruleName: route?.name || 'default',
715
+ contentScanning: route?.action.options?.contentScanning || false,
716
+ subject: email.subject
717
+ },
718
+ success: true
719
+ });
720
+ }
721
+ catch (error) {
722
+ logger.log('error', `Failed to process email: ${error.message}`);
723
+ SecurityLogger.getInstance().logEvent({
724
+ level: SecurityLogLevel.ERROR,
725
+ type: SecurityEventType.EMAIL_PROCESSING,
726
+ message: 'Email processing failed',
727
+ ipAddress: session.remoteAddress,
728
+ details: {
729
+ sessionId: session.id,
730
+ ruleName: session.matchedRoute?.name || 'default',
731
+ error: error.message
732
+ },
733
+ success: false
734
+ });
735
+ throw error;
736
+ }
737
+ }
738
+ /**
739
+ * Get file extension from filename
740
+ */
741
+ getFileExtension(filename) {
742
+ return filename.substring(filename.lastIndexOf('.')).toLowerCase();
743
+ }
744
+ /**
745
+ * Set up DKIM configuration for all domains
746
+ */
747
+ async setupDkimForDomains() {
748
+ const domainConfigs = this.domainRegistry.getAllConfigs();
749
+ if (domainConfigs.length === 0) {
750
+ logger.log('warn', 'No domains configured for DKIM');
751
+ return;
752
+ }
753
+ for (const domainConfig of domainConfigs) {
754
+ const domain = domainConfig.domain;
755
+ const selector = domainConfig.dkim?.selector || 'default';
756
+ try {
757
+ // Check if DKIM keys already exist for this domain
758
+ let keyPair;
759
+ try {
760
+ // Try to read existing keys
761
+ keyPair = await this.dkimCreator.readDKIMKeys(domain);
762
+ logger.log('info', `Using existing DKIM keys for domain: ${domain}`);
763
+ }
764
+ catch (error) {
765
+ // Generate new keys if they don't exist
766
+ keyPair = await this.dkimCreator.createDKIMKeys();
767
+ // Store them for future use
768
+ await this.dkimCreator.createAndStoreDKIMKeys(domain);
769
+ logger.log('info', `Generated new DKIM keys for domain: ${domain}`);
770
+ }
771
+ // Store the private key for signing
772
+ this.dkimKeys.set(domain, keyPair.privateKey);
773
+ // DNS record creation is now handled by DnsManager
774
+ logger.log('info', `DKIM keys loaded for domain: ${domain} with selector: ${selector}`);
775
+ }
776
+ catch (error) {
777
+ logger.log('error', `Failed to set up DKIM for domain ${domain}: ${error.message}`);
778
+ }
779
+ }
780
+ }
781
+ /**
782
+ * Apply per-domain rate limits from domain configurations
783
+ */
784
+ applyDomainRateLimits() {
785
+ const domainConfigs = this.domainRegistry.getAllConfigs();
786
+ for (const domainConfig of domainConfigs) {
787
+ if (domainConfig.rateLimits) {
788
+ const domain = domainConfig.domain;
789
+ const rateLimitConfig = {};
790
+ // Convert domain-specific rate limits to the format expected by UnifiedRateLimiter
791
+ if (domainConfig.rateLimits.outbound) {
792
+ if (domainConfig.rateLimits.outbound.messagesPerMinute) {
793
+ rateLimitConfig.maxMessagesPerMinute = domainConfig.rateLimits.outbound.messagesPerMinute;
794
+ }
795
+ // Note: messagesPerHour and messagesPerDay would need additional implementation in rate limiter
796
+ }
797
+ if (domainConfig.rateLimits.inbound) {
798
+ if (domainConfig.rateLimits.inbound.messagesPerMinute) {
799
+ rateLimitConfig.maxMessagesPerMinute = domainConfig.rateLimits.inbound.messagesPerMinute;
800
+ }
801
+ if (domainConfig.rateLimits.inbound.connectionsPerIp) {
802
+ rateLimitConfig.maxConnectionsPerIP = domainConfig.rateLimits.inbound.connectionsPerIp;
803
+ }
804
+ if (domainConfig.rateLimits.inbound.recipientsPerMessage) {
805
+ rateLimitConfig.maxRecipientsPerMessage = domainConfig.rateLimits.inbound.recipientsPerMessage;
806
+ }
807
+ }
808
+ // Apply the rate limits if we have any
809
+ if (Object.keys(rateLimitConfig).length > 0) {
810
+ this.rateLimiter.applyDomainLimits(domain, rateLimitConfig);
811
+ logger.log('info', `Applied rate limits for domain ${domain}:`, rateLimitConfig);
812
+ }
813
+ }
814
+ }
815
+ }
816
+ /**
817
+ * Check and rotate DKIM keys if needed
818
+ */
819
+ async checkAndRotateDkimKeys() {
820
+ const domainConfigs = this.domainRegistry.getAllConfigs();
821
+ for (const domainConfig of domainConfigs) {
822
+ const domain = domainConfig.domain;
823
+ const selector = domainConfig.dkim?.selector || 'default';
824
+ const rotateKeys = domainConfig.dkim?.rotateKeys || false;
825
+ const rotationInterval = domainConfig.dkim?.rotationInterval || 90;
826
+ const keySize = domainConfig.dkim?.keySize || 2048;
827
+ if (!rotateKeys) {
828
+ logger.log('debug', `DKIM key rotation disabled for ${domain}`);
829
+ continue;
830
+ }
831
+ try {
832
+ // Check if keys need rotation
833
+ const needsRotation = await this.dkimCreator.needsRotation(domain, selector, rotationInterval);
834
+ if (needsRotation) {
835
+ logger.log('info', `DKIM keys need rotation for ${domain} (selector: ${selector})`);
836
+ // Rotate the keys
837
+ const newSelector = await this.dkimCreator.rotateDkimKeys(domain, selector, keySize);
838
+ // Update the domain config with new selector
839
+ domainConfig.dkim = {
840
+ ...domainConfig.dkim,
841
+ selector: newSelector
842
+ };
843
+ // Re-register DNS handler for new selector if internal-dns mode
844
+ if (domainConfig.dnsMode === 'internal-dns' && this.dcRouter.dnsServer) {
845
+ // Get new public key
846
+ const keyPair = await this.dkimCreator.readDKIMKeysForSelector(domain, newSelector);
847
+ const publicKeyBase64 = keyPair.publicKey
848
+ .replace(/-----BEGIN PUBLIC KEY-----/g, '')
849
+ .replace(/-----END PUBLIC KEY-----/g, '')
850
+ .replace(/\s/g, '');
851
+ const ttl = domainConfig.dns?.internal?.ttl || 3600;
852
+ // Register new selector
853
+ this.dcRouter.dnsServer.registerHandler(`${newSelector}._domainkey.${domain}`, ['TXT'], () => ({
854
+ name: `${newSelector}._domainkey.${domain}`,
855
+ type: 'TXT',
856
+ class: 'IN',
857
+ ttl: ttl,
858
+ data: `v=DKIM1; k=rsa; p=${publicKeyBase64}`
859
+ }));
860
+ logger.log('info', `DKIM DNS handler registered for new selector: ${newSelector}._domainkey.${domain}`);
861
+ // Store the updated public key in storage
862
+ await this.dcRouter.storageManager.set(`/email/dkim/${domain}/public.key`, keyPair.publicKey);
863
+ }
864
+ // Clean up old keys after grace period (async, don't wait)
865
+ this.dkimCreator.cleanupOldKeys(domain, 30).catch(error => {
866
+ logger.log('warn', `Failed to cleanup old DKIM keys for ${domain}: ${error.message}`);
867
+ });
868
+ }
869
+ else {
870
+ logger.log('debug', `DKIM keys for ${domain} are up to date`);
871
+ }
872
+ }
873
+ catch (error) {
874
+ logger.log('error', `Failed to check/rotate DKIM keys for ${domain}: ${error.message}`);
875
+ }
876
+ }
877
+ }
878
+ /**
879
+ * Generate SmartProxy routes for email ports
880
+ */
881
+ generateProxyRoutes(portMapping) {
882
+ const routes = [];
883
+ const defaultPortMapping = {
884
+ 25: 10025,
885
+ 587: 10587,
886
+ 465: 10465
887
+ };
888
+ const actualPortMapping = portMapping || defaultPortMapping;
889
+ // Generate routes for each configured port
890
+ for (const externalPort of this.options.ports) {
891
+ const internalPort = actualPortMapping[externalPort] || externalPort + 10000;
892
+ let routeName = 'email-route';
893
+ let tlsMode = 'passthrough';
894
+ // Configure based on port
895
+ switch (externalPort) {
896
+ case 25:
897
+ routeName = 'smtp-route';
898
+ tlsMode = 'passthrough'; // STARTTLS
899
+ break;
900
+ case 587:
901
+ routeName = 'submission-route';
902
+ tlsMode = 'passthrough'; // STARTTLS
903
+ break;
904
+ case 465:
905
+ routeName = 'smtps-route';
906
+ tlsMode = 'terminate'; // Implicit TLS
907
+ break;
908
+ default:
909
+ routeName = `email-port-${externalPort}-route`;
910
+ }
911
+ routes.push({
912
+ name: routeName,
913
+ match: {
914
+ ports: [externalPort]
915
+ },
916
+ action: {
917
+ type: 'forward',
918
+ target: {
919
+ host: 'localhost',
920
+ port: internalPort
921
+ },
922
+ tls: {
923
+ mode: tlsMode
924
+ }
925
+ }
926
+ });
927
+ }
928
+ return routes;
929
+ }
930
+ /**
931
+ * Update server configuration
932
+ */
933
+ updateOptions(options) {
934
+ // Stop the server if changing ports
935
+ const portsChanged = options.ports &&
936
+ (!this.options.ports ||
937
+ JSON.stringify(options.ports) !== JSON.stringify(this.options.ports));
938
+ if (portsChanged) {
939
+ this.stop().then(() => {
940
+ this.options = { ...this.options, ...options };
941
+ this.start();
942
+ });
943
+ }
944
+ else {
945
+ // Update options without restart
946
+ this.options = { ...this.options, ...options };
947
+ // Update domain registry if domains changed
948
+ if (options.domains) {
949
+ this.domainRegistry = new DomainRegistry(options.domains, options.defaults || this.options.defaults);
950
+ }
951
+ // Update email router if routes changed
952
+ if (options.routes) {
953
+ this.emailRouter.updateRoutes(options.routes);
954
+ }
955
+ }
956
+ }
957
+ /**
958
+ * Update email routes
959
+ */
960
+ updateEmailRoutes(routes) {
961
+ this.options.routes = routes;
962
+ this.emailRouter.updateRoutes(routes);
963
+ }
964
+ /**
965
+ * Get server statistics
966
+ */
967
+ getStats() {
968
+ return { ...this.stats };
969
+ }
970
+ /**
971
+ * Get domain registry
972
+ */
973
+ getDomainRegistry() {
974
+ return this.domainRegistry;
975
+ }
976
+ /**
977
+ * Update email routes dynamically
978
+ */
979
+ updateRoutes(routes) {
980
+ this.emailRouter.setRoutes(routes);
981
+ logger.log('info', `Updated email routes with ${routes.length} routes`);
982
+ }
983
+ /**
984
+ * Send an email through the delivery system
985
+ * @param email The email to send
986
+ * @param mode The processing mode to use
987
+ * @param rule Optional rule to apply
988
+ * @param options Optional sending options
989
+ * @returns The ID of the queued email
990
+ */
991
+ async sendEmail(email, mode = 'mta', route, options) {
992
+ logger.log('info', `Sending email: ${email.subject} to ${email.to.join(', ')}`);
993
+ try {
994
+ // Validate the email
995
+ if (!email.from) {
996
+ throw new Error('Email must have a sender address');
997
+ }
998
+ if (!email.to || email.to.length === 0) {
999
+ throw new Error('Email must have at least one recipient');
1000
+ }
1001
+ // Check if any recipients are on the suppression list (unless explicitly skipped)
1002
+ if (!options?.skipSuppressionCheck) {
1003
+ const suppressedRecipients = email.to.filter(recipient => this.isEmailSuppressed(recipient));
1004
+ if (suppressedRecipients.length > 0) {
1005
+ // Filter out suppressed recipients
1006
+ const originalCount = email.to.length;
1007
+ const suppressed = suppressedRecipients.map(recipient => {
1008
+ const info = this.getSuppressionInfo(recipient);
1009
+ return {
1010
+ email: recipient,
1011
+ reason: info?.reason || 'Unknown',
1012
+ until: info?.expiresAt ? new Date(info.expiresAt).toISOString() : 'permanent'
1013
+ };
1014
+ });
1015
+ logger.log('warn', `Filtering out ${suppressedRecipients.length} suppressed recipient(s)`, { suppressed });
1016
+ // If all recipients are suppressed, throw an error
1017
+ if (suppressedRecipients.length === originalCount) {
1018
+ throw new Error('All recipients are on the suppression list');
1019
+ }
1020
+ // Filter the recipients list to only include non-suppressed addresses
1021
+ email.to = email.to.filter(recipient => !this.isEmailSuppressed(recipient));
1022
+ }
1023
+ }
1024
+ // IP warmup handling
1025
+ let ipAddress = options?.ipAddress;
1026
+ // If no specific IP was provided, use IP warmup manager to find the best IP
1027
+ if (!ipAddress) {
1028
+ const domain = email.from.split('@')[1];
1029
+ ipAddress = this.getBestIPForSending({
1030
+ from: email.from,
1031
+ to: email.to,
1032
+ domain,
1033
+ isTransactional: options?.isTransactional
1034
+ });
1035
+ if (ipAddress) {
1036
+ logger.log('info', `Selected IP ${ipAddress} for sending based on warmup status`);
1037
+ }
1038
+ }
1039
+ // If an IP is provided or selected by warmup manager, check its capacity
1040
+ if (ipAddress) {
1041
+ // Check if the IP can send more today
1042
+ if (!this.canIPSendMoreToday(ipAddress)) {
1043
+ logger.log('warn', `IP ${ipAddress} has reached its daily sending limit, email will be queued for later delivery`);
1044
+ }
1045
+ // Check if the IP can send more this hour
1046
+ if (!this.canIPSendMoreThisHour(ipAddress)) {
1047
+ logger.log('warn', `IP ${ipAddress} has reached its hourly sending limit, email will be queued for later delivery`);
1048
+ }
1049
+ // Record the send for IP warmup tracking
1050
+ this.recordIPSend(ipAddress);
1051
+ // Add IP header to the email
1052
+ email.addHeader('X-Sending-IP', ipAddress);
1053
+ }
1054
+ // Check if the sender domain has DKIM keys and sign the email if needed
1055
+ if (mode === 'mta' && route?.action.options?.mtaOptions?.dkimSign) {
1056
+ const domain = email.from.split('@')[1];
1057
+ await this.handleDkimSigning(email, domain, route.action.options.mtaOptions.dkimOptions?.keySelector || 'mta');
1058
+ }
1059
+ // Generate a unique ID for this email
1060
+ const id = plugins.uuid.v4();
1061
+ // Queue the email for delivery
1062
+ await this.deliveryQueue.enqueue(email, mode, route);
1063
+ // Record 'sent' event for domain reputation monitoring
1064
+ const senderDomain = email.from.split('@')[1];
1065
+ if (senderDomain) {
1066
+ this.recordReputationEvent(senderDomain, {
1067
+ type: 'sent',
1068
+ count: email.to.length
1069
+ });
1070
+ }
1071
+ logger.log('info', `Email queued with ID: ${id}`);
1072
+ return id;
1073
+ }
1074
+ catch (error) {
1075
+ logger.log('error', `Failed to send email: ${error.message}`);
1076
+ throw error;
1077
+ }
1078
+ }
1079
+ /**
1080
+ * Handle DKIM signing for an email
1081
+ * @param email The email to sign
1082
+ * @param domain The domain to sign with
1083
+ * @param selector The DKIM selector
1084
+ */
1085
+ async handleDkimSigning(email, domain, selector) {
1086
+ try {
1087
+ // Ensure we have DKIM keys for this domain
1088
+ await this.dkimCreator.handleDKIMKeysForDomain(domain);
1089
+ // Get the private key
1090
+ const { privateKey } = await this.dkimCreator.readDKIMKeys(domain);
1091
+ // Convert Email to raw format for signing
1092
+ const rawEmail = email.toRFC822String();
1093
+ // Sign the email
1094
+ const signResult = await plugins.dkimSign(rawEmail, {
1095
+ canonicalization: 'relaxed/relaxed',
1096
+ algorithm: 'rsa-sha256',
1097
+ signTime: new Date(),
1098
+ signatureData: [
1099
+ {
1100
+ signingDomain: domain,
1101
+ selector: selector,
1102
+ privateKey: privateKey,
1103
+ algorithm: 'rsa-sha256',
1104
+ canonicalization: 'relaxed/relaxed'
1105
+ }
1106
+ ]
1107
+ });
1108
+ // Add the DKIM-Signature header to the email
1109
+ if (signResult.signatures) {
1110
+ email.addHeader('DKIM-Signature', signResult.signatures);
1111
+ logger.log('info', `Successfully added DKIM signature for ${domain}`);
1112
+ }
1113
+ }
1114
+ catch (error) {
1115
+ logger.log('error', `Failed to sign email with DKIM: ${error.message}`);
1116
+ // Continue without DKIM rather than failing the send
1117
+ }
1118
+ }
1119
+ /**
1120
+ * Process a bounce notification email
1121
+ * @param bounceEmail The email containing bounce notification information
1122
+ * @returns Processed bounce record or null if not a bounce
1123
+ */
1124
+ async processBounceNotification(bounceEmail) {
1125
+ logger.log('info', 'Processing potential bounce notification email');
1126
+ try {
1127
+ // Process as a bounce notification (no conversion needed anymore)
1128
+ const bounceRecord = await this.bounceManager.processBounceEmail(bounceEmail);
1129
+ if (bounceRecord) {
1130
+ logger.log('info', `Successfully processed bounce notification for ${bounceRecord.recipient}`, {
1131
+ bounceType: bounceRecord.bounceType,
1132
+ bounceCategory: bounceRecord.bounceCategory
1133
+ });
1134
+ // Notify any registered listeners about the bounce
1135
+ this.emit('bounceProcessed', bounceRecord);
1136
+ // Record bounce event for domain reputation tracking
1137
+ if (bounceRecord.domain) {
1138
+ this.recordReputationEvent(bounceRecord.domain, {
1139
+ type: 'bounce',
1140
+ hardBounce: bounceRecord.bounceCategory === BounceCategory.HARD,
1141
+ receivingDomain: bounceRecord.recipient.split('@')[1]
1142
+ });
1143
+ }
1144
+ // Log security event
1145
+ SecurityLogger.getInstance().logEvent({
1146
+ level: SecurityLogLevel.INFO,
1147
+ type: SecurityEventType.EMAIL_VALIDATION,
1148
+ message: `Bounce notification processed for recipient`,
1149
+ domain: bounceRecord.domain,
1150
+ details: {
1151
+ recipient: bounceRecord.recipient,
1152
+ bounceType: bounceRecord.bounceType,
1153
+ bounceCategory: bounceRecord.bounceCategory
1154
+ },
1155
+ success: true
1156
+ });
1157
+ return true;
1158
+ }
1159
+ else {
1160
+ logger.log('info', 'Email not recognized as a bounce notification');
1161
+ return false;
1162
+ }
1163
+ }
1164
+ catch (error) {
1165
+ logger.log('error', `Error processing bounce notification: ${error.message}`);
1166
+ SecurityLogger.getInstance().logEvent({
1167
+ level: SecurityLogLevel.ERROR,
1168
+ type: SecurityEventType.EMAIL_VALIDATION,
1169
+ message: 'Failed to process bounce notification',
1170
+ details: {
1171
+ error: error.message,
1172
+ subject: bounceEmail.subject
1173
+ },
1174
+ success: false
1175
+ });
1176
+ return false;
1177
+ }
1178
+ }
1179
+ /**
1180
+ * Process an SMTP failure as a bounce
1181
+ * @param recipient Recipient email that failed
1182
+ * @param smtpResponse SMTP error response
1183
+ * @param options Additional options for bounce processing
1184
+ * @returns Processed bounce record
1185
+ */
1186
+ async processSmtpFailure(recipient, smtpResponse, options = {}) {
1187
+ logger.log('info', `Processing SMTP failure for ${recipient}: ${smtpResponse}`);
1188
+ try {
1189
+ // Process the SMTP failure through the bounce manager
1190
+ const bounceRecord = await this.bounceManager.processSmtpFailure(recipient, smtpResponse, options);
1191
+ logger.log('info', `Successfully processed SMTP failure for ${recipient} as ${bounceRecord.bounceCategory} bounce`, {
1192
+ bounceType: bounceRecord.bounceType
1193
+ });
1194
+ // Notify any registered listeners about the bounce
1195
+ this.emit('bounceProcessed', bounceRecord);
1196
+ // Record bounce event for domain reputation tracking
1197
+ if (bounceRecord.domain) {
1198
+ this.recordReputationEvent(bounceRecord.domain, {
1199
+ type: 'bounce',
1200
+ hardBounce: bounceRecord.bounceCategory === BounceCategory.HARD,
1201
+ receivingDomain: bounceRecord.recipient.split('@')[1]
1202
+ });
1203
+ }
1204
+ // Log security event
1205
+ SecurityLogger.getInstance().logEvent({
1206
+ level: SecurityLogLevel.INFO,
1207
+ type: SecurityEventType.EMAIL_VALIDATION,
1208
+ message: `SMTP failure processed for recipient`,
1209
+ domain: bounceRecord.domain,
1210
+ details: {
1211
+ recipient: bounceRecord.recipient,
1212
+ bounceType: bounceRecord.bounceType,
1213
+ bounceCategory: bounceRecord.bounceCategory,
1214
+ smtpResponse
1215
+ },
1216
+ success: true
1217
+ });
1218
+ return true;
1219
+ }
1220
+ catch (error) {
1221
+ logger.log('error', `Error processing SMTP failure: ${error.message}`);
1222
+ SecurityLogger.getInstance().logEvent({
1223
+ level: SecurityLogLevel.ERROR,
1224
+ type: SecurityEventType.EMAIL_VALIDATION,
1225
+ message: 'Failed to process SMTP failure',
1226
+ details: {
1227
+ recipient,
1228
+ smtpResponse,
1229
+ error: error.message
1230
+ },
1231
+ success: false
1232
+ });
1233
+ return false;
1234
+ }
1235
+ }
1236
+ /**
1237
+ * Check if an email address is suppressed (has bounced previously)
1238
+ * @param email Email address to check
1239
+ * @returns Whether the email is suppressed
1240
+ */
1241
+ isEmailSuppressed(email) {
1242
+ return this.bounceManager.isEmailSuppressed(email);
1243
+ }
1244
+ /**
1245
+ * Get suppression information for an email
1246
+ * @param email Email address to check
1247
+ * @returns Suppression information or null if not suppressed
1248
+ */
1249
+ getSuppressionInfo(email) {
1250
+ return this.bounceManager.getSuppressionInfo(email);
1251
+ }
1252
+ /**
1253
+ * Get bounce history information for an email
1254
+ * @param email Email address to check
1255
+ * @returns Bounce history or null if no bounces
1256
+ */
1257
+ getBounceHistory(email) {
1258
+ return this.bounceManager.getBounceInfo(email);
1259
+ }
1260
+ /**
1261
+ * Get all suppressed email addresses
1262
+ * @returns Array of suppressed email addresses
1263
+ */
1264
+ getSuppressionList() {
1265
+ return this.bounceManager.getSuppressionList();
1266
+ }
1267
+ /**
1268
+ * Get all hard bounced email addresses
1269
+ * @returns Array of hard bounced email addresses
1270
+ */
1271
+ getHardBouncedAddresses() {
1272
+ return this.bounceManager.getHardBouncedAddresses();
1273
+ }
1274
+ /**
1275
+ * Add an email to the suppression list
1276
+ * @param email Email address to suppress
1277
+ * @param reason Reason for suppression
1278
+ * @param expiresAt Optional expiration time (undefined for permanent)
1279
+ */
1280
+ addToSuppressionList(email, reason, expiresAt) {
1281
+ this.bounceManager.addToSuppressionList(email, reason, expiresAt);
1282
+ logger.log('info', `Added ${email} to suppression list: ${reason}`);
1283
+ }
1284
+ /**
1285
+ * Remove an email from the suppression list
1286
+ * @param email Email address to remove from suppression
1287
+ */
1288
+ removeFromSuppressionList(email) {
1289
+ this.bounceManager.removeFromSuppressionList(email);
1290
+ logger.log('info', `Removed ${email} from suppression list`);
1291
+ }
1292
+ /**
1293
+ * Get the status of IP warmup process
1294
+ * @param ipAddress Optional specific IP to check
1295
+ * @returns Status of IP warmup
1296
+ */
1297
+ getIPWarmupStatus(ipAddress) {
1298
+ return this.ipWarmupManager.getWarmupStatus(ipAddress);
1299
+ }
1300
+ /**
1301
+ * Add a new IP address to the warmup process
1302
+ * @param ipAddress IP address to add
1303
+ */
1304
+ addIPToWarmup(ipAddress) {
1305
+ this.ipWarmupManager.addIPToWarmup(ipAddress);
1306
+ }
1307
+ /**
1308
+ * Remove an IP address from the warmup process
1309
+ * @param ipAddress IP address to remove
1310
+ */
1311
+ removeIPFromWarmup(ipAddress) {
1312
+ this.ipWarmupManager.removeIPFromWarmup(ipAddress);
1313
+ }
1314
+ /**
1315
+ * Update metrics for an IP in the warmup process
1316
+ * @param ipAddress IP address
1317
+ * @param metrics Metrics to update
1318
+ */
1319
+ updateIPWarmupMetrics(ipAddress, metrics) {
1320
+ this.ipWarmupManager.updateMetrics(ipAddress, metrics);
1321
+ }
1322
+ /**
1323
+ * Check if an IP can send more emails today
1324
+ * @param ipAddress IP address to check
1325
+ * @returns Whether the IP can send more today
1326
+ */
1327
+ canIPSendMoreToday(ipAddress) {
1328
+ return this.ipWarmupManager.canSendMoreToday(ipAddress);
1329
+ }
1330
+ /**
1331
+ * Check if an IP can send more emails in the current hour
1332
+ * @param ipAddress IP address to check
1333
+ * @returns Whether the IP can send more this hour
1334
+ */
1335
+ canIPSendMoreThisHour(ipAddress) {
1336
+ return this.ipWarmupManager.canSendMoreThisHour(ipAddress);
1337
+ }
1338
+ /**
1339
+ * Get the best IP to use for sending an email based on warmup status
1340
+ * @param emailInfo Information about the email being sent
1341
+ * @returns Best IP to use or null
1342
+ */
1343
+ getBestIPForSending(emailInfo) {
1344
+ return this.ipWarmupManager.getBestIPForSending(emailInfo);
1345
+ }
1346
+ /**
1347
+ * Set the active IP allocation policy for warmup
1348
+ * @param policyName Name of the policy to set
1349
+ */
1350
+ setIPAllocationPolicy(policyName) {
1351
+ this.ipWarmupManager.setActiveAllocationPolicy(policyName);
1352
+ }
1353
+ /**
1354
+ * Record that an email was sent using a specific IP
1355
+ * @param ipAddress IP address used for sending
1356
+ */
1357
+ recordIPSend(ipAddress) {
1358
+ this.ipWarmupManager.recordSend(ipAddress);
1359
+ }
1360
+ /**
1361
+ * Get reputation data for a domain
1362
+ * @param domain Domain to get reputation for
1363
+ * @returns Domain reputation metrics
1364
+ */
1365
+ getDomainReputationData(domain) {
1366
+ return this.senderReputationMonitor.getReputationData(domain);
1367
+ }
1368
+ /**
1369
+ * Get summary reputation data for all monitored domains
1370
+ * @returns Summary data for all domains
1371
+ */
1372
+ getReputationSummary() {
1373
+ return this.senderReputationMonitor.getReputationSummary();
1374
+ }
1375
+ /**
1376
+ * Add a domain to the reputation monitoring system
1377
+ * @param domain Domain to add
1378
+ */
1379
+ addDomainToMonitoring(domain) {
1380
+ this.senderReputationMonitor.addDomain(domain);
1381
+ }
1382
+ /**
1383
+ * Remove a domain from the reputation monitoring system
1384
+ * @param domain Domain to remove
1385
+ */
1386
+ removeDomainFromMonitoring(domain) {
1387
+ this.senderReputationMonitor.removeDomain(domain);
1388
+ }
1389
+ /**
1390
+ * Record an email event for domain reputation tracking
1391
+ * @param domain Domain sending the email
1392
+ * @param event Event details
1393
+ */
1394
+ recordReputationEvent(domain, event) {
1395
+ this.senderReputationMonitor.recordSendEvent(domain, event);
1396
+ }
1397
+ /**
1398
+ * Check if DKIM key exists for a domain
1399
+ * @param domain Domain to check
1400
+ */
1401
+ hasDkimKey(domain) {
1402
+ return this.dkimKeys.has(domain);
1403
+ }
1404
+ /**
1405
+ * Record successful email delivery
1406
+ * @param domain Sending domain
1407
+ */
1408
+ recordDelivery(domain) {
1409
+ this.recordReputationEvent(domain, {
1410
+ type: 'delivered',
1411
+ count: 1
1412
+ });
1413
+ }
1414
+ /**
1415
+ * Record email bounce
1416
+ * @param domain Sending domain
1417
+ * @param receivingDomain Receiving domain that bounced
1418
+ * @param bounceType Type of bounce (hard/soft)
1419
+ * @param reason Bounce reason
1420
+ */
1421
+ recordBounce(domain, receivingDomain, bounceType, reason) {
1422
+ // Record bounce in bounce manager
1423
+ const bounceRecord = {
1424
+ id: `bounce_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
1425
+ recipient: `user@${receivingDomain}`,
1426
+ sender: `user@${domain}`,
1427
+ domain: domain,
1428
+ bounceType: bounceType === 'hard' ? BounceType.INVALID_RECIPIENT : BounceType.TEMPORARY_FAILURE,
1429
+ bounceCategory: bounceType === 'hard' ? BounceCategory.HARD : BounceCategory.SOFT,
1430
+ timestamp: Date.now(),
1431
+ smtpResponse: reason,
1432
+ diagnosticCode: reason,
1433
+ statusCode: bounceType === 'hard' ? '550' : '450',
1434
+ processed: false
1435
+ };
1436
+ // Process the bounce
1437
+ this.bounceManager.processBounce(bounceRecord);
1438
+ // Record reputation event
1439
+ this.recordReputationEvent(domain, {
1440
+ type: 'bounce',
1441
+ count: 1,
1442
+ hardBounce: bounceType === 'hard',
1443
+ receivingDomain
1444
+ });
1445
+ }
1446
+ /**
1447
+ * Get the rate limiter instance
1448
+ * @returns The unified rate limiter
1449
+ */
1450
+ getRateLimiter() {
1451
+ return this.rateLimiter;
1452
+ }
1453
+ }
1454
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy51bmlmaWVkLmVtYWlsLnNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL21haWwvcm91dGluZy9jbGFzc2VzLnVuaWZpZWQuZW1haWwuc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxLQUFLLEtBQUssTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQ0wsY0FBYyxFQUNkLGdCQUFnQixFQUNoQixpQkFBaUIsRUFDbEIsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDakUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sK0NBQStDLENBQUM7QUFDcEYsT0FBTyxFQUNMLGVBQWUsRUFFZix1QkFBdUIsRUFFeEIsTUFBTSwrQkFBK0IsQ0FBQztBQUN2QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFeEQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDN0YsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbkUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFFakYsT0FBTyxFQUFFLHVCQUF1QixFQUFrQyxNQUFNLHdDQUF3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