Skip to content

Commit

Permalink
Merge pull request #3068 from stof/symfony_mailer
Browse files Browse the repository at this point in the history
Add a mailer implementation based on symfony/mailer
  • Loading branch information
stof authored Jan 16, 2024
2 parents 4c0a2a8 + dd15a76 commit c70ecfd
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 11 deletions.
2 changes: 2 additions & 0 deletions DependencyInjection/FOSUserExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ private function loadRegistration(array $config, ContainerBuilder $container, Xm
unset($config['confirmation']['from_email']);
}
$container->setParameter('fos_user.registration.confirmation.from_email', [$fromEmail['address'] => $fromEmail['sender_name']]);
$container->setParameter('fos_user.registration.confirmation.from_address', $fromEmail);

$this->remapParametersNamespaces($config, $container, [
'confirmation' => 'fos_user.registration.confirmation.%s',
Expand Down Expand Up @@ -234,6 +235,7 @@ private function loadResetting(array $config, ContainerBuilder $container, XmlFi
unset($config['email']['from_email']);
}
$container->setParameter('fos_user.resetting.email.from_email', [$fromEmail['address'] => $fromEmail['sender_name']]);
$container->setParameter('fos_user.resetting.email.from_address', $fromEmail);

$this->remapParametersNamespaces($config, $container, [
'' => [
Expand Down
94 changes: 94 additions & 0 deletions Mailer/TwigSymfonyMailer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

/*
* This file is part of the FOSUserBundle package.
*
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FOS\UserBundle\Mailer;

use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Mailer\MailerInterface as SymfonyMailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Twig\Environment;

/**
* @author Christophe Coevoet <[email protected]>
*/
final class TwigSymfonyMailer implements MailerInterface
{
private SymfonyMailerInterface $mailer;
private UrlGeneratorInterface $router;
private Environment $twig;
private array $parameters;

public function __construct(SymfonyMailerInterface $mailer, UrlGeneratorInterface $router, Environment $twig, array $parameters)
{
$this->mailer = $mailer;
$this->router = $router;
$this->twig = $twig;
$this->parameters = $parameters;
}

public function sendConfirmationEmailMessage(UserInterface $user): void
{
$template = $this->parameters['template']['confirmation'];
$url = $this->router->generate('fos_user_registration_confirm', ['token' => $user->getConfirmationToken()], UrlGeneratorInterface::ABSOLUTE_URL);

$context = [
'user' => $user,
'confirmationUrl' => $url,
];

$this->sendMessage($template, $context, $this->parameters['from_email']['confirmation'], $user->getEmail());
}

public function sendResettingEmailMessage(UserInterface $user): void
{
$template = $this->parameters['template']['resetting'];
$url = $this->router->generate('fos_user_resetting_reset', ['token' => $user->getConfirmationToken()], UrlGeneratorInterface::ABSOLUTE_URL);

$context = [
'user' => $user,
'confirmationUrl' => $url,
];

$this->sendMessage($template, $context, $this->parameters['from_email']['resetting'], $user->getEmail());
}

/**
* @param array<string, mixed> $context
* @param array{address: string, sender_name: string} $fromEmail
*/
private function sendMessage(string $templateName, array $context, array $fromEmail, string $toEmail): void
{
$template = $this->twig->load($templateName);
$subject = $template->renderBlock('subject', $context);
$textBody = $template->renderBlock('body_text', $context);

$htmlBody = '';

if ($template->hasBlock('body_html', $context)) {
$htmlBody = $template->renderBlock('body_html', $context);
}

$message = (new Email())
->subject($subject)
->from(new Address($fromEmail['address'], $fromEmail['sender_name']))
->to($toEmail)
->text($textBody)
;

if (!empty($htmlBody)) {
$message->html($htmlBody);
}

$this->mailer->send($message);
}
}
24 changes: 24 additions & 0 deletions Resources/config/mailer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
<parameter key="fos_user.resetting.email.from_email" type="collection">
<parameter key="[email protected]">Acme Ltd</parameter>
</parameter>
<parameter key="fos_user.registration.confirmation.from_address" type="collection">
<parameter key="address">[email protected]</parameter>
<parameter key="sender_name">Acme Ltd</parameter>
</parameter>
<parameter key="fos_user.resetting.email.from_address" type="collection">
<parameter key="address">[email protected]</parameter>
<parameter key="sender_name">Acme Ltd</parameter>
</parameter>
</parameters>

<services>
Expand All @@ -33,6 +41,22 @@
<tag name="fos_user.requires_swift" />
</service>

<service id="fos_user.mailer.twig_symfony" class="FOS\UserBundle\Mailer\TwigSymfonyMailer" public="false">
<argument type="service" id="mailer" />
<argument type="service" id="router" />
<argument type="service" id="twig" />
<argument type="collection">
<argument key="template" type="collection">
<argument key="confirmation">%fos_user.registration.confirmation.template%</argument>
<argument key="resetting">%fos_user.resetting.email.template%</argument>
</argument>
<argument key="from_email" type="collection">
<argument key="confirmation">%fos_user.registration.confirmation.from_address%</argument>
<argument key="resetting">%fos_user.resetting.email.from_address%</argument>
</argument>
</argument>
</service>

<service id="fos_user.mailer.noop" class="FOS\UserBundle\Mailer\NoopMailer" public="false" />
</services>

Expand Down
20 changes: 9 additions & 11 deletions Resources/doc/emails.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,18 @@ a form to enter in a new password.
Default Mailer Implementations
------------------------------

The bundle comes with 2 mailer implementations. They are listed below
The bundle comes with 3 mailer implementations. They are listed below
by service id:

- ``fos_user.mailer.twig_symfony`` uses symfony/mailer to send emails and Twig blocks to render the message.
- ``fos_user.mailer.twig_swift`` uses Swiftmailer to send emails and Twig blocks to render the message.
- ``fos_user.mailer.noop`` is a mailer implementation which performs no operation, so no emails are sent.

.. note::

The ``fos_user.mailer.noop`` mailer service should be used in the case
where you do not want the bundle to send emails and you do not want to
include the SwiftmailerBundle in your app.
include an actual mailer in your app.

Configuring the Sender Email Address
------------------------------------
Expand Down Expand Up @@ -103,13 +104,12 @@ the password reset request email:
Sending HTML mails
------------------

The default mailer only supports sending plain text messages. If you want
to send multipart messages, the easiest solution is to use the TwigSwiftMailer
implementation instead. It expects your twig template to define 3 blocks:
The default mailers supports sending multipart messages. They expect your twig template
to define 3 blocks:

- ``subject`` containing the email subject
- ``body_text`` rendering the plain text version of the message
- ``body_html`` rendering the html mail
- ``body_html`` rendering the html mail (this block is optional)

Here is how you can use it, you can use either of the two methods
of referencing the email template below.
Expand All @@ -120,7 +120,7 @@ of referencing the email template below.
fos_user:
# ...
service:
mailer: fos_user.mailer.twig_swift
mailer: fos_user.mailer.twig_symfony
resetting:
email:
template: email/password_resetting.email.twig
Expand Down Expand Up @@ -166,10 +166,8 @@ You can view the default email templates at
Using A Custom Mailer
---------------------

The default mailer service used by FOSUserBundle relies on the Swiftmailer
library to send mail. If you would like to use a different library to send
emails, want to send HTML emails or simply change the content of the email you
may do so by defining your own service.
If you would like to use a different library to send emails, want to send HTML emails
or simply change the content of the email you may do so by defining your own service.

First you must create a new class which implements ``FOS\UserBundle\Mailer\MailerInterface``
which is listed below.
Expand Down
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
"friendsofphp/php-cs-fixer": "^3.0.2, !=3.5.0",
"swiftmailer/swiftmailer": "^4.3 || ^5.0 || ^6.0",
"symfony/console": "^4.4 || ^5.0 || ^6.0",
"symfony/mailer": "^4.4 || ^5.0 || ^6.0",
"symfony/mime": "^4.4 || ^5.0 || ^6.0",
"symfony/phpunit-bridge": "^6.1",
"symfony/yaml": "^4.4 || ^5.0 || ^6.0"
},
Expand Down

0 comments on commit c70ecfd

Please sign in to comment.