Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.6k
[Mime] useisRendered
method to ensure we can avoid rendering an email twice#59596
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
f83820d
to7ed10bd
Compare288c4c0
to477343b
CompareWould there be a way to test this? |
@nicolas-grekas I need to take a closer look to it. |
isRendered
method to ensure we can avoid rendering an email twicec6c75a6
to234c657
CompareHey 👋 I reviewed the existing tests and found that the Since the test below is very similar to publicfunctiontestEmailIsNotRenderedTwice(){$twig =newEnvironment(newArrayLoader(['text' =>'Initial Text','html' =>'<b>Initial HTML</b>', ]));$renderer =newBodyRenderer($twig);$email =newTemplatedEmail();$email->textTemplate('text');$email->htmlTemplate('html');// First render$renderer->render($email);$this->assertTrue($email->isRendered());$this->assertEquals('Initial Text',$email->getTextBody());$this->assertEquals('<b>Initial HTML</b>',$email->getHtmlBody());// Manually setting the text and HTML content to simulate a previous render$email->text('Manually Set Text');$email->html('Manually Set HTML');// Second render should not override manually set values$renderer->render($email);$this->assertEquals('Manually Set Text',$email->getTextBody());$this->assertEquals('Manually Set HTML',$email->getHtmlBody());} |
234c657
to2d37c79
CompareThank you@walva. |
0beb17a
intosymfony:6.4Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Description:
After upgrading my project from Symfony 5.4 to 6.4, due thischange, I encountered an issue where asynchronous email sending failed due to serialization problems with
TemplatedEmail
. According to theSymfony documentation, when sending an email asynchronously, the email instance must be serializable. While Mailer instances are inherently serializable,TemplatedEmail
requires that its context be serializable. If the context contains non-serializable variables, such as Doctrine entities, it's recommended to either replace them with serializable variables or render the email before calling$mailer->send($email)
.To address this, I decorated the Symfony
Mailer
to force the rendering of emails using theBodyRendererInterface::render(Message $message): void
method. However, this approach led to an exception indicating that the context was empty. The method successfully rendered the email, clearing its context, but the sameTemplatedEmail
object was rendered again later in the execution process, specifically in theMessageListener.To prevent this double rendering, I utilized the
TemplatedEmail::isRendered(): bool
method, as seen in theAbstractTransport. This ensures that if an email is already rendered, it won't be rendered again, preserving the context and preventing serialization issues.Solution
The proposed fix involves checking if the
TemplatedEmail
has already been rendered before attempting to render it again. By using theisRendered()
method, we can avoid unnecessary re-rendering, which can lead to empty contexts and serialization problems during asynchronous email sending.Impact
This correction allows classes extending
TemplatedEmail
to be sent asynchronously without encountering errors related to double rendering or context loss due to serialization issues, as outlined in the documentation.References
Symfony Mailer Documentation
MessageListener Implementation
AbstractTransport Implementation
This pull request aims to enhance the robustness of asynchronous email handling in Symfony by ensuring that TemplatedEmail instances are not rendered multiple times, thereby maintaining their context and serializability.
Original message:
Following up my comment onhttps://github.com/symfony/symfony/pull/47075/files.
I would recommend using the method TemplatedEmail::isRendered() the same way it is used inAbstractTransport.php.
Keeping like this prevents subclass of TemplatedEmail with computed html template to not be rendered twice, such asNotificationEmail.
This change will allow developers to create a subclass of template emails and render them before sending them async, without rendering them twice.