Preconditions and environment
Steps to reproduce
- Have e-mail communication disabled for store id 1
- Have 2FA enabled
- Create a new admin user
- Try to login with the admin user, it should try to send an e-mail with 2FA instructions, but it's not sending
Expected result
E-mail with 2FA instructions should be send.
Actual result
E-mail with 2FA instructions is not send.
Additional information
EmailUserNotifier passes 'store' => 0 to setTemplateOptions(), but that only tells TransportBuilder which store's template content/locale to render the email with. It has nothing to do with the disable-check.
The disable-check lives in a completely separate plugin, TransportInterfacePlugin::aroundSendMessage(), which wraps every outgoing email regardless of type:
$this->scopeConfig->isSetFlag('system/smtp/disable', ScopeInterface::SCOPE_STORE)
No scope code is passed — so it resolves against whatever StoreManagerInterface::getStore() considers the "current store" for that request. In an adminhtml request, without a frontend store cookie/session in play, Magento's store resolution falls through to the default store of the default website — store_id 1 in your setup — not store_id 0. Store 0 ("Default Config"/Admin) isn't a real browsable store, so it's essentially never what getStore() returns during a live request; it only shows up as a literal 0 when code explicitly asks for it, like EmailUserNotifier does for template rendering.
So yes — architecturally, 2FA/admin system mail should be governed by the global/default scope, and EmailUserNotifier clearly intended that with 'store' => 0. But the send-suppression check is a separate, unscoped lookup that happens to land on store 1 in practice. This is a genuine inconsistency in Magento core
Release note
No response
Triage and priority
Preconditions and environment
Steps to reproduce
Expected result
E-mail with 2FA instructions should be send.
Actual result
E-mail with 2FA instructions is not send.
Additional information
EmailUserNotifier passes 'store' => 0 to setTemplateOptions(), but that only tells TransportBuilder which store's template content/locale to render the email with. It has nothing to do with the disable-check.
The disable-check lives in a completely separate plugin, TransportInterfacePlugin::aroundSendMessage(), which wraps every outgoing email regardless of type:
$this->scopeConfig->isSetFlag('system/smtp/disable', ScopeInterface::SCOPE_STORE)
No scope code is passed — so it resolves against whatever StoreManagerInterface::getStore() considers the "current store" for that request. In an adminhtml request, without a frontend store cookie/session in play, Magento's store resolution falls through to the default store of the default website — store_id 1 in your setup — not store_id 0. Store 0 ("Default Config"/Admin) isn't a real browsable store, so it's essentially never what getStore() returns during a live request; it only shows up as a literal 0 when code explicitly asks for it, like EmailUserNotifier does for template rendering.
So yes — architecturally, 2FA/admin system mail should be governed by the global/default scope, and EmailUserNotifier clearly intended that with 'store' => 0. But the send-suppression check is a separate, unscoped lookup that happens to land on store 1 in practice. This is a genuine inconsistency in Magento core
Release note
No response
Triage and priority