Mails not being send in user preferred language.

Created on 4 July 2023, over 1 year ago

Problem/Motivation

When blocking or activating a user as admin the mails are not send in the user's preferred language.

Steps to reproduce

Go to the user overview.
Go the the edit page of a user.
Select a preferred language for the user other than the default site language.
Block the user.

User wil get a mail in the site default language.

Proposed resolution

Make sure the config translations of the policies are being loaded in the adjuster plugins.

Remaining tasks

User interface changes

API changes

Data model changes

๐Ÿ› Bug report
Status

Active

Version

1.2

Component

Code

Created by

๐Ÿ‡ง๐Ÿ‡ชBelgium Wouter Waeytens

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

Merge Requests

Comments & Activities

  • Issue created by @Wouter Waeytens
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    I don't think that's the right way to do translation. The email body and subject come from a config entity. Instead you should use the Drupal mechanism for translations of config.

  • Status changed to Closed: works as designed over 1 year ago
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps
  • Status changed to Active 11 months ago
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Patrick R.

    While the proposed patch is certainly not the way to go the problem with mails being sent in the wrong language when using adjusters like SubjectEmailAdjuster or BodyEmailAdjuster still persists. The adjuster plugins are already instantiated during initEmail() in the EmailFactory class which is happening quite some time before the eventual language switch might happen in Mailer::doSend(), so there's no way to get mails sent in the correct language using these adjusters even when using config translation properly. Not seeing a simple solution for this though. :-/

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Patrick R.

    Added the following as a workaround to my email builder plugin. Not overly pretty, but it seems to work. ๐Ÿคท๐Ÿปโ€โ™‚๏ธ

    
    /**
     * {@inheritdoc}
     */
    public function preRender(EmailInterface $email) {
      $adjusters = ['email_body', 'email_subject'];
      $suggestions = $email->getSuggestions('', '.');
    
      $adjuster_manager = \Drupal::service('plugin.manager.email_adjuster');
      $policy_config = MailerPolicy::loadInheritedConfig(end($suggestions));
    
      foreach ($policy_config as $plugin_id => $config) {
        if (in_array($plugin_id, $adjusters) && $adjuster_manager->hasDefinition($plugin_id)) {
          $adjuster_manager->createInstance($plugin_id, $config)->build($email);
        }
      }
    }
    
    
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    Ah good point thanks for the update.

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia mingsong ๐Ÿ‡ฆ๐Ÿ‡บ

    I tested this issue with
    Drupal 10.2.3
    Symfony Mailer 1.4.1

    And two issues I came across

    1. Imported policies didn't load the translation email content.
    2. Translate mailer policy wasn't applied to the email sent to the user in user's language.
  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia mingsong ๐Ÿ‡ฆ๐Ÿ‡บ

    Right. after debugging the code, I think I figure out what is happening here.

    In the Mailer::doSend() function,

    https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Mailer....

    We have four phases to process an email.

    In phase 'build', https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Mailer....

    The email body, subject and other contents were built in the default language since the configuration language hasn't been changed yet.

    After that, the language will be changed to user's language at line 224
    https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Mailer....

    Next phase is 'PHASE_PRE_RENDER', in this phase, the $email->process() will call the 'preRend()' function for each email adjuster, including the subject and body adjuster.
    BodyEmailAdjuster https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Plugin/...
    SubjectEmailAdjuster https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Plugin/...

    But the problem is that those email address doesn't have the preRend() fuction, so they won't change anything. The email subject and body still remain in the default language.

    And so on, after this stage, all coming phase won't change the language at all.

    So that is why the email will always be built in the default language of the website.

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia mingsong ๐Ÿ‡ฆ๐Ÿ‡บ

    Another problem with the translation of an email is that, the configuration of an adjuster plugin is loaded in the default language when the plugin is initiated.
    Even if the languageManager->setConfigOverrideLanguage($language) is called after that, the configuration loaded before won't be changed, until the configuration is loaded again.

    So if I add the following preRender function to SubjectEmailAdjuster class,

      public function preRender(EmailInterface $email) {
        $mail_config = \Drupal::config('symfony_mailer.mailer_policy.user.status_activated');
    
        $config = $mail_config->get('configuration.email_subject');
    
        if (isset($config['value'])) {
          $subject = $config['value'];
        }
        else {
          $subject = $this->configuration['value'];
        }
    
        $email->setSubject($subject, TRUE);
      }
    

    Then the email subject is translated to the user language.

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    Yes I feel that #6 and #10 both contain the seed of the solution. But both are hard-coded to a specific case of course we can't check them in as is.
    - The problem could apply to many adjusters (the plain text body; the addresses have a display name; even the skip sending has a displayed message)
    - And to any builder

    I propose that once we have chosen the language in Mailer.php then we should reload the policy with the correct language. The code that loaded them originally was in EmailFactory:

        $this->emailAdjusterManager->applyPolicy($email);
    

    However at the moment, Email::addProcessor() would also keep the original adjusters - they don't overwrite. We can fix that by changing the code to

    $this->processors[$phase][$id] = 
    

    But we still have a problem that the subject/body are being used mainly in the build() function that had already run. We also need a fix to ๐Ÿ“Œ Change to the phases Active .

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany Patrick R.

    I propose that once we have chosen the language in Mailer.php then we should reload the policy with the correct language. The code that loaded them originally was in EmailFactory:

    Might also be an idea to only instantiate adjuster plugins when they are applied during a certain phase and have the plugins use different phases - address adjusters should probably run earlier than e.g. subject or body adjusters since they could be responsible for determining the language of the email. SearchApiProcessor plugins use "stages" in their plugin annotations, maybe EmailAdjuster plugins should define "phases" in their annotations. ๐Ÿค”

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    There is now a MR for ๐Ÿ“Œ Change to the phases Active . It should fix #9 but not #10. Review and testing very welcome please.

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    I have written code that reloads the config at the start of the build phase.

    It's in a 2nd MR https://git.drupalcode.org/project/symfony_mailer/-/merge_requests/106. It's on the other issue, because it depends on that first fix and I could see any way to link between one fork and another.

    I haven't tested it as I don't use multi-lingual on any sites, and I'm not familiar with how to set it up. However I have run some basic testing to see that the code that should reload the config is being executed.

  • Merge request !107Resolve #3372166 "Wrong language" โ†’ (Merged) created by adamps
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    MR here is now ready for review

  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland oakulm

    Great news! I can see that the patch applies to 1.x-dev and emails are being sent in user preferred language. Subject and body are both working and fallback language is also working if there's no translation.

    For someone to verify go to admin/config/system/mailer/test translate the test email policy, add email of existing user to recipient email address field and hit send. Also make sure the user prefered language is correct in user edit page.

    I also made custom email policy and it seems to work as well. I'm not familiar with 2.x-dev branch and have not tested on that.

  • Pipeline finished with Skipped
    2 months ago
    #304125
    • adamps โ†’ committed 93829480 on 2.x
      Issue #3372166 by adamps, Wouter Waeytens, patrick r., mingsong, oakulm...
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    Great thanks

  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland oakulm

    Sorry to come back to this but for some reason the patch does not apply anymore to 1.5. Not exactly sure why it was working before. But the problem is here: https://git.drupalcode.org/project/symfony_mailer/-/merge_requests/107/d... in src/EmailFactory.php

    I can make the patch apply cleanly with this change but the code itself does not seem to work.

    diff --git a/src/EmailFactory.php b/src/EmailFactory.php
    index 53e6be0..e7a0714 100644
    --- a/src/EmailFactory.php
    +++ b/src/EmailFactory.php
    @@ -96,9 +96,7 @@ class EmailFactory implements EmailFactoryInterface {
         }
    
         // Apply policy.
    -    $this->emailAdjusterManager->applyPolicy($email);
    -
    -    $email->initDone();
    +    $email->addProcessor($this->emailAdjusterManager);
         return $email;
       }

    addProcessor expects callable as a param. Any ideas?

  • ๐Ÿ‡ณ๐Ÿ‡ฑNetherlands rfbrandsma
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    This bug has been fixed in 2.x, so I like to keep the issue summary clear and correct for that please.

    I am willing to do a backport. Please create a separate issue that includes the working MR for 1.x. Please don't just create the issue and expect that someone else will do the work๐Ÿ˜ƒ. The backport issue without the MR is just an annoyance for the maintainer.

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024