- Issue created by @znerol
- @znerol opened merge request.
- 🇨🇭Switzerland znerol
From #3534136-21: Requirements and strategy for Core Mailer → by @berdir:
Catching up on the discussion and merge requests. Long comment incoming...
I don't think LOC is the primary factor to consider for this. Also because the current examples are way more complicated than they need to be due to feature flags, the experimental module and BC. The actual implementation would be a lot less.
That said, I do agree that the config entity approach seems complex. Yes, config entity + plugin are a very common pattern, but sometimes also overused. This feels similar to action plugins and config entities, which are often pretty awkward as it's typically a 1:1 relationship and tedious for modules to maintain the config. In general, code that is hardcoding specific config entity ID's is a bit of a code smell to me. As @adamps said, it's unclear what would happen if that config is missing. For example now with recipes, which pretty much *encourages* installing modules without their config ( I don't really agree with that, but that's another topic). Deleting the password reset template
Naming: I think the template part is misleading. That makes me think of twig templates, HTML and customizing their output. Looking at DSM, it uses build() instead of render(), which makes a lot more sense to me. We build an Email object, which might or might not involve rendering something or using templates, but it's not the main thing. It's also similar to terminology used in simplenews.
An issue with the current architecture is that there's a bidirectional dependency between the plugin and the config entity, as it's passed to render. If you compare with block plugins for example, they don't know about block.module block config entities and can be used in other contexts as well. Similar for field formatters, which are also used by views. That's what $configuration is for, the config entity is responsible for storing and passing that in.
Now, there are cases where a fully implemented config entity + plugin could be useful. For example with user, the plugin would be provide a subject and body setting which would make it self-contained instead of accessing global config (which currently bypasses your attempt at making not just mails but also their data and arguments documented and discoverable). and status is built-in, so the code could check that. But it would mean that the UI would move from user settings to generic mail configuration, which is likely harder to find. It's also not as flexible as you'd be used to from plugins. you can't make up your own notifications, you can only enable/disable and edit the specific settings of them. In the end, pretty limited benefit over the current config and some drawbacks.
contact, update are examples that don't really benefit from there being a config entity, and that's going to be a lot of contrib and custom examples. That's combined with the "problem" that the mail rendering/preparing sits entirely on top of the actual mail send API and is there fore optional. People looking at this and trying to send mails will just directly create the Email object and send it directly. And if they do that, we lose the ability to use a mail theme because rendering of stuff possibly already happened. I think we should make it as easy as possible to use the mail API without losing features like language. And then optional features on top. If you look at commerce_mail(), they essentially bypass the whole thing by just passing in the body and rendering it there. I wonder if we should actually allow to use a callback based approach for those minimal cases, similar to what renderInContext() essentially already is.
I'm not sure how important discoverability and reusability of mail "templates" really is, it might in some cases even be undesired. We recently discussed that ECA explicitly doesn't support those special user password reset mails, to not allow to send them out in the wrong context, that could even be a security issue.
On the other side of the spectrum, use cases that actually have generic and complex use cases around mails might struggle to fit into this architecture. Simplenews has multiple things that make up a newsletter, specifically a entity that sent to a subscriber and there's a lot of rendering and logic going on that should happen within the mail render context. And ECA would need to redefine its mails that sit in its configuration or have a super generic one that would almost become recursive.
I think I get the intent with the types and data, but that really feels complex to use. the user confirm thing requires a data type plugin, a definition class, it's passed in as a raw value, converted to typed data and then used. It values (theoretical) reusability over DX, despite all that complexity, what you work with when writing the code is an array with arbitrary keys. I see that DSM has the concept of mail params on the object. That's still keys and not types that can be enforced, but I think that's an improvement over the single magic mixed type that this has. With mulitple params, we can still document them and their type.
I've even been thinking about going entirely with plain value objects implementing a basic interface, but haven't fully thought that through. But overall I'd clearly recommend keeping the actual mail builder interface/API as plain and un-opinionated as possible and start with that.
- 🇨🇭Switzerland znerol
We decided against the config + plugin approach in our last meeting. Due to the risks of config going missing and due to the fact that recipes do not encourage installing default config.
An issue with the current architecture is that there's a bidirectional dependency between the plugin and the config entity, as it's passed to render. If you compare with block plugins for example, they don't know about block.module block config entities and can be used in other contexts as well. Similar for field formatters, which are also used by views. That's what $configuration is for, the config entity is responsible for storing and passing that in.
That is crucial and it has bothered me a lot. I think I'll try to decouple the config from the plugin and then use that to branch off for coming experiments.
- 🇨🇭Switzerland znerol
Approach abandoned in 📌 [meeting] 2025-07-29 core mailer beta planning Active .