@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.
- package/.dockerignore +1 -0
- package/.gitea/workflows/docker_nottags.yaml +71 -0
- package/.gitea/workflows/docker_tags.yaml +106 -0
- package/.vscode/launch.json +11 -0
- package/.vscode/settings.json +26 -0
- package/Dockerfile +46 -0
- package/changelog.md +247 -0
- package/cli.child.js +4 -0
- package/cli.child.ts +4 -0
- package/cli.js +4 -0
- package/cli.ts.js +5 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.dcrouter.d.ts +238 -0
- package/dist_ts/classes.dcrouter.js +1008 -0
- package/dist_ts/config/index.d.ts +1 -0
- package/dist_ts/config/index.js +3 -0
- package/dist_ts/config/validator.d.ts +104 -0
- package/dist_ts/config/validator.js +152 -0
- package/dist_ts/deliverability/classes.ipwarmupmanager.d.ts +253 -0
- package/dist_ts/deliverability/classes.ipwarmupmanager.js +639 -0
- package/dist_ts/deliverability/classes.senderreputationmonitor.d.ts +300 -0
- package/dist_ts/deliverability/classes.senderreputationmonitor.js +961 -0
- package/dist_ts/deliverability/index.d.ts +2 -0
- package/dist_ts/deliverability/index.js +3 -0
- package/dist_ts/errors/base.errors.d.ts +224 -0
- package/dist_ts/errors/base.errors.js +310 -0
- package/dist_ts/errors/email.errors.d.ts +175 -0
- package/dist_ts/errors/email.errors.js +265 -0
- package/dist_ts/errors/error-handler.d.ts +98 -0
- package/dist_ts/errors/error-handler.js +282 -0
- package/dist_ts/errors/error.codes.d.ts +115 -0
- package/dist_ts/errors/error.codes.js +136 -0
- package/dist_ts/errors/index.d.ts +56 -0
- package/dist_ts/errors/index.js +138 -0
- package/dist_ts/errors/mta.errors.d.ts +259 -0
- package/dist_ts/errors/mta.errors.js +472 -0
- package/dist_ts/errors/reputation.errors.d.ts +183 -0
- package/dist_ts/errors/reputation.errors.js +292 -0
- package/dist_ts/index.d.ts +4 -0
- package/dist_ts/index.js +6 -0
- package/dist_ts/logger.d.ts +17 -0
- package/dist_ts/logger.js +77 -0
- package/dist_ts/mail/core/classes.bouncemanager.d.ts +200 -0
- package/dist_ts/mail/core/classes.bouncemanager.js +778 -0
- package/dist_ts/mail/core/classes.email.d.ts +291 -0
- package/dist_ts/mail/core/classes.email.js +780 -0
- package/dist_ts/mail/core/classes.emailvalidator.d.ts +61 -0
- package/dist_ts/mail/core/classes.emailvalidator.js +182 -0
- package/dist_ts/mail/core/classes.templatemanager.d.ts +95 -0
- package/dist_ts/mail/core/classes.templatemanager.js +239 -0
- package/dist_ts/mail/core/index.d.ts +4 -0
- package/dist_ts/mail/core/index.js +6 -0
- package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
- package/dist_ts/mail/delivery/classes.delivery.queue.js +485 -0
- package/dist_ts/mail/delivery/classes.delivery.system.d.ts +186 -0
- package/dist_ts/mail/delivery/classes.delivery.system.js +846 -0
- package/dist_ts/mail/delivery/classes.emailsendjob.d.ts +84 -0
- package/dist_ts/mail/delivery/classes.emailsendjob.js +362 -0
- package/dist_ts/mail/delivery/classes.emailsignjob.d.ts +18 -0
- package/dist_ts/mail/delivery/classes.emailsignjob.js +44 -0
- package/dist_ts/mail/delivery/classes.mta.config.d.ts +22 -0
- package/dist_ts/mail/delivery/classes.mta.config.js +51 -0
- package/dist_ts/mail/delivery/classes.ratelimiter.d.ts +98 -0
- package/dist_ts/mail/delivery/classes.ratelimiter.js +205 -0
- package/dist_ts/mail/delivery/classes.smtp.client.legacy.d.ts +275 -0
- package/dist_ts/mail/delivery/classes.smtp.client.legacy.js +973 -0
- package/dist_ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
- package/dist_ts/mail/delivery/classes.unified.rate.limiter.js +817 -0
- package/dist_ts/mail/delivery/index.d.ts +12 -0
- package/dist_ts/mail/delivery/index.js +18 -0
- package/dist_ts/mail/delivery/interfaces.d.ts +243 -0
- package/dist_ts/mail/delivery/interfaces.js +17 -0
- package/dist_ts/mail/delivery/smtpclient/auth-handler.d.ts +43 -0
- package/dist_ts/mail/delivery/smtpclient/auth-handler.js +188 -0
- package/dist_ts/mail/delivery/smtpclient/command-handler.d.ts +67 -0
- package/dist_ts/mail/delivery/smtpclient/command-handler.js +276 -0
- package/dist_ts/mail/delivery/smtpclient/connection-manager.d.ts +48 -0
- package/dist_ts/mail/delivery/smtpclient/connection-manager.js +238 -0
- package/dist_ts/mail/delivery/smtpclient/constants.d.ts +129 -0
- package/dist_ts/mail/delivery/smtpclient/constants.js +135 -0
- package/dist_ts/mail/delivery/smtpclient/create-client.d.ts +22 -0
- package/dist_ts/mail/delivery/smtpclient/create-client.js +86 -0
- package/dist_ts/mail/delivery/smtpclient/error-handler.d.ts +28 -0
- package/dist_ts/mail/delivery/smtpclient/error-handler.js +110 -0
- package/dist_ts/mail/delivery/smtpclient/index.d.ts +16 -0
- package/dist_ts/mail/delivery/smtpclient/index.js +21 -0
- package/dist_ts/mail/delivery/smtpclient/interfaces.d.ts +183 -0
- package/dist_ts/mail/delivery/smtpclient/interfaces.js +19 -0
- package/dist_ts/mail/delivery/smtpclient/smtp-client.d.ts +58 -0
- package/dist_ts/mail/delivery/smtpclient/smtp-client.js +279 -0
- package/dist_ts/mail/delivery/smtpclient/tls-handler.d.ts +33 -0
- package/dist_ts/mail/delivery/smtpclient/tls-handler.js +202 -0
- package/dist_ts/mail/delivery/smtpclient/utils/helpers.d.ts +77 -0
- package/dist_ts/mail/delivery/smtpclient/utils/helpers.js +196 -0
- package/dist_ts/mail/delivery/smtpclient/utils/logging.d.ts +46 -0
- package/dist_ts/mail/delivery/smtpclient/utils/logging.js +153 -0
- package/dist_ts/mail/delivery/smtpclient/utils/validation.d.ts +38 -0
- package/dist_ts/mail/delivery/smtpclient/utils/validation.js +139 -0
- package/dist_ts/mail/delivery/smtpserver/certificate-utils.d.ts +45 -0
- package/dist_ts/mail/delivery/smtpserver/certificate-utils.js +345 -0
- package/dist_ts/mail/delivery/smtpserver/command-handler.d.ts +156 -0
- package/dist_ts/mail/delivery/smtpserver/command-handler.js +1159 -0
- package/dist_ts/mail/delivery/smtpserver/connection-manager.d.ts +159 -0
- package/dist_ts/mail/delivery/smtpserver/connection-manager.js +894 -0
- package/dist_ts/mail/delivery/smtpserver/constants.d.ts +130 -0
- package/dist_ts/mail/delivery/smtpserver/constants.js +162 -0
- package/dist_ts/mail/delivery/smtpserver/create-server.d.ts +14 -0
- package/dist_ts/mail/delivery/smtpserver/create-server.js +28 -0
- package/dist_ts/mail/delivery/smtpserver/data-handler.d.ts +123 -0
- package/dist_ts/mail/delivery/smtpserver/data-handler.js +1148 -0
- package/dist_ts/mail/delivery/smtpserver/index.d.ts +20 -0
- package/dist_ts/mail/delivery/smtpserver/index.js +27 -0
- package/dist_ts/mail/delivery/smtpserver/interfaces.d.ts +530 -0
- package/dist_ts/mail/delivery/smtpserver/interfaces.js +10 -0
- package/dist_ts/mail/delivery/smtpserver/secure-server.d.ts +15 -0
- package/dist_ts/mail/delivery/smtpserver/secure-server.js +79 -0
- package/dist_ts/mail/delivery/smtpserver/security-handler.d.ts +86 -0
- package/dist_ts/mail/delivery/smtpserver/security-handler.js +234 -0
- package/dist_ts/mail/delivery/smtpserver/session-manager.d.ts +140 -0
- package/dist_ts/mail/delivery/smtpserver/session-manager.js +469 -0
- package/dist_ts/mail/delivery/smtpserver/smtp-server.d.ts +137 -0
- package/dist_ts/mail/delivery/smtpserver/smtp-server.js +666 -0
- package/dist_ts/mail/delivery/smtpserver/starttls-handler.d.ts +21 -0
- package/dist_ts/mail/delivery/smtpserver/starttls-handler.js +207 -0
- package/dist_ts/mail/delivery/smtpserver/tls-handler.d.ts +66 -0
- package/dist_ts/mail/delivery/smtpserver/tls-handler.js +261 -0
- package/dist_ts/mail/delivery/smtpserver/utils/adaptive-logging.d.ts +117 -0
- package/dist_ts/mail/delivery/smtpserver/utils/adaptive-logging.js +411 -0
- package/dist_ts/mail/delivery/smtpserver/utils/helpers.d.ts +78 -0
- package/dist_ts/mail/delivery/smtpserver/utils/helpers.js +208 -0
- package/dist_ts/mail/delivery/smtpserver/utils/logging.d.ts +106 -0
- package/dist_ts/mail/delivery/smtpserver/utils/logging.js +181 -0
- package/dist_ts/mail/delivery/smtpserver/utils/validation.d.ts +69 -0
- package/dist_ts/mail/delivery/smtpserver/utils/validation.js +360 -0
- package/dist_ts/mail/index.d.ts +8 -0
- package/dist_ts/mail/index.js +13 -0
- package/dist_ts/mail/routing/classes.dns.manager.d.ts +65 -0
- package/dist_ts/mail/routing/classes.dns.manager.js +413 -0
- package/dist_ts/mail/routing/classes.dnsmanager.d.ts +165 -0
- package/dist_ts/mail/routing/classes.dnsmanager.js +430 -0
- package/dist_ts/mail/routing/classes.domain.registry.d.ts +54 -0
- package/dist_ts/mail/routing/classes.domain.registry.js +118 -0
- package/dist_ts/mail/routing/classes.email.config.d.ts +64 -0
- package/dist_ts/mail/routing/classes.email.config.js +2 -0
- package/dist_ts/mail/routing/classes.email.router.d.ts +171 -0
- package/dist_ts/mail/routing/classes.email.router.js +491 -0
- package/dist_ts/mail/routing/classes.unified.email.server.d.ts +426 -0
- package/dist_ts/mail/routing/classes.unified.email.server.js +1454 -0
- package/dist_ts/mail/routing/index.d.ts +5 -0
- package/dist_ts/mail/routing/index.js +7 -0
- package/dist_ts/mail/routing/interfaces.d.ts +187 -0
- package/dist_ts/mail/routing/interfaces.js +2 -0
- package/dist_ts/mail/security/classes.dkimcreator.d.ts +68 -0
- package/dist_ts/mail/security/classes.dkimcreator.js +346 -0
- package/dist_ts/mail/security/classes.dkimverifier.d.ts +46 -0
- package/dist_ts/mail/security/classes.dkimverifier.js +317 -0
- package/dist_ts/mail/security/classes.dmarcverifier.d.ts +123 -0
- package/dist_ts/mail/security/classes.dmarcverifier.js +365 -0
- package/dist_ts/mail/security/classes.spfverifier.d.ts +103 -0
- package/dist_ts/mail/security/classes.spfverifier.js +492 -0
- package/dist_ts/mail/security/index.d.ts +4 -0
- package/dist_ts/mail/security/index.js +6 -0
- package/dist_ts/opsserver/classes.opsserver.d.ts +14 -0
- package/dist_ts/opsserver/classes.opsserver.js +37 -0
- package/dist_ts/opsserver/index.d.ts +1 -0
- package/dist_ts/opsserver/index.js +2 -0
- package/dist_ts/paths.d.ts +14 -0
- package/dist_ts/paths.js +39 -0
- package/dist_ts/plugins.d.ts +43 -0
- package/dist_ts/plugins.js +50 -0
- package/dist_ts/security/classes.contentscanner.d.ts +160 -0
- package/dist_ts/security/classes.contentscanner.js +634 -0
- package/dist_ts/security/classes.ipreputationchecker.d.ts +150 -0
- package/dist_ts/security/classes.ipreputationchecker.js +508 -0
- package/dist_ts/security/classes.securitylogger.d.ts +140 -0
- package/dist_ts/security/classes.securitylogger.js +232 -0
- package/dist_ts/security/index.d.ts +3 -0
- package/dist_ts/security/index.js +4 -0
- package/dist_ts/sms/classes.smsservice.d.ts +15 -0
- package/dist_ts/sms/classes.smsservice.js +72 -0
- package/dist_ts/sms/config/sms.config.d.ts +93 -0
- package/dist_ts/sms/config/sms.config.js +2 -0
- package/dist_ts/sms/config/sms.schema.d.ts +5 -0
- package/dist_ts/sms/config/sms.schema.js +121 -0
- package/dist_ts/sms/index.d.ts +1 -0
- package/dist_ts/sms/index.js +2 -0
- package/dist_ts/storage/classes.storagemanager.d.ts +82 -0
- package/dist_ts/storage/classes.storagemanager.js +341 -0
- package/dist_ts/storage/index.d.ts +1 -0
- package/dist_ts/storage/index.js +3 -0
- package/dist_ts/ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/ts/00_commitinfo_data.js +9 -0
- package/dist_ts/ts/classes.dcrouter.d.ts +238 -0
- package/dist_ts/ts/classes.dcrouter.js +1008 -0
- package/dist_ts/ts/config/index.d.ts +1 -0
- package/dist_ts/ts/config/index.js +3 -0
- package/dist_ts/ts/config/validator.d.ts +104 -0
- package/dist_ts/ts/config/validator.js +152 -0
- package/dist_ts/ts/deliverability/classes.ipwarmupmanager.d.ts +253 -0
- package/dist_ts/ts/deliverability/classes.ipwarmupmanager.js +639 -0
- package/dist_ts/ts/deliverability/classes.senderreputationmonitor.d.ts +300 -0
- package/dist_ts/ts/deliverability/classes.senderreputationmonitor.js +961 -0
- package/dist_ts/ts/deliverability/index.d.ts +2 -0
- package/dist_ts/ts/deliverability/index.js +3 -0
- package/dist_ts/ts/errors/base.errors.d.ts +224 -0
- package/dist_ts/ts/errors/base.errors.js +310 -0
- package/dist_ts/ts/errors/email.errors.d.ts +175 -0
- package/dist_ts/ts/errors/email.errors.js +265 -0
- package/dist_ts/ts/errors/error-handler.d.ts +98 -0
- package/dist_ts/ts/errors/error-handler.js +282 -0
- package/dist_ts/ts/errors/error.codes.d.ts +115 -0
- package/dist_ts/ts/errors/error.codes.js +136 -0
- package/dist_ts/ts/errors/index.d.ts +56 -0
- package/dist_ts/ts/errors/index.js +138 -0
- package/dist_ts/ts/errors/mta.errors.d.ts +259 -0
- package/dist_ts/ts/errors/mta.errors.js +472 -0
- package/dist_ts/ts/errors/reputation.errors.d.ts +183 -0
- package/dist_ts/ts/errors/reputation.errors.js +292 -0
- package/dist_ts/ts/index.d.ts +4 -0
- package/dist_ts/ts/index.js +6 -0
- package/dist_ts/ts/logger.d.ts +17 -0
- package/dist_ts/ts/logger.js +77 -0
- package/dist_ts/ts/mail/core/classes.bouncemanager.d.ts +200 -0
- package/dist_ts/ts/mail/core/classes.bouncemanager.js +778 -0
- package/dist_ts/ts/mail/core/classes.email.d.ts +291 -0
- package/dist_ts/ts/mail/core/classes.email.js +780 -0
- package/dist_ts/ts/mail/core/classes.emailvalidator.d.ts +61 -0
- package/dist_ts/ts/mail/core/classes.emailvalidator.js +182 -0
- package/dist_ts/ts/mail/core/classes.templatemanager.d.ts +95 -0
- package/dist_ts/ts/mail/core/classes.templatemanager.js +239 -0
- package/dist_ts/ts/mail/core/index.d.ts +4 -0
- package/dist_ts/ts/mail/core/index.js +6 -0
- package/dist_ts/ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
- package/dist_ts/ts/mail/delivery/classes.delivery.queue.js +485 -0
- package/dist_ts/ts/mail/delivery/classes.delivery.system.d.ts +186 -0
- package/dist_ts/ts/mail/delivery/classes.delivery.system.js +846 -0
- package/dist_ts/ts/mail/delivery/classes.emailsendjob.d.ts +84 -0
- package/dist_ts/ts/mail/delivery/classes.emailsendjob.js +362 -0
- package/dist_ts/ts/mail/delivery/classes.emailsignjob.d.ts +18 -0
- package/dist_ts/ts/mail/delivery/classes.emailsignjob.js +44 -0
- package/dist_ts/ts/mail/delivery/classes.mta.config.d.ts +22 -0
- package/dist_ts/ts/mail/delivery/classes.mta.config.js +51 -0
- package/dist_ts/ts/mail/delivery/classes.ratelimiter.d.ts +98 -0
- package/dist_ts/ts/mail/delivery/classes.ratelimiter.js +205 -0
- package/dist_ts/ts/mail/delivery/classes.smtp.client.legacy.d.ts +275 -0
- package/dist_ts/ts/mail/delivery/classes.smtp.client.legacy.js +973 -0
- package/dist_ts/ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
- package/dist_ts/ts/mail/delivery/classes.unified.rate.limiter.js +817 -0
- package/dist_ts/ts/mail/delivery/index.d.ts +12 -0
- package/dist_ts/ts/mail/delivery/index.js +18 -0
- package/dist_ts/ts/mail/delivery/interfaces.d.ts +243 -0
- package/dist_ts/ts/mail/delivery/interfaces.js +17 -0
- package/dist_ts/ts/mail/delivery/smtpclient/auth-handler.d.ts +43 -0
- package/dist_ts/ts/mail/delivery/smtpclient/auth-handler.js +188 -0
- package/dist_ts/ts/mail/delivery/smtpclient/command-handler.d.ts +67 -0
- package/dist_ts/ts/mail/delivery/smtpclient/command-handler.js +276 -0
- package/dist_ts/ts/mail/delivery/smtpclient/connection-manager.d.ts +48 -0
- package/dist_ts/ts/mail/delivery/smtpclient/connection-manager.js +238 -0
- package/dist_ts/ts/mail/delivery/smtpclient/constants.d.ts +129 -0
- package/dist_ts/ts/mail/delivery/smtpclient/constants.js +135 -0
- package/dist_ts/ts/mail/delivery/smtpclient/create-client.d.ts +22 -0
- package/dist_ts/ts/mail/delivery/smtpclient/create-client.js +86 -0
- package/dist_ts/ts/mail/delivery/smtpclient/error-handler.d.ts +28 -0
- package/dist_ts/ts/mail/delivery/smtpclient/error-handler.js +110 -0
- package/dist_ts/ts/mail/delivery/smtpclient/index.d.ts +16 -0
- package/dist_ts/ts/mail/delivery/smtpclient/index.js +21 -0
- package/dist_ts/ts/mail/delivery/smtpclient/interfaces.d.ts +183 -0
- package/dist_ts/ts/mail/delivery/smtpclient/interfaces.js +19 -0
- package/dist_ts/ts/mail/delivery/smtpclient/smtp-client.d.ts +58 -0
- package/dist_ts/ts/mail/delivery/smtpclient/smtp-client.js +279 -0
- package/dist_ts/ts/mail/delivery/smtpclient/tls-handler.d.ts +33 -0
- package/dist_ts/ts/mail/delivery/smtpclient/tls-handler.js +202 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/helpers.d.ts +77 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/helpers.js +196 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/logging.d.ts +46 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/logging.js +153 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/validation.d.ts +38 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/validation.js +139 -0
- package/dist_ts/ts/mail/delivery/smtpserver/certificate-utils.d.ts +45 -0
- package/dist_ts/ts/mail/delivery/smtpserver/certificate-utils.js +345 -0
- package/dist_ts/ts/mail/delivery/smtpserver/command-handler.d.ts +156 -0
- package/dist_ts/ts/mail/delivery/smtpserver/command-handler.js +1159 -0
- package/dist_ts/ts/mail/delivery/smtpserver/connection-manager.d.ts +159 -0
- package/dist_ts/ts/mail/delivery/smtpserver/connection-manager.js +894 -0
- package/dist_ts/ts/mail/delivery/smtpserver/constants.d.ts +130 -0
- package/dist_ts/ts/mail/delivery/smtpserver/constants.js +162 -0
- package/dist_ts/ts/mail/delivery/smtpserver/create-server.d.ts +14 -0
- package/dist_ts/ts/mail/delivery/smtpserver/create-server.js +28 -0
- package/dist_ts/ts/mail/delivery/smtpserver/data-handler.d.ts +123 -0
- package/dist_ts/ts/mail/delivery/smtpserver/data-handler.js +1148 -0
- package/dist_ts/ts/mail/delivery/smtpserver/index.d.ts +20 -0
- package/dist_ts/ts/mail/delivery/smtpserver/index.js +27 -0
- package/dist_ts/ts/mail/delivery/smtpserver/interfaces.d.ts +530 -0
- package/dist_ts/ts/mail/delivery/smtpserver/interfaces.js +10 -0
- package/dist_ts/ts/mail/delivery/smtpserver/secure-server.d.ts +15 -0
- package/dist_ts/ts/mail/delivery/smtpserver/secure-server.js +79 -0
- package/dist_ts/ts/mail/delivery/smtpserver/security-handler.d.ts +86 -0
- package/dist_ts/ts/mail/delivery/smtpserver/security-handler.js +234 -0
- package/dist_ts/ts/mail/delivery/smtpserver/session-manager.d.ts +140 -0
- package/dist_ts/ts/mail/delivery/smtpserver/session-manager.js +469 -0
- package/dist_ts/ts/mail/delivery/smtpserver/smtp-server.d.ts +137 -0
- package/dist_ts/ts/mail/delivery/smtpserver/smtp-server.js +666 -0
- package/dist_ts/ts/mail/delivery/smtpserver/starttls-handler.d.ts +21 -0
- package/dist_ts/ts/mail/delivery/smtpserver/starttls-handler.js +207 -0
- package/dist_ts/ts/mail/delivery/smtpserver/tls-handler.d.ts +66 -0
- package/dist_ts/ts/mail/delivery/smtpserver/tls-handler.js +261 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/adaptive-logging.d.ts +117 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/adaptive-logging.js +411 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/helpers.d.ts +78 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/helpers.js +208 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/logging.d.ts +106 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/logging.js +181 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/validation.d.ts +69 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/validation.js +360 -0
- package/dist_ts/ts/mail/index.d.ts +8 -0
- package/dist_ts/ts/mail/index.js +13 -0
- package/dist_ts/ts/mail/routing/classes.dns.manager.d.ts +65 -0
- package/dist_ts/ts/mail/routing/classes.dns.manager.js +413 -0
- package/dist_ts/ts/mail/routing/classes.dnsmanager.d.ts +165 -0
- package/dist_ts/ts/mail/routing/classes.dnsmanager.js +430 -0
- package/dist_ts/ts/mail/routing/classes.domain.registry.d.ts +54 -0
- package/dist_ts/ts/mail/routing/classes.domain.registry.js +118 -0
- package/dist_ts/ts/mail/routing/classes.email.config.d.ts +64 -0
- package/dist_ts/ts/mail/routing/classes.email.config.js +2 -0
- package/dist_ts/ts/mail/routing/classes.email.router.d.ts +171 -0
- package/dist_ts/ts/mail/routing/classes.email.router.js +491 -0
- package/dist_ts/ts/mail/routing/classes.unified.email.server.d.ts +426 -0
- package/dist_ts/ts/mail/routing/classes.unified.email.server.js +1454 -0
- package/dist_ts/ts/mail/routing/index.d.ts +5 -0
- package/dist_ts/ts/mail/routing/index.js +7 -0
- package/dist_ts/ts/mail/routing/interfaces.d.ts +187 -0
- package/dist_ts/ts/mail/routing/interfaces.js +2 -0
- package/dist_ts/ts/mail/security/classes.dkimcreator.d.ts +68 -0
- package/dist_ts/ts/mail/security/classes.dkimcreator.js +346 -0
- package/dist_ts/ts/mail/security/classes.dkimverifier.d.ts +46 -0
- package/dist_ts/ts/mail/security/classes.dkimverifier.js +317 -0
- package/dist_ts/ts/mail/security/classes.dmarcverifier.d.ts +123 -0
- package/dist_ts/ts/mail/security/classes.dmarcverifier.js +365 -0
- package/dist_ts/ts/mail/security/classes.spfverifier.d.ts +103 -0
- package/dist_ts/ts/mail/security/classes.spfverifier.js +492 -0
- package/dist_ts/ts/mail/security/index.d.ts +4 -0
- package/dist_ts/ts/mail/security/index.js +6 -0
- package/dist_ts/ts/opsserver/classes.opsserver.d.ts +20 -0
- package/dist_ts/ts/opsserver/classes.opsserver.js +44 -0
- package/dist_ts/ts/opsserver/handlers/admin.handler.d.ts +31 -0
- package/dist_ts/ts/opsserver/handlers/admin.handler.js +177 -0
- package/dist_ts/ts/opsserver/handlers/config.handler.d.ts +10 -0
- package/dist_ts/ts/opsserver/handlers/config.handler.js +100 -0
- package/dist_ts/ts/opsserver/handlers/index.d.ts +5 -0
- package/dist_ts/ts/opsserver/handlers/index.js +6 -0
- package/dist_ts/ts/opsserver/handlers/logs.handler.d.ts +10 -0
- package/dist_ts/ts/opsserver/handlers/logs.handler.js +121 -0
- package/dist_ts/ts/opsserver/handlers/security.handler.d.ts +11 -0
- package/dist_ts/ts/opsserver/handlers/security.handler.js +118 -0
- package/dist_ts/ts/opsserver/handlers/stats.handler.d.ts +13 -0
- package/dist_ts/ts/opsserver/handlers/stats.handler.js +233 -0
- package/dist_ts/ts/opsserver/helpers/guards.d.ts +25 -0
- package/dist_ts/ts/opsserver/helpers/guards.js +41 -0
- package/dist_ts/ts/opsserver/index.d.ts +1 -0
- package/dist_ts/ts/opsserver/index.js +2 -0
- package/dist_ts/ts/paths.d.ts +14 -0
- package/dist_ts/ts/paths.js +39 -0
- package/dist_ts/ts/plugins.d.ts +46 -0
- package/dist_ts/ts/plugins.js +53 -0
- package/dist_ts/ts/security/classes.contentscanner.d.ts +160 -0
- package/dist_ts/ts/security/classes.contentscanner.js +634 -0
- package/dist_ts/ts/security/classes.ipreputationchecker.d.ts +150 -0
- package/dist_ts/ts/security/classes.ipreputationchecker.js +508 -0
- package/dist_ts/ts/security/classes.securitylogger.d.ts +140 -0
- package/dist_ts/ts/security/classes.securitylogger.js +232 -0
- package/dist_ts/ts/security/index.d.ts +3 -0
- package/dist_ts/ts/security/index.js +4 -0
- package/dist_ts/ts/sms/classes.smsservice.d.ts +15 -0
- package/dist_ts/ts/sms/classes.smsservice.js +72 -0
- package/dist_ts/ts/sms/config/sms.config.d.ts +93 -0
- package/dist_ts/ts/sms/config/sms.config.js +2 -0
- package/dist_ts/ts/sms/config/sms.schema.d.ts +5 -0
- package/dist_ts/ts/sms/config/sms.schema.js +121 -0
- package/dist_ts/ts/sms/index.d.ts +1 -0
- package/dist_ts/ts/sms/index.js +2 -0
- package/dist_ts/ts/storage/classes.storagemanager.d.ts +82 -0
- package/dist_ts/ts/storage/classes.storagemanager.js +341 -0
- package/dist_ts/ts/storage/index.d.ts +1 -0
- package/dist_ts/ts/storage/index.js +3 -0
- package/dist_ts/ts_interfaces/data/auth.d.ts +8 -0
- package/dist_ts/ts_interfaces/data/auth.js +2 -0
- package/dist_ts/ts_interfaces/data/index.d.ts +2 -0
- package/dist_ts/ts_interfaces/data/index.js +3 -0
- package/dist_ts/ts_interfaces/data/stats.d.ts +93 -0
- package/dist_ts/ts_interfaces/data/stats.js +2 -0
- package/dist_ts/ts_interfaces/index.d.ts +5 -0
- package/dist_ts/ts_interfaces/index.js +8 -0
- package/dist_ts/ts_interfaces/plugins.d.ts +2 -0
- package/dist_ts/ts_interfaces/plugins.js +4 -0
- package/dist_ts/ts_interfaces/requests/admin.d.ts +31 -0
- package/dist_ts/ts_interfaces/requests/admin.js +3 -0
- package/dist_ts/ts_interfaces/requests/config.d.ts +25 -0
- package/dist_ts/ts_interfaces/requests/config.js +3 -0
- package/dist_ts/ts_interfaces/requests/index.d.ts +4 -0
- package/dist_ts/ts_interfaces/requests/index.js +5 -0
- package/dist_ts/ts_interfaces/requests/logs.d.ts +34 -0
- package/dist_ts/ts_interfaces/requests/logs.js +4 -0
- package/dist_ts/ts_interfaces/requests/stats.d.ts +131 -0
- package/dist_ts/ts_interfaces/requests/stats.js +4 -0
- package/html/index.html +121 -0
- package/npmextra.json +45 -0
- package/package.json +83 -0
- package/readme.hints.md +906 -0
- package/readme.md +1253 -0
- package/readme.opsserver.md +351 -0
- package/test/helpers/server.loader.ts +347 -0
- package/test/helpers/smtp.client.ts +209 -0
- package/test/helpers/utils.ts +311 -0
- package/test/readme.md +443 -0
- package/test/suite/smtpclient_commands/test.ccmd-01.ehlo-helo-sending.ts +168 -0
- package/test/suite/smtpclient_commands/test.ccmd-02.mail-from-parameters.ts +277 -0
- package/test/suite/smtpclient_commands/test.ccmd-03.rcpt-to-multiple.ts +283 -0
- package/test/suite/smtpclient_commands/test.ccmd-04.data-transmission.ts +274 -0
- package/test/suite/smtpclient_commands/test.ccmd-05.auth-mechanisms.ts +306 -0
- package/test/suite/smtpclient_commands/test.ccmd-06.command-pipelining.ts +233 -0
- package/test/suite/smtpclient_commands/test.ccmd-07.response-parsing.ts +243 -0
- package/test/suite/smtpclient_commands/test.ccmd-08.rset-command.ts +333 -0
- package/test/suite/smtpclient_commands/test.ccmd-09.noop-command.ts +339 -0
- package/test/suite/smtpclient_commands/test.ccmd-10.vrfy-expn.ts +457 -0
- package/test/suite/smtpclient_commands/test.ccmd-11.help-command.ts +409 -0
- package/test/suite/smtpclient_connection/test.ccm-01.basic-tcp-connection.ts +150 -0
- package/test/suite/smtpclient_connection/test.ccm-02.tls-connection.ts +140 -0
- package/test/suite/smtpclient_connection/test.ccm-03.starttls-upgrade.ts +208 -0
- package/test/suite/smtpclient_connection/test.ccm-04.connection-pooling.ts +250 -0
- package/test/suite/smtpclient_connection/test.ccm-05.connection-reuse.ts +288 -0
- package/test/suite/smtpclient_connection/test.ccm-06.connection-timeout.ts +267 -0
- package/test/suite/smtpclient_connection/test.ccm-07.automatic-reconnection.ts +324 -0
- package/test/suite/smtpclient_connection/test.ccm-08.dns-resolution.ts +139 -0
- package/test/suite/smtpclient_connection/test.ccm-09.ipv6-dual-stack.ts +167 -0
- package/test/suite/smtpclient_connection/test.ccm-10.proxy-support.ts +305 -0
- package/test/suite/smtpclient_connection/test.ccm-11.keepalive.ts +299 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-01.unusual-server-responses.ts +529 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-02.malformed-commands.ts +438 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-03.protocol-violations.ts +446 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-04.resource-constraints.ts +530 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-05.encoding-issues.ts +145 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-06.large-headers.ts +180 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-07.concurrent-operations.ts +204 -0
- package/test/suite/smtpclient_email-composition/test.cep-01.basic-headers.ts +245 -0
- package/test/suite/smtpclient_email-composition/test.cep-02.mime-multipart.ts +321 -0
- package/test/suite/smtpclient_email-composition/test.cep-03.attachment-encoding.ts +334 -0
- package/test/suite/smtpclient_email-composition/test.cep-04.bcc-handling.ts +187 -0
- package/test/suite/smtpclient_email-composition/test.cep-05.reply-to-return-path.ts +277 -0
- package/test/suite/smtpclient_email-composition/test.cep-06.utf8-international.ts +235 -0
- package/test/suite/smtpclient_email-composition/test.cep-07.html-inline-images.ts +489 -0
- package/test/suite/smtpclient_email-composition/test.cep-08.custom-headers.ts +293 -0
- package/test/suite/smtpclient_email-composition/test.cep-09.priority-importance.ts +314 -0
- package/test/suite/smtpclient_email-composition/test.cep-10.receipts-dsn.ts +411 -0
- package/test/suite/smtpclient_error-handling/test.cerr-01.4xx-errors.ts +232 -0
- package/test/suite/smtpclient_error-handling/test.cerr-02.5xx-errors.ts +309 -0
- package/test/suite/smtpclient_error-handling/test.cerr-03.network-failures.ts +299 -0
- package/test/suite/smtpclient_error-handling/test.cerr-04.greylisting-handling.ts +255 -0
- package/test/suite/smtpclient_error-handling/test.cerr-05.quota-exceeded.ts +273 -0
- package/test/suite/smtpclient_error-handling/test.cerr-06.invalid-recipients.ts +320 -0
- package/test/suite/smtpclient_error-handling/test.cerr-07.message-size-limits.ts +320 -0
- package/test/suite/smtpclient_error-handling/test.cerr-08.rate-limiting.ts +261 -0
- package/test/suite/smtpclient_error-handling/test.cerr-09.connection-pool-errors.ts +299 -0
- package/test/suite/smtpclient_error-handling/test.cerr-10.partial-failure.ts +373 -0
- package/test/suite/smtpclient_performance/test.cperf-01.bulk-sending.ts +332 -0
- package/test/suite/smtpclient_performance/test.cperf-02.message-throughput.ts +304 -0
- package/test/suite/smtpclient_performance/test.cperf-03.memory-usage.ts +332 -0
- package/test/suite/smtpclient_performance/test.cperf-04.cpu-utilization.ts +373 -0
- package/test/suite/smtpclient_performance/test.cperf-05.network-efficiency.ts +181 -0
- package/test/suite/smtpclient_performance/test.cperf-06.caching-strategies.ts +190 -0
- package/test/suite/smtpclient_performance/test.cperf-07.queue-management.ts +171 -0
- package/test/suite/smtpclient_performance/test.cperf-08.dns-caching.ts +50 -0
- package/test/suite/smtpclient_reliability/test.crel-01.reconnection-logic.ts +305 -0
- package/test/suite/smtpclient_reliability/test.crel-02.network-interruption.ts +207 -0
- package/test/suite/smtpclient_reliability/test.crel-03.queue-persistence.ts +469 -0
- package/test/suite/smtpclient_reliability/test.crel-04.crash-recovery.ts +520 -0
- package/test/suite/smtpclient_reliability/test.crel-05.memory-leaks.ts +503 -0
- package/test/suite/smtpclient_reliability/test.crel-06.concurrency-safety.ts +558 -0
- package/test/suite/smtpclient_reliability/test.crel-07.resource-cleanup.ts +52 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-01.rfc5321-client.ts +283 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-02.esmtp-compliance.ts +77 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-03.command-syntax.ts +67 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-04.response-codes.ts +54 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-05.state-machine.ts +703 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-06.protocol-negotiation.ts +688 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-07.interoperability.ts +728 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-08.smtp-extensions.ts +656 -0
- package/test/suite/smtpclient_security/test.csec-01.tls-verification.ts +88 -0
- package/test/suite/smtpclient_security/test.csec-02.oauth2-authentication.ts +132 -0
- package/test/suite/smtpclient_security/test.csec-03.dkim-signing.ts +138 -0
- package/test/suite/smtpclient_security/test.csec-04.spf-compliance.ts +163 -0
- package/test/suite/smtpclient_security/test.csec-05.dmarc-policy.ts +200 -0
- package/test/suite/smtpclient_security/test.csec-06.certificate-validation.ts +145 -0
- package/test/suite/smtpclient_security/test.csec-07.cipher-suites.ts +153 -0
- package/test/suite/smtpclient_security/test.csec-08.authentication-fallback.ts +154 -0
- package/test/suite/smtpclient_security/test.csec-09.relay-restrictions.ts +166 -0
- package/test/suite/smtpclient_security/test.csec-10.anti-spam-measures.ts +196 -0
- package/test/suite/smtpserver_commands/test.cmd-01.ehlo-command.ts +193 -0
- package/test/suite/smtpserver_commands/test.cmd-02.mail-from.ts +330 -0
- package/test/suite/smtpserver_commands/test.cmd-03.rcpt-to.ts +296 -0
- package/test/suite/smtpserver_commands/test.cmd-04.data-command.ts +395 -0
- package/test/suite/smtpserver_commands/test.cmd-05.noop-command.ts +320 -0
- package/test/suite/smtpserver_commands/test.cmd-06.rset-command.ts +399 -0
- package/test/suite/smtpserver_commands/test.cmd-07.vrfy-command.ts +391 -0
- package/test/suite/smtpserver_commands/test.cmd-08.expn-command.ts +450 -0
- package/test/suite/smtpserver_commands/test.cmd-09.size-extension.ts +465 -0
- package/test/suite/smtpserver_commands/test.cmd-10.help-command.ts +454 -0
- package/test/suite/smtpserver_commands/test.cmd-11.command-pipelining.ts +334 -0
- package/test/suite/smtpserver_commands/test.cmd-12.helo-command.ts +420 -0
- package/test/suite/smtpserver_commands/test.cmd-13.quit-command.ts +384 -0
- package/test/suite/smtpserver_connection/test.cm-01.tls-connection.ts +61 -0
- package/test/suite/smtpserver_connection/test.cm-02.multiple-connections.ts +112 -0
- package/test/suite/smtpserver_connection/test.cm-03.connection-timeout.ts +134 -0
- package/test/suite/smtpserver_connection/test.cm-04.connection-limits.ts +374 -0
- package/test/suite/smtpserver_connection/test.cm-05.connection-rejection.ts +296 -0
- package/test/suite/smtpserver_connection/test.cm-06.starttls-upgrade.ts +468 -0
- package/test/suite/smtpserver_connection/test.cm-07.abrupt-disconnection.ts +321 -0
- package/test/suite/smtpserver_connection/test.cm-08.tls-versions.ts +361 -0
- package/test/suite/smtpserver_connection/test.cm-09.tls-ciphers.ts +556 -0
- package/test/suite/smtpserver_connection/test.cm-10.plain-connection.ts +293 -0
- package/test/suite/smtpserver_connection/test.cm-11.keepalive.ts +382 -0
- package/test/suite/smtpserver_edge-cases/test.edge-01.very-large-email.ts +239 -0
- package/test/suite/smtpserver_edge-cases/test.edge-02.very-small-email.ts +389 -0
- package/test/suite/smtpserver_edge-cases/test.edge-03.invalid-character-handling.ts +479 -0
- package/test/suite/smtpserver_edge-cases/test.edge-04.empty-commands.ts +430 -0
- package/test/suite/smtpserver_edge-cases/test.edge-05.extremely-long-lines.ts +425 -0
- package/test/suite/smtpserver_edge-cases/test.edge-06.extremely-long-headers.ts +404 -0
- package/test/suite/smtpserver_edge-cases/test.edge-07.unusual-mime-types.ts +333 -0
- package/test/suite/smtpserver_edge-cases/test.edge-08.nested-mime-structures.ts +379 -0
- package/test/suite/smtpserver_email-processing/test.ep-01.basic-email-sending.ts +338 -0
- package/test/suite/smtpserver_email-processing/test.ep-02.invalid-email-addresses.ts +315 -0
- package/test/suite/smtpserver_email-processing/test.ep-03.multiple-recipients.ts +493 -0
- package/test/suite/smtpserver_email-processing/test.ep-04.large-email.ts +528 -0
- package/test/suite/smtpserver_email-processing/test.ep-05.mime-handling.ts +515 -0
- package/test/suite/smtpserver_email-processing/test.ep-06.attachment-handling.ts +629 -0
- package/test/suite/smtpserver_email-processing/test.ep-07.special-character-handling.ts +462 -0
- package/test/suite/smtpserver_email-processing/test.ep-08.email-routing.ts +527 -0
- package/test/suite/smtpserver_email-processing/test.ep-09.delivery-status-notifications.ts +486 -0
- package/test/suite/smtpserver_error-handling/test.err-01.syntax-errors.ts +475 -0
- package/test/suite/smtpserver_error-handling/test.err-02.invalid-sequence.ts +450 -0
- package/test/suite/smtpserver_error-handling/test.err-03.temporary-failures.ts +453 -0
- package/test/suite/smtpserver_error-handling/test.err-04.permanent-failures.ts +325 -0
- package/test/suite/smtpserver_error-handling/test.err-05.resource-exhaustion.ts +302 -0
- package/test/suite/smtpserver_error-handling/test.err-06.malformed-mime.ts +374 -0
- package/test/suite/smtpserver_error-handling/test.err-07.exception-handling.ts +333 -0
- package/test/suite/smtpserver_error-handling/test.err-08.error-logging.ts +324 -0
- package/test/suite/smtpserver_performance/test.perf-01.throughput.ts +183 -0
- package/test/suite/smtpserver_performance/test.perf-02.concurrency.ts +388 -0
- package/test/suite/smtpserver_performance/test.perf-03.cpu-utilization.ts +245 -0
- package/test/suite/smtpserver_performance/test.perf-04.memory-usage.ts +238 -0
- package/test/suite/smtpserver_performance/test.perf-05.connection-processing-time.ts +363 -0
- package/test/suite/smtpserver_performance/test.perf-06.message-processing-time.ts +252 -0
- package/test/suite/smtpserver_performance/test.perf-07.resource-cleanup.ts +317 -0
- package/test/suite/smtpserver_reliability/test.rel-01.long-running-operation.ts +344 -0
- package/test/suite/smtpserver_reliability/test.rel-02.restart-recovery.ts +328 -0
- package/test/suite/smtpserver_reliability/test.rel-03.resource-leak-detection.ts +394 -0
- package/test/suite/smtpserver_reliability/test.rel-04.error-recovery.ts +401 -0
- package/test/suite/smtpserver_reliability/test.rel-05.dns-resolution-failure.ts +335 -0
- package/test/suite/smtpserver_reliability/test.rel-06.network-interruption.ts +410 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-01.rfc5321-compliance.ts +382 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-02.rfc5322-compliance.ts +428 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-03.rfc7208-spf-compliance.ts +330 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-04.rfc6376-dkim-compliance.ts +450 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-05.rfc7489-dmarc-compliance.ts +408 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-06.rfc8314-tls-compliance.ts +366 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-07.rfc3461-dsn-compliance.ts +399 -0
- package/test/suite/smtpserver_security/test.sec-01.authentication.ts +218 -0
- package/test/suite/smtpserver_security/test.sec-02.authorization.ts +286 -0
- package/test/suite/smtpserver_security/test.sec-03.dkim-processing.ts +414 -0
- package/test/suite/smtpserver_security/test.sec-04.spf-checking.ts +280 -0
- package/test/suite/smtpserver_security/test.sec-05.dmarc-policy.ts +374 -0
- package/test/suite/smtpserver_security/test.sec-06.ip-reputation.ts +303 -0
- package/test/suite/smtpserver_security/test.sec-07.content-scanning.ts +409 -0
- package/test/suite/smtpserver_security/test.sec-08.rate-limiting.ts +324 -0
- package/test/suite/smtpserver_security/test.sec-09.tls-certificate-validation.ts +312 -0
- package/test/suite/smtpserver_security/test.sec-10.header-injection-prevention.ts +332 -0
- package/test/suite/smtpserver_security/test.sec-11.bounce-management.ts +363 -0
- package/test/test.base.ts +65 -0
- package/test/test.bouncemanager.ts +196 -0
- package/test/test.config.md +175 -0
- package/test/test.contentscanner.ts +265 -0
- package/test/test.dcrouter.email.ts +201 -0
- package/test/test.deliverability.ts +55 -0
- package/test/test.dns-manager-creation.ts +141 -0
- package/test/test.dns-mode-switching.ts +257 -0
- package/test/test.dns-server-config.ts +140 -0
- package/test/test.dns-socket-handler.ts +169 -0
- package/test/test.dns-validation.ts +283 -0
- package/test/test.email-socket-handler.ts +228 -0
- package/test/test.email.integration.ts +377 -0
- package/test/test.email.router.ts +283 -0
- package/test/test.emailauth.ts +195 -0
- package/test/test.errors.ts +408 -0
- package/test/test.integration.storage.ts +313 -0
- package/test/test.integration.ts +75 -0
- package/test/test.ipreputationchecker.ts +179 -0
- package/test/test.ipwarmupmanager.ts +323 -0
- package/test/test.jwt-auth.ts +130 -0
- package/test/test.minimal.ts +66 -0
- package/test/test.opsserver-api.ts +83 -0
- package/test/test.protected-endpoint.ts +115 -0
- package/test/test.rate-limiting-integration.ts +236 -0
- package/test/test.ratelimiter.ts +141 -0
- package/test/test.reputationmonitor.ts +262 -0
- package/test/test.smartmail.ts +248 -0
- package/test/test.smtp.client.compatibility.ts +154 -0
- package/test/test.smtp.client.ts +191 -0
- package/test/test.smtp.server.ts +180 -0
- package/test/test.socket-handler-integration.ts +240 -0
- package/test/test.socket-handler-unit.ts +198 -0
- package/test/test.storagemanager.ts +289 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.dcrouter.ts +1310 -0
- package/ts/config/index.ts +2 -0
- package/ts/config/validator.ts +266 -0
- package/ts/deliverability/classes.ipwarmupmanager.ts +896 -0
- package/ts/deliverability/classes.senderreputationmonitor.ts +1244 -0
- package/ts/deliverability/index.ts +13 -0
- package/ts/errors/base.errors.ts +525 -0
- package/ts/errors/email.errors.ts +383 -0
- package/ts/errors/error-handler.ts +412 -0
- package/ts/errors/error.codes.ts +165 -0
- package/ts/errors/index.ts +195 -0
- package/ts/errors/mta.errors.ts +681 -0
- package/ts/errors/reputation.errors.ts +422 -0
- package/ts/index.ts +7 -0
- package/ts/logger.ts +91 -0
- package/ts/mail/core/classes.bouncemanager.ts +965 -0
- package/ts/mail/core/classes.email.ts +941 -0
- package/ts/mail/core/classes.emailvalidator.ts +239 -0
- package/ts/mail/core/classes.templatemanager.ts +320 -0
- package/ts/mail/core/index.ts +5 -0
- package/ts/mail/delivery/classes.delivery.queue.ts +645 -0
- package/ts/mail/delivery/classes.delivery.system.ts +1089 -0
- package/ts/mail/delivery/classes.emailsendjob.ts +447 -0
- package/ts/mail/delivery/classes.emailsendjob.ts.backup +691 -0
- package/ts/mail/delivery/classes.emailsignjob.ts +67 -0
- package/ts/mail/delivery/classes.mta.config.ts +73 -0
- package/ts/mail/delivery/classes.ratelimiter.ts +281 -0
- package/ts/mail/delivery/classes.smtp.client.legacy.ts +1422 -0
- package/ts/mail/delivery/classes.unified.rate.limiter.ts +1053 -0
- package/ts/mail/delivery/index.ts +24 -0
- package/ts/mail/delivery/interfaces.ts +291 -0
- package/ts/mail/delivery/smtpclient/auth-handler.ts +232 -0
- package/ts/mail/delivery/smtpclient/command-handler.ts +343 -0
- package/ts/mail/delivery/smtpclient/connection-manager.ts +289 -0
- package/ts/mail/delivery/smtpclient/constants.ts +145 -0
- package/ts/mail/delivery/smtpclient/create-client.ts +94 -0
- package/ts/mail/delivery/smtpclient/error-handler.ts +141 -0
- package/ts/mail/delivery/smtpclient/index.ts +24 -0
- package/ts/mail/delivery/smtpclient/interfaces.ts +242 -0
- package/ts/mail/delivery/smtpclient/smtp-client.ts +357 -0
- package/ts/mail/delivery/smtpclient/tls-handler.ts +254 -0
- package/ts/mail/delivery/smtpclient/utils/helpers.ts +224 -0
- package/ts/mail/delivery/smtpclient/utils/logging.ts +212 -0
- package/ts/mail/delivery/smtpclient/utils/validation.ts +170 -0
- package/ts/mail/delivery/smtpserver/certificate-utils.ts +398 -0
- package/ts/mail/delivery/smtpserver/command-handler.ts +1340 -0
- package/ts/mail/delivery/smtpserver/connection-manager.ts +1045 -0
- package/ts/mail/delivery/smtpserver/constants.ts +181 -0
- package/ts/mail/delivery/smtpserver/create-server.ts +31 -0
- package/ts/mail/delivery/smtpserver/data-handler.ts +1283 -0
- package/ts/mail/delivery/smtpserver/index.ts +32 -0
- package/ts/mail/delivery/smtpserver/interfaces.ts +655 -0
- package/ts/mail/delivery/smtpserver/secure-server.ts +97 -0
- package/ts/mail/delivery/smtpserver/security-handler.ts +345 -0
- package/ts/mail/delivery/smtpserver/session-manager.ts +557 -0
- package/ts/mail/delivery/smtpserver/smtp-server.ts +804 -0
- package/ts/mail/delivery/smtpserver/starttls-handler.ts +262 -0
- package/ts/mail/delivery/smtpserver/tls-handler.ts +346 -0
- package/ts/mail/delivery/smtpserver/utils/adaptive-logging.ts +514 -0
- package/ts/mail/delivery/smtpserver/utils/helpers.ts +246 -0
- package/ts/mail/delivery/smtpserver/utils/logging.ts +246 -0
- package/ts/mail/delivery/smtpserver/utils/validation.ts +436 -0
- package/ts/mail/index.ts +19 -0
- package/ts/mail/routing/classes.dns.manager.ts +563 -0
- package/ts/mail/routing/classes.dnsmanager.ts +559 -0
- package/ts/mail/routing/classes.domain.registry.ts +139 -0
- package/ts/mail/routing/classes.email.config.ts +82 -0
- package/ts/mail/routing/classes.email.router.ts +575 -0
- package/ts/mail/routing/classes.unified.email.server.ts +1873 -0
- package/ts/mail/routing/index.ts +6 -0
- package/ts/mail/routing/interfaces.ts +202 -0
- package/ts/mail/security/classes.dkimcreator.ts +431 -0
- package/ts/mail/security/classes.dkimverifier.ts +382 -0
- package/ts/mail/security/classes.dmarcverifier.ts +478 -0
- package/ts/mail/security/classes.spfverifier.ts +606 -0
- package/ts/mail/security/index.ts +5 -0
- package/ts/opsserver/classes.opsserver.ts +65 -0
- package/ts/opsserver/handlers/admin.handler.ts +240 -0
- package/ts/opsserver/handlers/config.handler.ts +150 -0
- package/ts/opsserver/handlers/index.ts +5 -0
- package/ts/opsserver/handlers/logs.handler.ts +195 -0
- package/ts/opsserver/handlers/security.handler.ts +208 -0
- package/ts/opsserver/handlers/stats.handler.ts +344 -0
- package/ts/opsserver/helpers/guards.ts +56 -0
- package/ts/opsserver/index.ts +1 -0
- package/ts/paths.ts +48 -0
- package/ts/plugins.ts +94 -0
- package/ts/security/classes.contentscanner.ts +739 -0
- package/ts/security/classes.ipreputationchecker.ts +592 -0
- package/ts/security/classes.securitylogger.ts +299 -0
- package/ts/security/index.ts +21 -0
- package/ts/sms/classes.smsservice.ts +98 -0
- package/ts/sms/config/sms.config.ts +109 -0
- package/ts/sms/config/sms.schema.ts +122 -0
- package/ts/sms/index.ts +1 -0
- package/ts/storage/classes.storagemanager.ts +400 -0
- package/ts/storage/index.ts +2 -0
- package/ts/tspublish.json +3 -0
- package/ts_interfaces/data/auth.ts +8 -0
- package/ts_interfaces/data/index.ts +2 -0
- package/ts_interfaces/data/stats.ts +101 -0
- package/ts_interfaces/index.ts +9 -0
- package/ts_interfaces/plugins.ts +6 -0
- package/ts_interfaces/requests/admin.ts +46 -0
- package/ts_interfaces/requests/config.ts +35 -0
- package/ts_interfaces/requests/index.ts +4 -0
- package/ts_interfaces/requests/logs.ts +44 -0
- package/ts_interfaces/requests/stats.ts +162 -0
- package/ts_interfaces/tspublish.json +3 -0
- package/ts_web/00_commitinfo_data.ts +8 -0
- package/ts_web/appstate.ts +361 -0
- package/ts_web/elements/index.ts +7 -0
- package/ts_web/elements/ops-dashboard.ts +165 -0
- package/ts_web/elements/ops-view-config.ts +268 -0
- package/ts_web/elements/ops-view-logs.ts +207 -0
- package/ts_web/elements/ops-view-overview.ts +222 -0
- package/ts_web/elements/ops-view-security.ts +471 -0
- package/ts_web/elements/ops-view-stats.ts +299 -0
- package/ts_web/elements/shared/css.ts +10 -0
- package/ts_web/elements/shared/index.ts +2 -0
- package/ts_web/elements/shared/ops-sectionheading.ts +42 -0
- package/ts_web/index.ts +9 -0
- package/ts_web/plugins.ts +11 -0
- package/ts_web/tspublish.json +3 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,1422 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { logger } from '../../logger.js';
|
|
3
|
+
import {
|
|
4
|
+
SecurityLogger,
|
|
5
|
+
SecurityLogLevel,
|
|
6
|
+
SecurityEventType
|
|
7
|
+
} from '../../security/index.js';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
MtaConnectionError,
|
|
11
|
+
MtaAuthenticationError,
|
|
12
|
+
MtaDeliveryError,
|
|
13
|
+
MtaConfigurationError,
|
|
14
|
+
MtaTimeoutError,
|
|
15
|
+
MtaProtocolError
|
|
16
|
+
} from '../../errors/index.js';
|
|
17
|
+
|
|
18
|
+
import { Email } from '../core/classes.email.js';
|
|
19
|
+
import type { EmailProcessingMode } from './interfaces.js';
|
|
20
|
+
|
|
21
|
+
// Custom error type extension
|
|
22
|
+
interface NodeNetworkError extends Error {
|
|
23
|
+
code?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* SMTP client connection options
|
|
28
|
+
*/
|
|
29
|
+
export type ISmtpClientOptions = {
|
|
30
|
+
/**
|
|
31
|
+
* Hostname of the SMTP server
|
|
32
|
+
*/
|
|
33
|
+
host: string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Port to connect to
|
|
37
|
+
*/
|
|
38
|
+
port: number;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Whether to use TLS for the connection
|
|
42
|
+
*/
|
|
43
|
+
secure?: boolean;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Connection timeout in milliseconds
|
|
47
|
+
*/
|
|
48
|
+
connectionTimeout?: number;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Socket timeout in milliseconds
|
|
52
|
+
*/
|
|
53
|
+
socketTimeout?: number;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Command timeout in milliseconds
|
|
57
|
+
*/
|
|
58
|
+
commandTimeout?: number;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* TLS options
|
|
62
|
+
*/
|
|
63
|
+
tls?: {
|
|
64
|
+
/**
|
|
65
|
+
* Whether to verify certificates
|
|
66
|
+
*/
|
|
67
|
+
rejectUnauthorized?: boolean;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Minimum TLS version
|
|
71
|
+
*/
|
|
72
|
+
minVersion?: string;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* CA certificate path
|
|
76
|
+
*/
|
|
77
|
+
ca?: string;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Authentication options
|
|
82
|
+
*/
|
|
83
|
+
auth?: {
|
|
84
|
+
/**
|
|
85
|
+
* Authentication user
|
|
86
|
+
*/
|
|
87
|
+
user: string;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Authentication password
|
|
91
|
+
*/
|
|
92
|
+
pass: string;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Authentication method
|
|
96
|
+
*/
|
|
97
|
+
method?: 'PLAIN' | 'LOGIN' | 'OAUTH2';
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Domain name for EHLO
|
|
102
|
+
*/
|
|
103
|
+
domain?: string;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* DKIM options for signing outgoing emails
|
|
107
|
+
*/
|
|
108
|
+
dkim?: {
|
|
109
|
+
/**
|
|
110
|
+
* Whether to sign emails with DKIM
|
|
111
|
+
*/
|
|
112
|
+
enabled: boolean;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Domain name for DKIM
|
|
116
|
+
*/
|
|
117
|
+
domain: string;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Selector for DKIM
|
|
121
|
+
*/
|
|
122
|
+
selector: string;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Private key for DKIM signing
|
|
126
|
+
*/
|
|
127
|
+
privateKey: string;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Headers to sign
|
|
131
|
+
*/
|
|
132
|
+
headers?: string[];
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* SMTP delivery result
|
|
138
|
+
*/
|
|
139
|
+
export type ISmtpDeliveryResult = {
|
|
140
|
+
/**
|
|
141
|
+
* Whether the delivery was successful
|
|
142
|
+
*/
|
|
143
|
+
success: boolean;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Message ID if successful
|
|
147
|
+
*/
|
|
148
|
+
messageId?: string;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Error message if failed
|
|
152
|
+
*/
|
|
153
|
+
error?: string;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* SMTP response code
|
|
157
|
+
*/
|
|
158
|
+
responseCode?: string;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Recipients successfully delivered to
|
|
162
|
+
*/
|
|
163
|
+
acceptedRecipients: string[];
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Recipients rejected during delivery
|
|
167
|
+
*/
|
|
168
|
+
rejectedRecipients: string[];
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Server response
|
|
172
|
+
*/
|
|
173
|
+
response?: string;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Timestamp of the delivery attempt
|
|
177
|
+
*/
|
|
178
|
+
timestamp: number;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Whether DKIM signing was applied
|
|
182
|
+
*/
|
|
183
|
+
dkimSigned?: boolean;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Whether this was a TLS secured delivery
|
|
187
|
+
*/
|
|
188
|
+
secure?: boolean;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Whether authentication was used
|
|
192
|
+
*/
|
|
193
|
+
authenticated?: boolean;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* SMTP client for sending emails to remote mail servers
|
|
198
|
+
*/
|
|
199
|
+
export class SmtpClient {
|
|
200
|
+
private options: ISmtpClientOptions;
|
|
201
|
+
private connected: boolean = false;
|
|
202
|
+
private socket?: plugins.net.Socket | plugins.tls.TLSSocket;
|
|
203
|
+
private supportedExtensions: Set<string> = new Set();
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Create a new SMTP client instance
|
|
207
|
+
* @param options SMTP client connection options
|
|
208
|
+
*/
|
|
209
|
+
constructor(options: ISmtpClientOptions) {
|
|
210
|
+
// Set default options
|
|
211
|
+
this.options = {
|
|
212
|
+
...options,
|
|
213
|
+
connectionTimeout: options.connectionTimeout || 30000, // 30 seconds
|
|
214
|
+
socketTimeout: options.socketTimeout || 60000, // 60 seconds
|
|
215
|
+
commandTimeout: options.commandTimeout || 30000, // 30 seconds
|
|
216
|
+
secure: options.secure || false,
|
|
217
|
+
domain: options.domain || 'localhost',
|
|
218
|
+
tls: {
|
|
219
|
+
rejectUnauthorized: options.tls?.rejectUnauthorized !== false, // Default to true
|
|
220
|
+
minVersion: options.tls?.minVersion || 'TLSv1.2'
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Connect to the SMTP server
|
|
227
|
+
*/
|
|
228
|
+
public async connect(): Promise<void> {
|
|
229
|
+
if (this.connected && this.socket) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
logger.log('info', `Connecting to SMTP server ${this.options.host}:${this.options.port}`);
|
|
235
|
+
|
|
236
|
+
// Create socket
|
|
237
|
+
const socket = new plugins.net.Socket();
|
|
238
|
+
|
|
239
|
+
// Set timeouts
|
|
240
|
+
socket.setTimeout(this.options.socketTimeout);
|
|
241
|
+
|
|
242
|
+
// Connect to the server
|
|
243
|
+
await new Promise<void>((resolve, reject) => {
|
|
244
|
+
// Handle connection events
|
|
245
|
+
socket.once('connect', () => {
|
|
246
|
+
logger.log('debug', `Connected to ${this.options.host}:${this.options.port}`);
|
|
247
|
+
resolve();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
socket.once('timeout', () => {
|
|
251
|
+
reject(MtaConnectionError.timeout(
|
|
252
|
+
this.options.host,
|
|
253
|
+
this.options.port,
|
|
254
|
+
this.options.connectionTimeout
|
|
255
|
+
));
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
socket.once('error', (err: NodeNetworkError) => {
|
|
259
|
+
if (err.code === 'ECONNREFUSED') {
|
|
260
|
+
reject(MtaConnectionError.refused(
|
|
261
|
+
this.options.host,
|
|
262
|
+
this.options.port
|
|
263
|
+
));
|
|
264
|
+
} else if (err.code === 'ENOTFOUND') {
|
|
265
|
+
reject(MtaConnectionError.dnsError(
|
|
266
|
+
this.options.host,
|
|
267
|
+
err
|
|
268
|
+
));
|
|
269
|
+
} else {
|
|
270
|
+
reject(new MtaConnectionError(
|
|
271
|
+
`Connection error to ${this.options.host}:${this.options.port}: ${err.message}`,
|
|
272
|
+
{
|
|
273
|
+
data: {
|
|
274
|
+
host: this.options.host,
|
|
275
|
+
port: this.options.port,
|
|
276
|
+
error: err.message,
|
|
277
|
+
code: err.code
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
));
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Connect to the server
|
|
285
|
+
const connectOptions = {
|
|
286
|
+
host: this.options.host,
|
|
287
|
+
port: this.options.port
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// For direct TLS connections
|
|
291
|
+
if (this.options.secure) {
|
|
292
|
+
const tlsSocket = plugins.tls.connect({
|
|
293
|
+
...connectOptions,
|
|
294
|
+
rejectUnauthorized: this.options.tls.rejectUnauthorized,
|
|
295
|
+
minVersion: this.options.tls.minVersion as any,
|
|
296
|
+
ca: this.options.tls.ca ? [this.options.tls.ca] : undefined
|
|
297
|
+
} as plugins.tls.ConnectionOptions);
|
|
298
|
+
|
|
299
|
+
tlsSocket.once('secureConnect', () => {
|
|
300
|
+
logger.log('debug', `Secure connection established to ${this.options.host}:${this.options.port}`);
|
|
301
|
+
this.socket = tlsSocket;
|
|
302
|
+
resolve();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
tlsSocket.once('error', (err: NodeNetworkError) => {
|
|
306
|
+
reject(new MtaConnectionError(
|
|
307
|
+
`TLS connection error to ${this.options.host}:${this.options.port}: ${err.message}`,
|
|
308
|
+
{
|
|
309
|
+
data: {
|
|
310
|
+
host: this.options.host,
|
|
311
|
+
port: this.options.port,
|
|
312
|
+
error: err.message,
|
|
313
|
+
code: err.code
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
));
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
tlsSocket.setTimeout(this.options.socketTimeout);
|
|
320
|
+
|
|
321
|
+
tlsSocket.once('timeout', () => {
|
|
322
|
+
reject(MtaConnectionError.timeout(
|
|
323
|
+
this.options.host,
|
|
324
|
+
this.options.port,
|
|
325
|
+
this.options.connectionTimeout
|
|
326
|
+
));
|
|
327
|
+
});
|
|
328
|
+
} else {
|
|
329
|
+
socket.connect(connectOptions);
|
|
330
|
+
this.socket = socket;
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Wait for server greeting
|
|
335
|
+
const greeting = await this.readResponse();
|
|
336
|
+
|
|
337
|
+
if (!greeting.startsWith('220')) {
|
|
338
|
+
throw new MtaConnectionError(
|
|
339
|
+
`Unexpected greeting from server: ${greeting}`,
|
|
340
|
+
{
|
|
341
|
+
data: {
|
|
342
|
+
host: this.options.host,
|
|
343
|
+
port: this.options.port,
|
|
344
|
+
greeting
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Send EHLO
|
|
351
|
+
await this.sendEhlo();
|
|
352
|
+
|
|
353
|
+
// Start TLS if not secure and supported
|
|
354
|
+
if (!this.options.secure && this.supportedExtensions.has('STARTTLS')) {
|
|
355
|
+
await this.startTls();
|
|
356
|
+
|
|
357
|
+
// Send EHLO again after STARTTLS
|
|
358
|
+
await this.sendEhlo();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Authenticate if credentials provided
|
|
362
|
+
if (this.options.auth) {
|
|
363
|
+
await this.authenticate();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
this.connected = true;
|
|
367
|
+
logger.log('info', `Successfully connected to SMTP server ${this.options.host}:${this.options.port}`);
|
|
368
|
+
|
|
369
|
+
// Set up error handling for the socket
|
|
370
|
+
this.socket.on('error', (err) => {
|
|
371
|
+
logger.log('error', `Socket error: ${err.message}`);
|
|
372
|
+
this.connected = false;
|
|
373
|
+
this.socket = undefined;
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
this.socket.on('close', () => {
|
|
377
|
+
logger.log('debug', 'Socket closed');
|
|
378
|
+
this.connected = false;
|
|
379
|
+
this.socket = undefined;
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
this.socket.on('timeout', () => {
|
|
383
|
+
logger.log('error', 'Socket timeout');
|
|
384
|
+
this.connected = false;
|
|
385
|
+
if (this.socket) {
|
|
386
|
+
this.socket.destroy();
|
|
387
|
+
this.socket = undefined;
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
} catch (error) {
|
|
392
|
+
// Clean up socket if connection failed
|
|
393
|
+
if (this.socket) {
|
|
394
|
+
this.socket.destroy();
|
|
395
|
+
this.socket = undefined;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
logger.log('error', `Failed to connect to SMTP server: ${error.message}`);
|
|
399
|
+
throw error;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Send EHLO command to the server
|
|
405
|
+
*/
|
|
406
|
+
private async sendEhlo(): Promise<void> {
|
|
407
|
+
// Clear previous extensions
|
|
408
|
+
this.supportedExtensions.clear();
|
|
409
|
+
|
|
410
|
+
// Send EHLO - don't allow pipelining for this command
|
|
411
|
+
const response = await this.sendCommand(`EHLO ${this.options.domain}`, false);
|
|
412
|
+
|
|
413
|
+
// Parse supported extensions
|
|
414
|
+
const lines = response.split('\r\n');
|
|
415
|
+
for (let i = 1; i < lines.length; i++) {
|
|
416
|
+
const line = lines[i];
|
|
417
|
+
if (line.startsWith('250-') || line.startsWith('250 ')) {
|
|
418
|
+
const extension = line.substring(4).split(' ')[0];
|
|
419
|
+
this.supportedExtensions.add(extension);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Check if server supports pipelining
|
|
424
|
+
this.supportsPipelining = this.supportedExtensions.has('PIPELINING');
|
|
425
|
+
|
|
426
|
+
logger.log('debug', `Server supports extensions: ${Array.from(this.supportedExtensions).join(', ')}`);
|
|
427
|
+
if (this.supportsPipelining) {
|
|
428
|
+
logger.log('info', 'Server supports PIPELINING - will use for improved performance');
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Start TLS negotiation
|
|
434
|
+
*/
|
|
435
|
+
private async startTls(): Promise<void> {
|
|
436
|
+
logger.log('debug', 'Starting TLS negotiation');
|
|
437
|
+
|
|
438
|
+
// Send STARTTLS command
|
|
439
|
+
const response = await this.sendCommand('STARTTLS');
|
|
440
|
+
|
|
441
|
+
if (!response.startsWith('220')) {
|
|
442
|
+
throw new MtaConnectionError(
|
|
443
|
+
`Failed to start TLS: ${response}`,
|
|
444
|
+
{
|
|
445
|
+
data: {
|
|
446
|
+
host: this.options.host,
|
|
447
|
+
port: this.options.port,
|
|
448
|
+
response
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (!this.socket) {
|
|
455
|
+
throw new MtaConnectionError(
|
|
456
|
+
'No socket available for TLS upgrade',
|
|
457
|
+
{
|
|
458
|
+
data: {
|
|
459
|
+
host: this.options.host,
|
|
460
|
+
port: this.options.port
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Upgrade socket to TLS
|
|
467
|
+
const currentSocket = this.socket;
|
|
468
|
+
this.socket = await this.upgradeTls(currentSocket);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Upgrade socket to TLS
|
|
473
|
+
* @param socket Original socket
|
|
474
|
+
*/
|
|
475
|
+
private async upgradeTls(socket: plugins.net.Socket): Promise<plugins.tls.TLSSocket> {
|
|
476
|
+
return new Promise<plugins.tls.TLSSocket>((resolve, reject) => {
|
|
477
|
+
const tlsOptions: plugins.tls.ConnectionOptions = {
|
|
478
|
+
socket,
|
|
479
|
+
servername: this.options.host,
|
|
480
|
+
rejectUnauthorized: this.options.tls.rejectUnauthorized,
|
|
481
|
+
minVersion: this.options.tls.minVersion as any,
|
|
482
|
+
ca: this.options.tls.ca ? [this.options.tls.ca] : undefined
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
const tlsSocket = plugins.tls.connect(tlsOptions);
|
|
486
|
+
|
|
487
|
+
tlsSocket.once('secureConnect', () => {
|
|
488
|
+
logger.log('debug', 'TLS negotiation successful');
|
|
489
|
+
resolve(tlsSocket);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
tlsSocket.once('error', (err: NodeNetworkError) => {
|
|
493
|
+
reject(new MtaConnectionError(
|
|
494
|
+
`TLS error: ${err.message}`,
|
|
495
|
+
{
|
|
496
|
+
data: {
|
|
497
|
+
host: this.options.host,
|
|
498
|
+
port: this.options.port,
|
|
499
|
+
error: err.message,
|
|
500
|
+
code: err.code
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
));
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
tlsSocket.setTimeout(this.options.socketTimeout);
|
|
507
|
+
|
|
508
|
+
tlsSocket.once('timeout', () => {
|
|
509
|
+
reject(MtaTimeoutError.commandTimeout(
|
|
510
|
+
'STARTTLS',
|
|
511
|
+
this.options.host,
|
|
512
|
+
this.options.socketTimeout
|
|
513
|
+
));
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Authenticate with the server
|
|
520
|
+
*/
|
|
521
|
+
private async authenticate(): Promise<void> {
|
|
522
|
+
if (!this.options.auth) {
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const { user, pass, method = 'LOGIN' } = this.options.auth;
|
|
527
|
+
|
|
528
|
+
logger.log('debug', `Authenticating as ${user} using ${method}`);
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
switch (method) {
|
|
532
|
+
case 'PLAIN':
|
|
533
|
+
await this.authPlain(user, pass);
|
|
534
|
+
break;
|
|
535
|
+
|
|
536
|
+
case 'LOGIN':
|
|
537
|
+
await this.authLogin(user, pass);
|
|
538
|
+
break;
|
|
539
|
+
|
|
540
|
+
case 'OAUTH2':
|
|
541
|
+
await this.authOAuth2(user, pass);
|
|
542
|
+
break;
|
|
543
|
+
|
|
544
|
+
default:
|
|
545
|
+
throw new MtaAuthenticationError(
|
|
546
|
+
`Authentication method ${method} not supported by client`,
|
|
547
|
+
{
|
|
548
|
+
data: {
|
|
549
|
+
method
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
logger.log('info', `Successfully authenticated as ${user}`);
|
|
556
|
+
} catch (error) {
|
|
557
|
+
logger.log('error', `Authentication failed: ${error.message}`);
|
|
558
|
+
throw error;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Authenticate using PLAIN method
|
|
564
|
+
* @param user Username
|
|
565
|
+
* @param pass Password
|
|
566
|
+
*/
|
|
567
|
+
private async authPlain(user: string, pass: string): Promise<void> {
|
|
568
|
+
// PLAIN authentication format: \0username\0password
|
|
569
|
+
const authString = Buffer.from(`\0${user}\0${pass}`).toString('base64');
|
|
570
|
+
const response = await this.sendCommand(`AUTH PLAIN ${authString}`);
|
|
571
|
+
|
|
572
|
+
if (!response.startsWith('235')) {
|
|
573
|
+
throw MtaAuthenticationError.invalidCredentials(
|
|
574
|
+
this.options.host,
|
|
575
|
+
user
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Authenticate using LOGIN method
|
|
582
|
+
* @param user Username
|
|
583
|
+
* @param pass Password
|
|
584
|
+
*/
|
|
585
|
+
private async authLogin(user: string, pass: string): Promise<void> {
|
|
586
|
+
// Start LOGIN authentication
|
|
587
|
+
const response = await this.sendCommand('AUTH LOGIN');
|
|
588
|
+
|
|
589
|
+
if (!response.startsWith('334')) {
|
|
590
|
+
throw new MtaAuthenticationError(
|
|
591
|
+
`Server did not accept AUTH LOGIN: ${response}`,
|
|
592
|
+
{
|
|
593
|
+
data: {
|
|
594
|
+
host: this.options.host,
|
|
595
|
+
response
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Send username (base64)
|
|
602
|
+
const userResponse = await this.sendCommand(Buffer.from(user).toString('base64'));
|
|
603
|
+
|
|
604
|
+
if (!userResponse.startsWith('334')) {
|
|
605
|
+
throw MtaAuthenticationError.invalidCredentials(
|
|
606
|
+
this.options.host,
|
|
607
|
+
user
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Send password (base64)
|
|
612
|
+
const passResponse = await this.sendCommand(Buffer.from(pass).toString('base64'));
|
|
613
|
+
|
|
614
|
+
if (!passResponse.startsWith('235')) {
|
|
615
|
+
throw MtaAuthenticationError.invalidCredentials(
|
|
616
|
+
this.options.host,
|
|
617
|
+
user
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Authenticate using OAuth2 method
|
|
624
|
+
* @param user Username
|
|
625
|
+
* @param token OAuth2 token
|
|
626
|
+
*/
|
|
627
|
+
private async authOAuth2(user: string, token: string): Promise<void> {
|
|
628
|
+
// XOAUTH2 format
|
|
629
|
+
const authString = `user=${user}\x01auth=Bearer ${token}\x01\x01`;
|
|
630
|
+
const response = await this.sendCommand(`AUTH XOAUTH2 ${Buffer.from(authString).toString('base64')}`);
|
|
631
|
+
|
|
632
|
+
if (!response.startsWith('235')) {
|
|
633
|
+
throw MtaAuthenticationError.invalidCredentials(
|
|
634
|
+
this.options.host,
|
|
635
|
+
user
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Send an email through the SMTP client
|
|
642
|
+
* @param email Email to send
|
|
643
|
+
* @param processingMode Optional processing mode
|
|
644
|
+
*/
|
|
645
|
+
public async sendMail(email: Email, processingMode?: EmailProcessingMode): Promise<ISmtpDeliveryResult> {
|
|
646
|
+
// Ensure we're connected
|
|
647
|
+
if (!this.connected || !this.socket) {
|
|
648
|
+
await this.connect();
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const startTime = Date.now();
|
|
652
|
+
const result: ISmtpDeliveryResult = {
|
|
653
|
+
success: false,
|
|
654
|
+
acceptedRecipients: [],
|
|
655
|
+
rejectedRecipients: [],
|
|
656
|
+
timestamp: startTime,
|
|
657
|
+
secure: this.options.secure || this.socket instanceof plugins.tls.TLSSocket,
|
|
658
|
+
authenticated: !!this.options.auth
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
try {
|
|
662
|
+
logger.log('info', `Sending email to ${email.getAllRecipients().join(', ')}`);
|
|
663
|
+
|
|
664
|
+
// Apply DKIM signing if configured
|
|
665
|
+
if (this.options.dkim?.enabled) {
|
|
666
|
+
await this.applyDkimSignature(email);
|
|
667
|
+
result.dkimSigned = true;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// Get envelope and recipients
|
|
671
|
+
const envelope_from = email.getEnvelopeFrom() || email.from;
|
|
672
|
+
const recipients = email.getAllRecipients();
|
|
673
|
+
|
|
674
|
+
// Check if we can use pipelining for MAIL FROM and RCPT TO commands
|
|
675
|
+
if (this.supportsPipelining && recipients.length > 0) {
|
|
676
|
+
logger.log('debug', 'Using SMTP pipelining for sending');
|
|
677
|
+
|
|
678
|
+
// Send MAIL FROM command first (always needed)
|
|
679
|
+
const mailFromCmd = `MAIL FROM:<${envelope_from}> SIZE=${this.getEmailSize(email)}`;
|
|
680
|
+
let mailFromResponse: string;
|
|
681
|
+
|
|
682
|
+
try {
|
|
683
|
+
mailFromResponse = await this.sendCommand(mailFromCmd);
|
|
684
|
+
|
|
685
|
+
if (!mailFromResponse.startsWith('250')) {
|
|
686
|
+
throw new MtaDeliveryError(
|
|
687
|
+
`MAIL FROM command failed: ${mailFromResponse}`,
|
|
688
|
+
{
|
|
689
|
+
data: {
|
|
690
|
+
command: mailFromCmd,
|
|
691
|
+
response: mailFromResponse
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
} catch (error) {
|
|
697
|
+
logger.log('error', `MAIL FROM failed: ${error.message}`);
|
|
698
|
+
throw error;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// Pipeline all RCPT TO commands
|
|
702
|
+
const rcptPromises = recipients.map(recipient => {
|
|
703
|
+
return this.sendCommand(`RCPT TO:<${recipient}>`)
|
|
704
|
+
.then(response => {
|
|
705
|
+
if (response.startsWith('250')) {
|
|
706
|
+
result.acceptedRecipients.push(recipient);
|
|
707
|
+
return { recipient, accepted: true, response };
|
|
708
|
+
} else {
|
|
709
|
+
result.rejectedRecipients.push(recipient);
|
|
710
|
+
logger.log('warn', `Recipient ${recipient} rejected: ${response}`);
|
|
711
|
+
return { recipient, accepted: false, response };
|
|
712
|
+
}
|
|
713
|
+
})
|
|
714
|
+
.catch(error => {
|
|
715
|
+
result.rejectedRecipients.push(recipient);
|
|
716
|
+
logger.log('warn', `Recipient ${recipient} rejected with error: ${error.message}`);
|
|
717
|
+
return { recipient, accepted: false, error: error.message };
|
|
718
|
+
});
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
// Wait for all RCPT TO commands to complete
|
|
722
|
+
await Promise.all(rcptPromises);
|
|
723
|
+
} else {
|
|
724
|
+
// Fall back to sequential commands if pipelining not supported
|
|
725
|
+
logger.log('debug', 'Using sequential SMTP commands for sending');
|
|
726
|
+
|
|
727
|
+
// Send MAIL FROM
|
|
728
|
+
await this.sendCommand(`MAIL FROM:<${envelope_from}> SIZE=${this.getEmailSize(email)}`);
|
|
729
|
+
|
|
730
|
+
// Send RCPT TO for each recipient
|
|
731
|
+
for (const recipient of recipients) {
|
|
732
|
+
try {
|
|
733
|
+
await this.sendCommand(`RCPT TO:<${recipient}>`);
|
|
734
|
+
result.acceptedRecipients.push(recipient);
|
|
735
|
+
} catch (error) {
|
|
736
|
+
logger.log('warn', `Recipient ${recipient} rejected: ${error.message}`);
|
|
737
|
+
result.rejectedRecipients.push(recipient);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Check if at least one recipient was accepted
|
|
743
|
+
if (result.acceptedRecipients.length === 0) {
|
|
744
|
+
throw new MtaDeliveryError(
|
|
745
|
+
'All recipients were rejected',
|
|
746
|
+
{
|
|
747
|
+
data: {
|
|
748
|
+
recipients,
|
|
749
|
+
rejectedRecipients: result.rejectedRecipients
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Send DATA
|
|
756
|
+
const dataResponse = await this.sendCommand('DATA');
|
|
757
|
+
|
|
758
|
+
if (!dataResponse.startsWith('354')) {
|
|
759
|
+
throw new MtaProtocolError(
|
|
760
|
+
`Failed to start DATA phase: ${dataResponse}`,
|
|
761
|
+
{
|
|
762
|
+
data: {
|
|
763
|
+
response: dataResponse
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Format email content efficiently
|
|
770
|
+
const emailContent = await this.getFormattedEmail(email);
|
|
771
|
+
|
|
772
|
+
// Send email content
|
|
773
|
+
const finalResponse = await this.sendCommand(emailContent + '\r\n.');
|
|
774
|
+
|
|
775
|
+
// Extract message ID if available
|
|
776
|
+
const messageIdMatch = finalResponse.match(/\[(.*?)\]/);
|
|
777
|
+
if (messageIdMatch) {
|
|
778
|
+
result.messageId = messageIdMatch[1];
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
result.success = true;
|
|
782
|
+
result.response = finalResponse;
|
|
783
|
+
|
|
784
|
+
logger.log('info', `Email sent successfully to ${result.acceptedRecipients.join(', ')}`);
|
|
785
|
+
|
|
786
|
+
// Log security event
|
|
787
|
+
SecurityLogger.getInstance().logEvent({
|
|
788
|
+
level: SecurityLogLevel.INFO,
|
|
789
|
+
type: SecurityEventType.EMAIL_DELIVERY,
|
|
790
|
+
message: 'Email sent successfully',
|
|
791
|
+
details: {
|
|
792
|
+
recipients: result.acceptedRecipients,
|
|
793
|
+
rejectedRecipients: result.rejectedRecipients,
|
|
794
|
+
messageId: result.messageId,
|
|
795
|
+
secure: result.secure,
|
|
796
|
+
authenticated: result.authenticated,
|
|
797
|
+
server: `${this.options.host}:${this.options.port}`,
|
|
798
|
+
dkimSigned: result.dkimSigned
|
|
799
|
+
},
|
|
800
|
+
success: true
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
return result;
|
|
804
|
+
} catch (error) {
|
|
805
|
+
logger.log('error', `Failed to send email: ${error.message}`);
|
|
806
|
+
|
|
807
|
+
// Format error for result
|
|
808
|
+
result.error = error.message;
|
|
809
|
+
|
|
810
|
+
// Extract SMTP code if available
|
|
811
|
+
if (error.context?.data?.statusCode) {
|
|
812
|
+
result.responseCode = error.context.data.statusCode;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// Log security event
|
|
816
|
+
SecurityLogger.getInstance().logEvent({
|
|
817
|
+
level: SecurityLogLevel.ERROR,
|
|
818
|
+
type: SecurityEventType.EMAIL_DELIVERY,
|
|
819
|
+
message: 'Email delivery failed',
|
|
820
|
+
details: {
|
|
821
|
+
error: error.message,
|
|
822
|
+
server: `${this.options.host}:${this.options.port}`,
|
|
823
|
+
recipients: email.getAllRecipients(),
|
|
824
|
+
acceptedRecipients: result.acceptedRecipients,
|
|
825
|
+
rejectedRecipients: result.rejectedRecipients,
|
|
826
|
+
secure: result.secure,
|
|
827
|
+
authenticated: result.authenticated
|
|
828
|
+
},
|
|
829
|
+
success: false
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
return result;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Apply DKIM signature to email
|
|
838
|
+
* @param email Email to sign
|
|
839
|
+
*/
|
|
840
|
+
private async applyDkimSignature(email: Email): Promise<void> {
|
|
841
|
+
if (!this.options.dkim?.enabled || !this.options.dkim?.privateKey) {
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
try {
|
|
846
|
+
logger.log('debug', `Signing email with DKIM for domain ${this.options.dkim.domain}`);
|
|
847
|
+
|
|
848
|
+
// Format email for DKIM signing
|
|
849
|
+
const { dkimSign } = plugins;
|
|
850
|
+
const emailContent = await this.getFormattedEmail(email);
|
|
851
|
+
|
|
852
|
+
// Sign email
|
|
853
|
+
const signOptions = {
|
|
854
|
+
domainName: this.options.dkim.domain,
|
|
855
|
+
keySelector: this.options.dkim.selector,
|
|
856
|
+
privateKey: this.options.dkim.privateKey,
|
|
857
|
+
headerFieldNames: this.options.dkim.headers || [
|
|
858
|
+
'from', 'to', 'subject', 'date', 'message-id'
|
|
859
|
+
]
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
const signedEmail = await dkimSign(emailContent, signOptions);
|
|
863
|
+
|
|
864
|
+
// Replace headers in original email
|
|
865
|
+
const dkimHeader = signedEmail.substring(0, signedEmail.indexOf('\r\n\r\n')).split('\r\n')
|
|
866
|
+
.find(line => line.startsWith('DKIM-Signature: '));
|
|
867
|
+
|
|
868
|
+
if (dkimHeader) {
|
|
869
|
+
email.addHeader('DKIM-Signature', dkimHeader.substring('DKIM-Signature: '.length));
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
logger.log('debug', 'DKIM signature applied successfully');
|
|
873
|
+
} catch (error) {
|
|
874
|
+
logger.log('error', `Failed to apply DKIM signature: ${error.message}`);
|
|
875
|
+
throw error;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Format email for SMTP transmission
|
|
881
|
+
* @param email Email to format
|
|
882
|
+
*/
|
|
883
|
+
private async getFormattedEmail(email: Email): Promise<string> {
|
|
884
|
+
// This is a simplified implementation
|
|
885
|
+
// In a full implementation, this would use proper MIME formatting
|
|
886
|
+
|
|
887
|
+
let content = '';
|
|
888
|
+
|
|
889
|
+
// Add headers
|
|
890
|
+
content += `From: ${email.from}\r\n`;
|
|
891
|
+
content += `To: ${email.to.join(', ')}\r\n`;
|
|
892
|
+
content += `Subject: ${email.subject}\r\n`;
|
|
893
|
+
content += `Date: ${new Date().toUTCString()}\r\n`;
|
|
894
|
+
content += `Message-ID: <${plugins.uuid.v4()}@${this.options.domain}>\r\n`;
|
|
895
|
+
|
|
896
|
+
// Add additional headers
|
|
897
|
+
for (const [name, value] of Object.entries(email.headers || {})) {
|
|
898
|
+
content += `${name}: ${value}\r\n`;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// Add content type for multipart
|
|
902
|
+
if (email.attachments && email.attachments.length > 0) {
|
|
903
|
+
const boundary = `----_=_NextPart_${Math.random().toString(36).substr(2)}`;
|
|
904
|
+
content += `MIME-Version: 1.0\r\n`;
|
|
905
|
+
content += `Content-Type: multipart/mixed; boundary="${boundary}"\r\n`;
|
|
906
|
+
content += `\r\n`;
|
|
907
|
+
|
|
908
|
+
// Add text part
|
|
909
|
+
content += `--${boundary}\r\n`;
|
|
910
|
+
content += `Content-Type: text/plain; charset="UTF-8"\r\n`;
|
|
911
|
+
content += `\r\n`;
|
|
912
|
+
content += `${email.text}\r\n`;
|
|
913
|
+
|
|
914
|
+
// Add HTML part if present
|
|
915
|
+
if (email.html) {
|
|
916
|
+
content += `--${boundary}\r\n`;
|
|
917
|
+
content += `Content-Type: text/html; charset="UTF-8"\r\n`;
|
|
918
|
+
content += `\r\n`;
|
|
919
|
+
content += `${email.html}\r\n`;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// Add attachments
|
|
923
|
+
for (const attachment of email.attachments) {
|
|
924
|
+
content += `--${boundary}\r\n`;
|
|
925
|
+
content += `Content-Type: ${attachment.contentType || 'application/octet-stream'}; name="${attachment.filename}"\r\n`;
|
|
926
|
+
content += `Content-Disposition: attachment; filename="${attachment.filename}"\r\n`;
|
|
927
|
+
content += `Content-Transfer-Encoding: base64\r\n`;
|
|
928
|
+
content += `\r\n`;
|
|
929
|
+
|
|
930
|
+
// Add base64 encoded content
|
|
931
|
+
const base64Content = attachment.content.toString('base64');
|
|
932
|
+
|
|
933
|
+
// Split into lines of 76 characters
|
|
934
|
+
for (let i = 0; i < base64Content.length; i += 76) {
|
|
935
|
+
content += base64Content.substring(i, i + 76) + '\r\n';
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// End boundary
|
|
940
|
+
content += `--${boundary}--\r\n`;
|
|
941
|
+
} else {
|
|
942
|
+
// Simple email with just text
|
|
943
|
+
content += `Content-Type: text/plain; charset="UTF-8"\r\n`;
|
|
944
|
+
content += `\r\n`;
|
|
945
|
+
content += `${email.text}\r\n`;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
return content;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* Get size of email in bytes
|
|
953
|
+
* @param email Email to measure
|
|
954
|
+
*/
|
|
955
|
+
private getEmailSize(email: Email): number {
|
|
956
|
+
// Simplified size estimation
|
|
957
|
+
let size = 0;
|
|
958
|
+
|
|
959
|
+
// Headers
|
|
960
|
+
size += `From: ${email.from}\r\n`.length;
|
|
961
|
+
size += `To: ${email.to.join(', ')}\r\n`.length;
|
|
962
|
+
size += `Subject: ${email.subject}\r\n`.length;
|
|
963
|
+
|
|
964
|
+
// Body
|
|
965
|
+
size += (email.text?.length || 0) + 2; // +2 for CRLF
|
|
966
|
+
|
|
967
|
+
// HTML part if present
|
|
968
|
+
if (email.html) {
|
|
969
|
+
size += email.html.length + 2;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// Attachments
|
|
973
|
+
for (const attachment of email.attachments || []) {
|
|
974
|
+
size += attachment.content.length;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// Add overhead for MIME boundaries and headers
|
|
978
|
+
const overhead = email.attachments?.length ? 1000 + (email.attachments.length * 200) : 200;
|
|
979
|
+
|
|
980
|
+
return size + overhead;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Send SMTP command and wait for response
|
|
985
|
+
* @param command SMTP command to send
|
|
986
|
+
*/
|
|
987
|
+
// Queue for command pipelining
|
|
988
|
+
private commandQueue: Array<{
|
|
989
|
+
command: string;
|
|
990
|
+
resolve: (response: string) => void;
|
|
991
|
+
reject: (error: any) => void;
|
|
992
|
+
timeout: NodeJS.Timeout;
|
|
993
|
+
}> = [];
|
|
994
|
+
|
|
995
|
+
// Flag to indicate if we're currently processing commands
|
|
996
|
+
private processingCommands = false;
|
|
997
|
+
|
|
998
|
+
// Flag to indicate if server supports pipelining
|
|
999
|
+
private supportsPipelining = false;
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Send an SMTP command and wait for response
|
|
1003
|
+
* @param command SMTP command to send
|
|
1004
|
+
* @param allowPipelining Whether this command can be pipelined
|
|
1005
|
+
*/
|
|
1006
|
+
private async sendCommand(command: string, allowPipelining = true): Promise<string> {
|
|
1007
|
+
if (!this.socket) {
|
|
1008
|
+
throw new MtaConnectionError(
|
|
1009
|
+
'Not connected to server',
|
|
1010
|
+
{
|
|
1011
|
+
data: {
|
|
1012
|
+
host: this.options.host,
|
|
1013
|
+
port: this.options.port
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// Log command if not sensitive
|
|
1020
|
+
if (!command.startsWith('AUTH')) {
|
|
1021
|
+
logger.log('debug', `> ${command}`);
|
|
1022
|
+
} else {
|
|
1023
|
+
logger.log('debug', '> AUTH ***');
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
return new Promise<string>((resolve, reject) => {
|
|
1027
|
+
// Set up timeout for command
|
|
1028
|
+
const timeout = setTimeout(() => {
|
|
1029
|
+
// Remove this command from the queue if it times out
|
|
1030
|
+
const index = this.commandQueue.findIndex(item => item.command === command);
|
|
1031
|
+
if (index !== -1) {
|
|
1032
|
+
this.commandQueue.splice(index, 1);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
reject(MtaTimeoutError.commandTimeout(
|
|
1036
|
+
command.split(' ')[0],
|
|
1037
|
+
this.options.host,
|
|
1038
|
+
this.options.commandTimeout
|
|
1039
|
+
));
|
|
1040
|
+
}, this.options.commandTimeout);
|
|
1041
|
+
|
|
1042
|
+
// Add command to the queue
|
|
1043
|
+
this.commandQueue.push({
|
|
1044
|
+
command,
|
|
1045
|
+
resolve,
|
|
1046
|
+
reject,
|
|
1047
|
+
timeout
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
// Process command queue if we can pipeline or if not currently processing commands
|
|
1051
|
+
if ((this.supportsPipelining && allowPipelining) || !this.processingCommands) {
|
|
1052
|
+
this.processCommandQueue();
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Process the command queue - either one by one or pipelined if supported
|
|
1059
|
+
*/
|
|
1060
|
+
private processCommandQueue(): void {
|
|
1061
|
+
if (this.processingCommands || this.commandQueue.length === 0 || !this.socket) {
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
this.processingCommands = true;
|
|
1066
|
+
|
|
1067
|
+
try {
|
|
1068
|
+
// If pipelining is supported, send all commands at once
|
|
1069
|
+
if (this.supportsPipelining) {
|
|
1070
|
+
// Send all commands in queue at once
|
|
1071
|
+
const commands = this.commandQueue.map(item => item.command).join('\r\n') + '\r\n';
|
|
1072
|
+
|
|
1073
|
+
this.socket.write(commands, (err) => {
|
|
1074
|
+
if (err) {
|
|
1075
|
+
// Handle write error for all commands
|
|
1076
|
+
const error = new MtaConnectionError(
|
|
1077
|
+
`Failed to send commands: ${err.message}`,
|
|
1078
|
+
{
|
|
1079
|
+
data: {
|
|
1080
|
+
error: err.message
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
);
|
|
1084
|
+
|
|
1085
|
+
// Fail all pending commands
|
|
1086
|
+
while (this.commandQueue.length > 0) {
|
|
1087
|
+
const item = this.commandQueue.shift();
|
|
1088
|
+
clearTimeout(item.timeout);
|
|
1089
|
+
item.reject(error);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
this.processingCommands = false;
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
// Process responses one by one in order
|
|
1097
|
+
this.processResponses();
|
|
1098
|
+
} else {
|
|
1099
|
+
// Process commands one by one if pipelining not supported
|
|
1100
|
+
this.processNextCommand();
|
|
1101
|
+
}
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
logger.log('error', `Error processing command queue: ${error.message}`);
|
|
1104
|
+
this.processingCommands = false;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* Process the next command in the queue (non-pipelined mode)
|
|
1110
|
+
*/
|
|
1111
|
+
private processNextCommand(): void {
|
|
1112
|
+
if (this.commandQueue.length === 0 || !this.socket) {
|
|
1113
|
+
this.processingCommands = false;
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
const currentCommand = this.commandQueue[0];
|
|
1118
|
+
|
|
1119
|
+
this.socket.write(currentCommand.command + '\r\n', (err) => {
|
|
1120
|
+
if (err) {
|
|
1121
|
+
// Handle write error
|
|
1122
|
+
const error = new MtaConnectionError(
|
|
1123
|
+
`Failed to send command: ${err.message}`,
|
|
1124
|
+
{
|
|
1125
|
+
data: {
|
|
1126
|
+
command: currentCommand.command.split(' ')[0],
|
|
1127
|
+
error: err.message
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
);
|
|
1131
|
+
|
|
1132
|
+
// Remove from queue
|
|
1133
|
+
this.commandQueue.shift();
|
|
1134
|
+
clearTimeout(currentCommand.timeout);
|
|
1135
|
+
currentCommand.reject(error);
|
|
1136
|
+
|
|
1137
|
+
// Continue with next command
|
|
1138
|
+
this.processNextCommand();
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// Read response
|
|
1143
|
+
this.readResponse()
|
|
1144
|
+
.then((response) => {
|
|
1145
|
+
// Remove from queue and resolve
|
|
1146
|
+
this.commandQueue.shift();
|
|
1147
|
+
clearTimeout(currentCommand.timeout);
|
|
1148
|
+
currentCommand.resolve(response);
|
|
1149
|
+
|
|
1150
|
+
// Process next command
|
|
1151
|
+
this.processNextCommand();
|
|
1152
|
+
})
|
|
1153
|
+
.catch((err) => {
|
|
1154
|
+
// Remove from queue and reject
|
|
1155
|
+
this.commandQueue.shift();
|
|
1156
|
+
clearTimeout(currentCommand.timeout);
|
|
1157
|
+
currentCommand.reject(err);
|
|
1158
|
+
|
|
1159
|
+
// Process next command
|
|
1160
|
+
this.processNextCommand();
|
|
1161
|
+
});
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Process responses for pipelined commands
|
|
1167
|
+
*/
|
|
1168
|
+
private async processResponses(): Promise<void> {
|
|
1169
|
+
try {
|
|
1170
|
+
// Process responses for each command in order
|
|
1171
|
+
while (this.commandQueue.length > 0) {
|
|
1172
|
+
const currentCommand = this.commandQueue[0];
|
|
1173
|
+
|
|
1174
|
+
try {
|
|
1175
|
+
// Wait for response
|
|
1176
|
+
const response = await this.readResponse();
|
|
1177
|
+
|
|
1178
|
+
// Remove from queue and resolve
|
|
1179
|
+
this.commandQueue.shift();
|
|
1180
|
+
clearTimeout(currentCommand.timeout);
|
|
1181
|
+
currentCommand.resolve(response);
|
|
1182
|
+
} catch (error) {
|
|
1183
|
+
// Remove from queue and reject
|
|
1184
|
+
this.commandQueue.shift();
|
|
1185
|
+
clearTimeout(currentCommand.timeout);
|
|
1186
|
+
currentCommand.reject(error);
|
|
1187
|
+
|
|
1188
|
+
// Stop processing if this is a critical error
|
|
1189
|
+
if (
|
|
1190
|
+
error instanceof MtaConnectionError &&
|
|
1191
|
+
(error.message.includes('Connection closed') || error.message.includes('Not connected'))
|
|
1192
|
+
) {
|
|
1193
|
+
break;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
} catch (error) {
|
|
1198
|
+
logger.log('error', `Error processing responses: ${error.message}`);
|
|
1199
|
+
} finally {
|
|
1200
|
+
this.processingCommands = false;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/**
|
|
1205
|
+
* Read response from the server
|
|
1206
|
+
*/
|
|
1207
|
+
private async readResponse(): Promise<string> {
|
|
1208
|
+
if (!this.socket) {
|
|
1209
|
+
throw new MtaConnectionError(
|
|
1210
|
+
'Not connected to server',
|
|
1211
|
+
{
|
|
1212
|
+
data: {
|
|
1213
|
+
host: this.options.host,
|
|
1214
|
+
port: this.options.port
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
return new Promise<string>((resolve, reject) => {
|
|
1221
|
+
// Use an array to collect response chunks instead of string concatenation
|
|
1222
|
+
const responseChunks: Buffer[] = [];
|
|
1223
|
+
|
|
1224
|
+
// Single function to clean up all listeners
|
|
1225
|
+
const cleanupListeners = () => {
|
|
1226
|
+
if (!this.socket) return;
|
|
1227
|
+
this.socket.removeListener('data', onData);
|
|
1228
|
+
this.socket.removeListener('error', onError);
|
|
1229
|
+
this.socket.removeListener('close', onClose);
|
|
1230
|
+
this.socket.removeListener('end', onEnd);
|
|
1231
|
+
};
|
|
1232
|
+
|
|
1233
|
+
const onData = (data: Buffer) => {
|
|
1234
|
+
// Store buffer directly, avoiding unnecessary string conversion
|
|
1235
|
+
responseChunks.push(data);
|
|
1236
|
+
|
|
1237
|
+
// Convert to string only for response checking
|
|
1238
|
+
const responseData = Buffer.concat(responseChunks).toString();
|
|
1239
|
+
|
|
1240
|
+
// Check if this is a complete response
|
|
1241
|
+
if (this.isCompleteResponse(responseData)) {
|
|
1242
|
+
// Clean up listeners
|
|
1243
|
+
cleanupListeners();
|
|
1244
|
+
|
|
1245
|
+
const trimmedResponse = responseData.trim();
|
|
1246
|
+
logger.log('debug', `< ${trimmedResponse}`);
|
|
1247
|
+
|
|
1248
|
+
// Check if this is an error response
|
|
1249
|
+
if (this.isErrorResponse(responseData)) {
|
|
1250
|
+
const code = responseData.substring(0, 3);
|
|
1251
|
+
reject(this.createErrorFromResponse(trimmedResponse, code));
|
|
1252
|
+
} else {
|
|
1253
|
+
resolve(trimmedResponse);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
const onError = (err: Error) => {
|
|
1259
|
+
cleanupListeners();
|
|
1260
|
+
|
|
1261
|
+
reject(new MtaConnectionError(
|
|
1262
|
+
`Socket error while waiting for response: ${err.message}`,
|
|
1263
|
+
{
|
|
1264
|
+
data: {
|
|
1265
|
+
error: err.message
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
));
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
const onClose = () => {
|
|
1272
|
+
cleanupListeners();
|
|
1273
|
+
|
|
1274
|
+
const responseData = Buffer.concat(responseChunks).toString();
|
|
1275
|
+
reject(new MtaConnectionError(
|
|
1276
|
+
'Connection closed while waiting for response',
|
|
1277
|
+
{
|
|
1278
|
+
data: {
|
|
1279
|
+
partialResponse: responseData
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
));
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1285
|
+
const onEnd = () => {
|
|
1286
|
+
cleanupListeners();
|
|
1287
|
+
|
|
1288
|
+
const responseData = Buffer.concat(responseChunks).toString();
|
|
1289
|
+
reject(new MtaConnectionError(
|
|
1290
|
+
'Connection ended while waiting for response',
|
|
1291
|
+
{
|
|
1292
|
+
data: {
|
|
1293
|
+
partialResponse: responseData
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
));
|
|
1297
|
+
};
|
|
1298
|
+
|
|
1299
|
+
// Set up listeners
|
|
1300
|
+
this.socket.on('data', onData);
|
|
1301
|
+
this.socket.once('error', onError);
|
|
1302
|
+
this.socket.once('close', onClose);
|
|
1303
|
+
this.socket.once('end', onEnd);
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
/**
|
|
1308
|
+
* Check if the response is complete
|
|
1309
|
+
* @param response Response to check
|
|
1310
|
+
*/
|
|
1311
|
+
private isCompleteResponse(response: string): boolean {
|
|
1312
|
+
// Check if it's a multi-line response
|
|
1313
|
+
const lines = response.split('\r\n');
|
|
1314
|
+
const lastLine = lines[lines.length - 2]; // Second to last because of the trailing CRLF
|
|
1315
|
+
|
|
1316
|
+
// Check if the last line starts with a code followed by a space
|
|
1317
|
+
// If it does, this is a complete response
|
|
1318
|
+
if (lastLine && /^\d{3} /.test(lastLine)) {
|
|
1319
|
+
return true;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// For single line responses
|
|
1323
|
+
if (lines.length === 2 && lines[0].length >= 3 && /^\d{3} /.test(lines[0])) {
|
|
1324
|
+
return true;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
/**
|
|
1331
|
+
* Check if the response is an error
|
|
1332
|
+
* @param response Response to check
|
|
1333
|
+
*/
|
|
1334
|
+
private isErrorResponse(response: string): boolean {
|
|
1335
|
+
// Get the status code (first 3 characters)
|
|
1336
|
+
const code = response.substring(0, 3);
|
|
1337
|
+
|
|
1338
|
+
// 4xx and 5xx are error codes
|
|
1339
|
+
return code.startsWith('4') || code.startsWith('5');
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
/**
|
|
1343
|
+
* Create appropriate error from response
|
|
1344
|
+
* @param response Error response
|
|
1345
|
+
* @param code SMTP status code
|
|
1346
|
+
*/
|
|
1347
|
+
private createErrorFromResponse(response: string, code: string): Error {
|
|
1348
|
+
// Extract message part
|
|
1349
|
+
const message = response.substring(4).trim();
|
|
1350
|
+
|
|
1351
|
+
switch (code.charAt(0)) {
|
|
1352
|
+
case '4': // Temporary errors
|
|
1353
|
+
return MtaDeliveryError.temporary(
|
|
1354
|
+
message,
|
|
1355
|
+
'recipient',
|
|
1356
|
+
code,
|
|
1357
|
+
response
|
|
1358
|
+
);
|
|
1359
|
+
|
|
1360
|
+
case '5': // Permanent errors
|
|
1361
|
+
return MtaDeliveryError.permanent(
|
|
1362
|
+
message,
|
|
1363
|
+
'recipient',
|
|
1364
|
+
code,
|
|
1365
|
+
response
|
|
1366
|
+
);
|
|
1367
|
+
|
|
1368
|
+
default:
|
|
1369
|
+
return new MtaDeliveryError(
|
|
1370
|
+
`Unexpected error response: ${response}`,
|
|
1371
|
+
{
|
|
1372
|
+
data: {
|
|
1373
|
+
response,
|
|
1374
|
+
code
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
/**
|
|
1382
|
+
* Close the connection to the server
|
|
1383
|
+
*/
|
|
1384
|
+
public async close(): Promise<void> {
|
|
1385
|
+
if (!this.connected || !this.socket) {
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
try {
|
|
1390
|
+
// Send QUIT
|
|
1391
|
+
await this.sendCommand('QUIT');
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
logger.log('warn', `Error sending QUIT command: ${error.message}`);
|
|
1394
|
+
} finally {
|
|
1395
|
+
// Close socket
|
|
1396
|
+
this.socket.destroy();
|
|
1397
|
+
this.socket = undefined;
|
|
1398
|
+
this.connected = false;
|
|
1399
|
+
logger.log('info', 'SMTP connection closed');
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* Checks if the connection is active
|
|
1405
|
+
*/
|
|
1406
|
+
public isConnected(): boolean {
|
|
1407
|
+
return this.connected && !!this.socket;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Update SMTP client options
|
|
1412
|
+
* @param options New options
|
|
1413
|
+
*/
|
|
1414
|
+
public updateOptions(options: Partial<ISmtpClientOptions>): void {
|
|
1415
|
+
this.options = {
|
|
1416
|
+
...this.options,
|
|
1417
|
+
...options
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
logger.log('info', 'SMTP client options updated');
|
|
1421
|
+
}
|
|
1422
|
+
}
|