
Documentation
TYPO3 Extension “Mail Queue”
Version 1.7.0 (2026-09-12)
Instances where different sites send through different SMTP accounts are supported via a tenant key—a declared identity carried with each mail. The queue delivers and retries every mail through the transport that tenant is mapped to, so a mail never leaves via the wrong account.
1. Declare the Per-Tenant Transport
Use a standard MAIL "Connection":
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['Connections']['brand-one'] = [
'transport' => 'smtp',
'transport_smtp_server' => getenv('BRAND_ONE_SMTP_SERVER'),
'transport_smtp_username' => getenv('BRAND_ONE_SMTP_USERNAME'),
'transport_smtp_password' => getenv('BRAND_ONE_SMTP_PASSWORD'),
];
brand-one is the tenant key throughout this chapter. In a real setup it is your site identifier.
The connection is merged over the global MAIL config, so it only needs the keys it changes. Credentials stay in the deployment config—they are never written to the queue table for tenant mails.
2. Tell Mail Queue Which Tenant a Mail Belongs To
By default the tenant is the current TYPO3 site identifier, resolved by SiteTenantResolver. For a one-site-per-tenant setup there is nothing to do in code: a mail sent from the brand-one site uses the brand-one connection automatically.
To use a different identity, either replace the TenantResolverInterface alias with your own resolver, or stamp the header per mail when composing it:
$email->getHeaders()->addTextHeader(\B13\MailQueue\Service\TenantRouter::HEADER, 'brand-one');
The header is internal and stripped before the mail is sent.
Backend and CLI Mails
A frontend request carries the resolved site, so the tenant is picked automatically. A backend or Install Tool request has no resolved site—there SiteTenantResolver falls back to matching the request host and path against the sites' base.
When several sites share one host and differ only by base path, for example example.com and example.com/shop/, the site with the longest base path that still prefixes the request path wins. With the backend at its default /typo3, no site base matches, so the request resolves to that host's root site rather than to a sub-path site.
Three consequences worth planning for:
- Reach the backend on a site's configured host for this to work, or set the
X-MailQueue-Tenantheader for a host that matches no site base, such as a dedicated backend domain or an alias. - A scheduler or CLI run has no host at all. Stamp the header explicitly if such a mail is tenant-specific; otherwise it uses the default transport.
- If you moved the backend to a custom entry point, check where that path sits. A backend below a sub-path site's base—say the backend at
/shop/adminwhile a site's base is/shop/—resolves to that sub-path site, not to the root site. Stamp the header explicitly if that is not what you want.
Tenant Is Not the Same as Connection
When several tenants share one transport—several landing pages of one brand, say, kept apart only for backend visibility—map them to a common connection:
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['mail_queue']['tenants'] = [
'landing-1' => 'brand-one',
'landing-2' => 'brand-one',
'landing-3' => 'brand-one',
];
Unmapped tenants use the connection of the same name. Tenants without a matching connection, and single-transport installs, simply use the global transport.
What Not to Do
Do not swap the global MAIL config per host in additional.php. The CLI flush has no request context, so it would retry every mail through the default transport. Declare real connections as shown above instead.
Legacy Setups
Setups that build their own Mailer instances still work: a transport differing from the global one is captured verbatim and replayed, as before.
Related
The tenant key is also what per-tenant scoping in the backend module filters on, so a delegated editor sees only their own site’s mail.
Multiple Transports (Multi-Tenant)