Skip to content

[Notifier] Add easier way to remove Importance from EmailNotification Subject #37879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
alexander-schranz opened this issue Aug 18, 2020 · 12 comments · Fixed by #40448
Closed
Labels

Comments

@alexander-schranz
Copy link
Contributor

alexander-schranz commented Aug 18, 2020

Description

When using the notifier the subject contains priority. I think in most cases you don't want to have the priority in the subject of the email (its not translated and contains maybe information not needed for the end user). So it would be great that we maybe could change this behaviour for the next major release, not sure if there could be a way to implement this now.

$headers->setHeaderBody('Text', 'Subject', sprintf('[%s] %s', strtoupper($importance), $this->getSubject()));

In the future I would maybe think that in the subject could be used a placeholder if somebody really wanted to have the priority in it but I personally see no advantage of it.

Example

This is how it could look in future to set a subject with importance:

use Symfony\Bridge\Twig\Mime\NotificationEmail;

$email = (new NotificationEmail())
    ->importance(NotificationEmail::IMPORTANCE_HIGH)
    ->subject('[%importance%] My Subject');

Current Workaround

At current state you need to implement your own NotificationEmail class to override this behaviour:

namespace App\Checkin\Application\Notifications;

use Symfony\Bridge\Twig\Mime\NotificationEmail;
use Symfony\Component\Mime\Header\Headers;

class CustomNotificationEmail extends NotificationEmail
{
    public function getPreparedHeaders(): Headers
    {
        $headers = parent::getPreparedHeaders();

        $headers->setHeaderBody('Text', 'Subject', $this->getSubject());

        return $headers;
    }
}
@shristov-iMeniu
Copy link

Description

I created my own "Email" class, extended the "NotificationEmail" class and override the getPreparedHeaders method. But the subject is not changing. I added "dd()" and realised the workflow doesn't goes inside the implemented getPreparedHeaders method of the own class.

Example

Here is my own "Email" class (it's pretty much the same):

namespace App\Service\Mailer;


use Symfony\Bridge\Twig\Mime\NotificationEmail;
use Symfony\Component\Mime\Header\Headers;

class Email extends NotificationEmail
{
    public function getPreparedHeaders(): Headers
    {
        $headers = parent::getPreparedHeaders();

        $headers->setHeaderBody("Text", "Subject", $this->getSubject());

        return $headers;
    }
}

Question

Is there any other solution to workaround this issue?

@ngrie
Copy link

ngrie commented Jan 14, 2021

This indeed is a bit impractical right now when sending notifications to end users. There even exists the asPublicEmail method, would be great to be able to use that somehow when sending notifications using the notifier.

Not sure though how this could be made configurable. Maybe using a something like a "public" flag when defining a notification?

@maxailloud
Copy link
Contributor

I don't understand the underlying decision that lead to that.
It makes the notifier not suited to send emails to end users in this state. Or maybe I am missing something.

maxailloud added a commit to maxailloud/symfony that referenced this issue Mar 10, 2021
Closes symfony#37879

Using the NotificationEmail alongside the Symfony Notifier for end users is a bit weird as the importance is automatically added to the subject of the email.
This PR allows the NotificationEmail to be marked as public, the same way it was possible with the static `NotificationEmail::asPublicEmail`.
@stof
Copy link
Member

stof commented Mar 11, 2021

It makes the notifier not suited to send emails to end users in this state. Or maybe I am missing something.

that's what the Mailer component is for though

@maxailloud
Copy link
Contributor

My use case is sending an email + sending a push notification to mobile app. So I was expecting the notifier component to be the one to use to do that.
I don't see why the notifier would be only to send only to admin, or users who cares about the importance of emails at least.

maxailloud added a commit to maxailloud/symfony that referenced this issue Mar 11, 2021
Closes symfony#37879

Using the NotificationEmail alongside the Symfony Notifier for end users is a bit weird as the importance is automatically added to the subject of the email.
This PR allows the NotificationEmail to be marked as public, the same way it was possible with the static `NotificationEmail::asPublicEmail`.

i#Add tests for new  method
@fabpot fabpot closed this as completed Mar 12, 2021
fabpot added a commit that referenced this issue Mar 12, 2021
…public (maxailloud)

This PR was squashed before being merged into the 5.3-dev branch.

Discussion
----------

[twig-bridge] Allow NotificationEmail to be marked as public

| Q             | A
| ------------- | ---
| Branch?       | 5.x for features
| Bug fix?      |no
| New feature?  | yes
| Deprecations? |no
| Tickets       | Fix #37879
| License       | MIT
| Doc PR        | -

Closes #37879

`NotificationEmail` can be created public from the `asPublicEmail` method in any context but with the Notifier component. In this case it is created by it as not public and therefore displays the importance in the subject of the email.
For end users, aka not admin, the importance in the subject's email is not necessary.
This PR will allow if needed to set a `NotificationEmail` as public even after being created, wherever it was created.

I am not sure how to handle the version in the changelog.
For the tests I don't know what's the policy so I just added a new case in each test case.

Commits
-------

8f753d2 [twig-bridge] Allow NotificationEmail to be marked as public
symfony-splitter pushed a commit to symfony/twig-bridge that referenced this issue Mar 12, 2021
…public (maxailloud)

This PR was squashed before being merged into the 5.3-dev branch.

Discussion
----------

[twig-bridge] Allow NotificationEmail to be marked as public

| Q             | A
| ------------- | ---
| Branch?       | 5.x for features
| Bug fix?      |no
| New feature?  | yes
| Deprecations? |no
| Tickets       | Fix #37879
| License       | MIT
| Doc PR        | -

Closes symfony/symfony#37879

`NotificationEmail` can be created public from the `asPublicEmail` method in any context but with the Notifier component. In this case it is created by it as not public and therefore displays the importance in the subject of the email.
For end users, aka not admin, the importance in the subject's email is not necessary.
This PR will allow if needed to set a `NotificationEmail` as public even after being created, wherever it was created.

I am not sure how to handle the version in the changelog.
For the tests I don't know what's the policy so I just added a new case in each test case.

Commits
-------

8f753d27f2 [twig-bridge] Allow NotificationEmail to be marked as public
@alexander-schranz
Copy link
Contributor Author

@maxailloud Thank you 👍

@antoine1003
Copy link

Hey guys,
I am still trying to figure out how can I use the markAs public with the build in notifer in Symfony :/

For now my notification class il like that :

<?php

namespace App\Notifier;

use App\Entity\Enfant;
use App\Entity\Sollicitation;
use App\Entity\Spectacle;
use Symfony\Bridge\Twig\Mime\NotificationEmail;
use Symfony\Component\Notifier\Message\EmailMessage;
use Symfony\Component\Notifier\Notification\EmailNotificationInterface;
use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\Recipient\EmailRecipientInterface;

class DemandeDisponibiliteNotification extends Notification implements EmailNotificationInterface
{
   // [...]
    public function __construct(array $enfants, Sollicitation $sollicitation)
    {
        $this->enfants = $enfants;
        $this->sollicitation = $sollicitation;
        parent::__construct('Nouvelle sollicitation pour ' . $sollicitation->getSpectacle()->getNom());
    }

    public function asEmailMessage(EmailRecipientInterface $recipient, string $transport = null): ?EmailMessage
    {
        $this->importance(Notification::IMPORTANCE_MEDIUM);
        $message = EmailMessage::fromNotification($this, $recipient, $transport);
        $message->getMessage()
            ->htmlTemplate('emails/sollicitation/demande_disponibilite.html.twig')
            ->context([
                'enfants' => $this->enfants,
                'sollicitation' => $this->sollicitation,
                'parent' => $recipient
            ])
        ;
        return $message;
    }
}

And to send it I use $this->notifier->send(new DemandeDisponibiliteNotification($enfants, $sollicitation), $parent); I don't see how can I transform this without getting the importance in the subject :/ There is nothing in the documentation...

Thanks for your help :)

@maxailloud
Copy link
Contributor

@antoine1003
You should do something like this in this case:

$demandeDisponibiliteNotification = new DemandeDisponibiliteNotification($enfants, $sollicitation);
$demandeDisponibiliteNotification->markAsPublic();

$this->notifier->send($demandeDisponibiliteNotification, $parent);

Without trying you could even try to add $this->markAPublic; in the constructor of your notification, but it means it will always be like this for this notification.

@pmorelVM
Copy link

pmorelVM commented Feb 2, 2022

@antoine1003
Hi, maybe with this one ?

<?php

namespace App\Notifier;

use App\Entity\Enfant;
use App\Entity\Sollicitation;
use App\Entity\Spectacle;
use Symfony\Bridge\Twig\Mime\NotificationEmail;
use Symfony\Component\Notifier\Message\EmailMessage;
use Symfony\Component\Notifier\Notification\EmailNotificationInterface;
use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\Recipient\EmailRecipientInterface;

class DemandeDisponibiliteNotification extends Notification implements EmailNotificationInterface
{
   // [...]
    public function __construct(array $enfants, Sollicitation $sollicitation)
    {
        $this->enfants = $enfants;
        $this->sollicitation = $sollicitation;
        parent::__construct('Nouvelle sollicitation pour ' . $sollicitation->getSpectacle()->getNom());
    }

    public function asEmailMessage(EmailRecipientInterface $recipient, string $transport = null): ?EmailMessage
    {
        $email = NotificationEmail::asPublicEmail()
            ->to($recipient->getEmail())
            ->subject($this->getSubject());

        $message = new EmailMessage($email);
        $message->getMessage()
            ->htmlTemplate('emails/sollicitation/demande_disponibilite.html.twig')
            ->context([
                'enfants' => $this->enfants,
                'sollicitation' => $this->sollicitation,
                'parent' => $recipient
            ])
        ;
        return $message;
    }
}

Explanation: you can't use EmailMessage::fromNotification to get the message anymore, because it returns an EmailMessage object based on this type of NotificationEmail

(new NotificationEmail())
    ->to($recipient->getEmail())
    ->subject($notification->getSubject())
    ->content($notification->getContent() ?: $notification->getSubject())
    ->importance($notification->getImportance())

The new markAsPublic method has to be called on that NotificationEmail before we make an EmailMessage from it, and EmailMessage::fromNotification doesn't let you do that.

So, the alternative is to do the job of EmailMessage::fromNotification, but with the little markAsPublic extra call.

That what the

$email = NotificationEmail::asPublicEmail()
    ->to($recipient->getEmail())
    ->subject($this->getSubject());

$message = new EmailMessage($email);

part does : NotificationEmail::asPublicEmail() does it, to be precise.

@antoine1003
Copy link

antoine1003 commented Feb 2, 2022

Hey guys,
Thanks a lot for your help.
I read that the asPublicEmail could be a feature of Sumfony 5.4 and I am still in 5.3. So I'll try your solutions and let you know, if it doen't work I'll update my project to 5.4 😄
Have a good day !

@mopielka
Copy link

On the notification set:
$notification->importance('');

and in config/packages/notifier.yaml include the following channel policy:

framework:
    notifier:
        channel_policy:
            '':
                - email

@phasdev
Copy link
Contributor

phasdev commented Sep 24, 2024

Here's another option, which is a slight twist on the above:

Create App\Notifier\Notification.php which extends Symfony\Component\Notifier\Notification\Notification and overrides the asEmailMessage method:

<?php

namespace App\Notifier;

use Symfony\Bridge\Twig\Mime\NotificationEmail;
use Symfony\Component\Notifier\Message\EmailMessage;
use Symfony\Component\Notifier\Notification\EmailNotificationInterface;
use Symfony\Component\Notifier\Notification\Notification as SymfonyNotification;
use Symfony\Component\Notifier\Recipient\EmailRecipientInterface ;

// HACK: Mark email notifications as public to avoid adding importance to subject
class Notification extends SymfonyNotification implements EmailNotificationInterface
{
    private array $context;

    public function __construct(string $subject = '', array $channels = [], array $context = []) {
        $this->context = $context;
        parent::__construct($subject, $channels);
    }

    public function asEmailMessage(EmailRecipientInterface $recipient, ?string $transport = null): ?EmailMessage
    {
        $email = NotificationEmail::asPublicEmail()
            ->to($recipient->getEmail())
            ->subject($this->getSubject())
            ->content($this->getContent())                         
            ->context($this->context);

          // Don't set importance otherwise it will be included in subject
          //->importance($this->getImportance())
            
          // Override default template
          // ->htmlTemplate('@email/notification.html.twig')
          // ->textTemplate('@email/notification.txt.twig')
            
          // Add attachments, etc.
          // ->addPart(...)

        $message = new EmailMessage($email);

        return $message;
    }
}

Now you can use App\Notifier\Notification instead of Symfony\Component\Notifier\Notification\Notification if you want extra flexibility when generating email notifications (e.g. adding a title variable to the template's context so it can be used in the template):

use App\Notifier\Notification;
use Twig\Environment;

...

$context = [            
    'title' => 'New entity created',
    'action_text' => 'View entity',
    'action_url' => 'https://example.com',
    'footer_text' => 'Sent from custom notifier',
    'raw' => true,
];

$content = $this->twig->render(
    'email/created.html.twig', [
    'entity' => $entity 
]);

$notification = (new Notification($subject, ['email'], $context))
    ->importance(Notification::IMPORTANCE_LOW)
    ->content($content);

$this->notifier->send($notification, new Recipient('alice@example.com'));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants