Introduce theme negotiator for mail and use it in mail manager

Created on 7 November 2024, 7 months ago

Problem/Motivation

Part of 🌱 [META] Adopt the symfony mailer component Needs review but benefits the current mail system as well. Also see #2621018: Support rendering from a manually specified theme β†’ for why we need this no matter how the mail building part is going to look in the future.

Steps to reproduce

Proposed resolution

  1. Add a Drupal\Core\MailTheme\MailThemeManager with one method: executeInMailTheme(string $emailId, callable $function)
  2. Add Drupal\Core\MailTheme\MailThemeNegotiator which works analogous to theme negotiation
  3. Add Drupal\Core\MailTheme\DefaultNegotiator with a low priority which falls back to the configured theme.
  4. Switch the theme before building / sending mails from within plugin.manager.mail

This is basically cherry-picking from contrib Mailsystem β†’ and Drupal Symfony Mailer β†’ respectively.

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

πŸ“Œ Task
Status

Active

Version

11.1 πŸ”₯

Component

mail system

Created by

πŸ‡¨πŸ‡­Switzerland znerol

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @znerol
  • Pipeline finished with Failed
    7 months ago
    #332176
  • Pipeline finished with Failed
    7 months ago
    #332181
  • Pipeline finished with Failed
    7 months ago
    #332233
  • Pipeline finished with Running
    7 months ago
    #332237
  • Pipeline finished with Failed
    7 months ago
    #332260
  • Pipeline finished with Failed
    7 months ago
    Total: 557s
    #332335
  • Pipeline finished with Failed
    7 months ago
    Total: 616s
    #332363
  • πŸ‡¨πŸ‡­Switzerland znerol
  • Pipeline finished with Success
    7 months ago
    Total: 1496s
    #332399
  • Pipeline finished with Failed
    7 months ago
    #332494
  • Pipeline finished with Failed
    7 months ago
    Total: 171s
    #332549
  • Pipeline finished with Running
    7 months ago
    #332554
  • Pipeline finished with Success
    7 months ago
    Total: 528s
    #332923
  • πŸ‡³πŸ‡ΏNew Zealand quietone

    Changes are made on on 11.x (our main development branch) first, and are then back ported as needed according to our policies.

  • πŸ‡¨πŸ‡­Switzerland znerol
  • Pipeline finished with Canceled
    7 months ago
    Total: 770s
    #340954
  • Pipeline finished with Canceled
    7 months ago
    Total: 69s
    #340959
  • Pipeline finished with Canceled
    7 months ago
    Total: 149s
    #340958
  • Pipeline finished with Canceled
    7 months ago
    Total: 127s
    #340960
  • Pipeline finished with Failed
    7 months ago
    Total: 645s
    #340961
  • πŸ‡¨πŸ‡­Switzerland znerol
  • πŸ‡¨πŸ‡­Switzerland znerol
  • πŸ‡¨πŸ‡­Switzerland znerol
  • πŸ‡¨πŸ‡­Switzerland znerol
  • πŸ‡¨πŸ‡­Switzerland znerol
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Can the deprecations be updated for 11.2

    Not sure who to ping to review this one.

  • πŸ‡¨πŸ‡­Switzerland znerol

    Deprecation message updated. Good candidates for reviewers are the maintainers of the mailsystem β†’ module I guess.

  • Pipeline finished with Canceled
    6 months ago
    Total: 271s
    #372071
  • Pipeline finished with Success
    6 months ago
    Total: 1472s
    #372076
  • Status changed to Needs work 5 months ago
  • The Needs Review Queue Bot β†’ tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

    Consult the Drupal Contributor Guide β†’ to find step-by-step guides for working with issues.

  • πŸ‡¨πŸ‡­Switzerland berdir Switzerland

    > Good candidates for reviewers are the maintainers of the mailsystem module I guess.

    the maintainer of that module is following this issue, I'll try to review soon.

  • πŸ‡¨πŸ‡­Switzerland znerol

    Fixed issue reported in #13.

  • Pipeline finished with Success
    5 months ago
    Total: 1508s
    #400810
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Apologize for letting this one sit.

    But does need a rebase again

    If you are another contributor eager to jump in, please allow the previous poster at least 48 hours to respond to feedback first, so they have the opportunity to finish what they started!

  • πŸ‡¨πŸ‡­Switzerland znerol

    Conflicts due to πŸ“Œ Use ::class instead of string literals in plugin managers Active resolved.

  • Pipeline finished with Failed
    4 months ago
    Total: 105s
    #429035
  • Pipeline finished with Success
    4 months ago
    Total: 2454s
    #429054
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Does this require a CR you think?

  • πŸ‡¨πŸ‡­Switzerland znerol

    I guess yes.

  • The Needs Review Queue Bot β†’ tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

    Consult the Drupal Contributor Guide β†’ to find step-by-step guides for working with issues.

  • Pipeline finished with Success
    3 months ago
    Total: 1023s
    #452293
  • πŸ‡¨πŸ‡­Switzerland znerol

    Pipeline passed.

  • Status changed to Needs review 29 days ago
  • Some comments on the MR. I'm also wondering if the mail theme classes shouldn't be in the `Drupal\Core\Mail` namespace instead of `Drupal\Core\MailTheme`? Though I think everything mentioned is personal preference and not necessarily a blocker.

  • πŸ‡¨πŸ‡­Switzerland znerol

    Thanks, I like all of the suggestions.

    I'm also wondering if the mail theme classes shouldn't be in the `Drupal\Core\Mail` namespace instead of `Drupal\Core\MailTheme`?

    My plan was to deprecated everything in Drupal\Core\Mail eventually. πŸ“Œ [PP-1] Add symfony mailer transports to DIC Postponed introduces Drupal\Core\Mailer namespace as a replacement.

  • Pipeline finished with Success
    29 days ago
    Total: 655s
    #492946
  • πŸ‡¨πŸ‡­Switzerland znerol

    Added a CR draft.

  • πŸ‡¬πŸ‡§United Kingdom adamps

    Great. Here are my comments.

    1) If we apply this to the existing mailer then it seems not to meet the back-compatibility requirements of a minor release.

    • Change in behaviour: introducing this code could change the theme used when rendering emails. This in turn affects which templates and CSS files are used.
    • Change in UI: before it was the mailsystem one and now it is the Core one.
    • Change in config model: before the mailsystem setting now the Core one (requires a change to installation profiles etc).

    Secondly it potentially creates forward-compatibility problems because then these changes aren't experimental, and we might need to make changes as we develop the rest of the mailer.

    If we add it only to the new mailer, and we have a global setting whether to use old mailer or new, then this solves the problem as sites have a choice when to adopt it. Sites using the old mailer anyway have an existing working solution using mailsystem and might even prefer that we leave them in peace until one big change when they switch mailsystem.

    2)

    The Drupal Symfony Mailer project implemented this functionality in a more flexible way. However, since it is reusing patterns unique to that module, the mechanism isn't easily portable to current core architecture.

    Yes I understand your point. I feel that the key here is to ensure that we can re-implement the DSM flexibility on top of the mechanism proposed here.

    The main question I have is regarding MailThemeNegotiator::applies(), which requires the choice of theme to depend only on MailTemplateID. This doesn't "unambiguously identifies the email to be sent" as the IS states but identifies a category (the email also varies with the params etc). I can imagine scenarios where we would require more flexibility: e.g. the site has multiple brands with different main themes. We might check the user who will receive the email, see which brand they registered with, and choose the matching theme.

    I feel we want instead is the email object - and I am aware this doesn't exist yet, however we could create a placeholder class for the purpose of this issue that we fill out later.

    3) This patch is making key design choices about the new mailer in advance of an overall design (AFAIK). I feel it could be really useful to try to establish a design in advance, but otherwise I guess we can discuss design questions here.

    a) The concept of a MailTemplateId. In contrib DSM v2 we have a string value named "tag" - which follows after the concepts in the underlying symfony code. This choice was actually influenced by a comment from @znerol on another issueπŸ˜ƒ . It's a "dotted-string" format, with the first part being the module, hence allowing a hierarchy such as contact.page.copy and simplenews.subscriber.validate. The two alternatives are basically compatible so it's not a big deal, but I feel it could really help the community if we could make Core and Contrib consistent as much as possible. If you agree with my comment 2 then anyway this patch doesn't need to contain MailTemplateId so we can defer the discussion.

    b) I agree with the basic approach of executing the mail building/sending code in a new context with the correct theme. When we take the whole design into account, I found 4 contexts that we need to switch: render, theme, language and user. This led DSM to choose a general approach, with a Mailer class which does all 4 switches. We could make MailThemeManager::switchTheme() public, and then it works more like AccountSwitcher (perhaps we call it MailThemeSwitcher?). I agree it could work with 4 separate switches stacked inside one another, each with try/finally and creating a new closure, but it seems less clear.

    The language switcher is also missing, see πŸ“Œ Allow to change the current language Needs work , which should handle translations, see #3029003: TranslationManager has method setDefaultLangcode not defined on any interface. β†’ .

  • πŸ‡¨πŸ‡­Switzerland berdir Switzerland

    The main question I have is regarding MailThemeNegotiator::applies(), which requires the choice of theme to depend only on MailTemplateID. This doesn't "unambiguously identifies the email to be sent" as the IS states but identifies a category (the email also varies with the params etc). I can imagine scenarios where we would require more flexibility: e.g. the site has multiple brands with different main themes. We might check the user who will receive the email, see which brand they registered with, and choose the matching theme.

    I think it's perfectly fine if applies() and the actual logic considers global context like current user/domain/configuration, you can just inject that in your service. I don't expect we'd do any caching or so of this logic, so we don't need to be aware of all the things that might influence the decision, we just run through this on every e-mail.

    On BC, I think it's fine if it applies to the current mailer if core doesn't come with en enforced default. Either nothing for now, or a configurable setting which could be a 1:1 copy of what mailsystem does, with current/default/specific theme list.

  • πŸ‡¬πŸ‡§United Kingdom adamps

    The Drupal Symfony Mailer project implemented this functionality in a more flexible way. However, since it is reusing patterns unique to that module, the mechanism isn't easily portable to current core architecture.

    I suggested how the patterns from DSM could be introduced in Core in ✨ Create new mailer service based on symfony Active . In addition to being more flexible, it feels simpler, just $email->setTheme() without adding 3 new services and a service tag. So far my suggestion doesn't seem popular, and I've got no problem with that, of course you will make your own way.

    You can ignore my other points from #25. Contrib DSM can just stick with the approach that it already uses and that works.

Production build 0.71.5 2024