SMTP Configuration
Configure SMTP delivery for transactional emails such as account confirmation and password reset.
Hexabot uses SMTP for transactional emails sent by the API. In the current NestJS implementation, SMTP is used for account confirmation emails and password reset emails.
The mailer is configured from EMAIL_SMTP_* environment variables, then registered with @nestjs-modules/mailer, Nodemailer SMTP transport, and MJML templates.
How Email Delivery Works
At API startup, Hexabot reads the SMTP environment variables and builds config.emails:
config.emails.isEnabled
EMAIL_SMTP_ENABLED
config.emails.smtp.host
EMAIL_SMTP_HOST
config.emails.smtp.port
EMAIL_SMTP_PORT
config.emails.smtp.secure
EMAIL_SMTP_SECURE
config.emails.smtp.auth.user
EMAIL_SMTP_USER
config.emails.smtp.auth.pass
EMAIL_SMTP_PASS
config.emails.from
EMAIL_SMTP_FROM
When EMAIL_SMTP_ENABLED=true, the API registers a real SMTP transporter. When it is false, the API does not register the NestJS mailer transport and injects a fallback MailerService whose sendMail() method throws Email Service is not enabled.
That means SMTP can be disabled for local development only if you do not need email-dependent flows. Account creation still succeeds when the confirmation email cannot be sent, but the new user remains inactive until confirmed or enabled manually. Password reset requests require email delivery and will fail if SMTP is disabled or unreachable.
SMTP settings are read only at startup. Restart the API after changing environment variables.
SMTP Variables
EMAIL_SMTP_ENABLED=true
EMAIL_SMTP_HOST=smtp.example.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_SECURE=false
EMAIL_SMTP_USER=your-smtp-username
EMAIL_SMTP_PASS=your-smtp-password
EMAIL_SMTP_FROM="Hexabot <[email protected]>"EMAIL_SMTP_ENABLED
Yes
false
Must be exactly true to enable the real mailer module.
EMAIL_SMTP_HOST
Yes
localhost
Hostname reachable from the API process or API container.
EMAIL_SMTP_PORT
Yes
25
Common values are 25, 587, and 465, depending on the provider.
EMAIL_SMTP_SECURE
Yes
false
Use true for implicit TLS from connection start, usually port 465. Use false for plain SMTP or STARTTLS, commonly ports 25 or 587.
EMAIL_SMTP_USER
Usually
empty
SMTP username, API key username, or provider-specific login.
EMAIL_SMTP_PASS
Usually
empty
SMTP password, app password, or provider API key.
EMAIL_SMTP_FROM
Yes
Default sender used by MailerModule for outgoing email. Many providers require this address or domain to be verified.
Hexabot sets Nodemailer ignoreTLS to false, so STARTTLS can be used when the SMTP server advertises it and EMAIL_SMTP_SECURE=false.
Related URL and Token Settings
Email templates include links back to the frontend. Set the public frontend URL correctly, especially in production:
The current templates use this value for:
Account confirmation
FRONTEND_BASE_URL/login/<token>
Password reset
FRONTEND_BASE_URL/reset/<token>
Set production-grade secrets and expiration values for the email tokens:
Do not reuse the development defaults in production.
Local Testing with smtp4dev
The repository includes a Docker Compose override for smtp4dev at docker/docker-compose.smtp4dev.yml.
smtp4dev exposes:
SMTP inside the Docker Compose network
smtp4dev:25
Web inbox on the host
http://localhost:9002
For Docker-based development, enable SMTP and point the API container at the smtp4dev service:
Then start Docker with the smtp4dev compose file. With the CLI:
Or directly from this repository:
Open http://localhost:9002 to inspect captured messages.
If the API runs on the host machine instead of inside the Docker Compose network, use the host mapping instead:
Production Example
For a typical authenticated SMTP provider using STARTTLS on port 587:
For a provider that requires implicit TLS on port 465, change only the port and secure flag:
Before going live, verify the provider-side requirements:
Verified sender or domain
Providers often reject or rewrite unverified EMAIL_SMTP_FROM addresses.
Valid SMTP credentials
Some providers use API keys as the SMTP password.
Allowed outbound SMTP port
Cloud networks and hosting providers may block ports 25, 465, or 587.
Correct TLS mode
A port/secure mismatch is a common cause of connection failures.
The current environment mapping does not expose advanced Nodemailer options such as custom TLS certificates, requireTLS, or multiple transports. Add code-level configuration if your SMTP provider requires those options.
Verifying the Configuration
Restart the API after editing the environment file.
Open the dashboard and check Integrations Health.
Look for Email (SMTP).
A healthy SMTP card means
verifyAllTransporters()succeeded.Trigger a real email flow, such as a password reset request or creating a user that should receive an account confirmation email.
Check the recipient inbox, provider logs, or smtp4dev web inbox.
The API also exposes integration health through /api/stats/integration-health for authenticated dashboard requests. The SMTP item reports one of these reasons:
smtp.disabled
EMAIL_SMTP_ENABLED is not true.
smtp.verified
The configured transporter verified successfully.
smtp.verify_failed
The transporter verification failed.
smtp.timeout
Verification did not complete within the API health timeout.
Troubleshooting
Email (SMTP) shows disabled
SMTP is not enabled
Set EMAIL_SMTP_ENABLED=true and restart the API.
Password reset returns an email error
Mailer is disabled or cannot send
Check SMTP health, API logs, and provider logs.
getaddrinfo ENOTFOUND smtp4dev
API process cannot resolve the Docker service name
Use smtp4dev only from inside Compose. Use localhost when the API runs on the host.
TLS or SSL handshake error
EMAIL_SMTP_SECURE does not match the port
Use secure=true for port 465; use secure=false for STARTTLS ports such as 587.
Authentication failed
Wrong user, password, API key, or sender policy
Regenerate credentials and confirm the provider's SMTP login format.
Emails send but links point to localhost
FRONTEND_BASE_URL still uses a development value
Set it to the public frontend URL and restart.
Health check times out
Network, firewall, or provider connectivity issue
Confirm the host and port are reachable from the API container or host.
Templates
Transactional email templates live in packages/api/src/templates:
account_confirmation.mjmlpassword_reset.mjml
The Nest build copies these files into dist/templates, and the mailer reads templates from that compiled directory at runtime. Templates are MJML files rendered through Handlebars. Keep template variable names aligned with the context objects passed by PasswordResetService and ValidateAccountService; missing Handlebars values render as empty strings.
Text translations used by the templates live under packages/api/src/config/i18n.
Last updated
Was this helpful?