This companion app routes Nextcloud mail configuration by company or group.
Install the app in your Nextcloud apps-extra directory and enable it:
occ app:enable smtp_routerIf you deploy apps from git, keep the repository checked out beside your other custom apps and make sure Nextcloud can load it from the apps directory.
An admin section named SMTP Router will appear in the Nextcloud settings area.
Use it to pick a group, open the SMTP modal, and save the per-company profile.
The test-vps branch is configured to deploy automatically through GitHub Actions.
It can also be started manually from the Actions tab with workflow_dispatch.
Configure these repository secrets:
VPS_HOST: VPS hostname or IP addressVPS_USER: regular SSH user with passwordlesssudopermission for the deployment commandsVPS_SSH_KEY: dedicated private SSH key for that user, without a passphraseVPS_KNOWN_HOSTS: output ofssh-keyscan -p <port> -H <host>for the VPS
Configure these repository variables:
VPS_APP_PATH: optional remote app path; defaults to/var/www/nextcloud/custom_apps/smtp_routerVPS_PORT: optional SSH port; defaults to22VPS_OCC_COMMAND: optional command to run withsudo -nafter syncing, for examplecd /var/www/nextcloud && php occ app:enable smtp_router
Every push to test-vps syncs the app files over SSH. The SSH user must be able
to run sudo without an interactive password prompt for mkdir, rsync and the
optional VPS_OCC_COMMAND. Keep VPS_OCC_COMMAND
appropriate for the Nextcloud installation on the test VPS; Docker installations
will usually need a docker compose exec command instead of a host-side php occ.
The deployment key must not require interactive passphrase input. Generate a dedicated key for the workflow and leave the passphrase empty when prompted:
ssh-keygen -t ed25519 -f ./smtp-router-deployAdd smtp-router-deploy.pub to the regular user's ~/.ssh/authorized_keys on
the VPS and save the contents of smtp-router-deploy as the VPS_SSH_KEY
repository secret. Do not reuse a personal SSH key.
- Keep
custom_domainfocused on visual customization and trusted domains. - Select different SMTP settings based on the current subdomain or the user's group membership.
The app decorates Nextcloud config reads for keys that start with mail_.
When Nextcloud asks for mail_smtphost, mail_smtpname, mail_smtppassword, mail_domain, and related keys, the app returns the values from the active route.
Route selection order:
- current subdomain if it matches a group
- current user's group membership
default
Use this app together with custom_domain:
custom_domainmaps each company subdomain to a group and trusted domainsmtp_routerpicks the active SMTP profile for that company or group
If a user belongs to a company group, mail sent during that request will use the matching route. If the request host matches a company subdomain, that route takes priority.
Store a JSON document in the app config key smtp_router/routes.
Example:
{
"default": {
"mail_smtpmode": "smtp",
"mail_smtphost": "smtp-default.example.com:587",
"mail_smtpsecure": "tls",
"mail_smtpauth": true,
"mail_smtpname": "default-user",
"mail_smtppassword": "secret",
"mail_domain": "example.com"
},
"empresa-a": {
"mail_smtpmode": "smtp",
"mail_smtphost": "smtp-a.example.com:587",
"mail_smtpsecure": "tls",
"mail_smtpauth": true,
"mail_smtpname": "empresa-a",
"mail_smtppassword": "secret-a",
"mail_domain": "empresa-a.com"
},
"empresa-b": {
"mail_smtpmode": "smtp",
"mail_smtphost": "smtp-b.example.com:587",
"mail_smtpsecure": "tls",
"mail_smtpauth": true,
"mail_smtpname": "empresa-b",
"mail_smtppassword": "secret-b",
"mail_domain": "empresa-b.com"
}
}Write the config with:
occ smtp-router:route:set '{
"default": {
"mail_smtpmode": "smtp",
"mail_smtphost": "mailcow.example.com:587",
"mail_smtpsecure": "tls",
"mail_smtpauth": true,
"mail_smtpname": "nextcloud-default",
"mail_smtppassword": "change-me",
"mail_domain": "example.com"
},
"empresa-a": {
"mail_smtpmode": "smtp",
"mail_smtphost": "mailcow.example.com:587",
"mail_smtpsecure": "tls",
"mail_smtpauth": true,
"mail_smtpname": "empresa-a",
"mail_smtppassword": "change-me-a",
"mail_domain": "empresa-a.com"
},
"empresa-b": {
"mail_smtpmode": "smtp",
"mail_smtphost": "mailcow.example.com:587",
"mail_smtpsecure": "tls",
"mail_smtpauth": true,
"mail_smtpname": "empresa-b",
"mail_smtppassword": "change-me-b",
"mail_domain": "empresa-b.com"
}
}'Read it back with:
occ smtp-router:route:getThe admin UI lets you:
- search groups by name or id and choose the target from a live list
- open a modal to edit SMTP host, port, encryption, login and password
- keep one route per company group
- remove a company route without touching the others
The default route is kept as the fallback for cron jobs and generic system mail.
When no default route is explicitly saved, the app displays and uses the
global mail settings configured in Nextcloud's Server settings > Mail server.
For a Mailcow-backed deployment, the practical pattern is:
- Nextcloud sends mail to Mailcow as the SMTP endpoint.
- Mailcow accepts the authenticated SMTP session.
- Mailcow routes the final delivery according to its own relay or transport rules.
Keep one route as default so background jobs and generic system mail always have a fallback.
- This is still a dynamic config override, not a full mailer rewrite.
- If Nextcloud stops reading SMTP values through system config at send time, the approach will need a deeper mailer integration.
After setting routes, test from the Nextcloud host:
occ smtp-router:route:get --output json_prettyThen trigger a notification or password reset flow from the matching company context and confirm the SMTP session reaches the expected Mailcow account or relay.