Ibexa DXP Discussions

Community discussion forum for developers working with Ibexa DXP

eZ EE Send custom mail on submission

Good morning, everyone.

For once I don’t create a topic because I’m in trouble but because I’m rather proud to share my find.

My purpose is to send a notification email to the submission of a form based on the data entered.

The form has a “Subject” field of type select.
Depending on this choice, the email address to be notified is not the same.

Les mails de notification sont envoyés par le service EzSystems\EzPlatformFormBuilder\FormSubmission\Notification\EmailNotificationSender.
On va donc le Décorer.

services:
    MyBundle\EmailNotificationSender:
        # https://symfony.com/doc/3.4/service_container/service_decoration.html
        # overrides the EzSystems\...\EmailNotificationSender service
        # but that service is still available as ... (@see decoration_inner_name)
        decorates: EzSystems\EzPlatformFormBuilder\FormSubmission\Notification\EmailNotificationSender

        decoration_inner_name: MyBundle\FormBuilder\EmailNotificationSender.inner

        arguments:
            - "@mailer"
            - "@twig"
            - '@@ezdesign/form_builder/form_submit_notification_email.html.twig'

        # private, because usually you do not need to fetch  directly
        public:    false

    # https://symfony.com/doc/3.4/service_container/alias_private.html#aliasing
    EzSystems\EzPlatformFormBuilder\FormSubmission\Notification\EmailNotificationSender:
        alias: MyBundle\FormBuilder\EmailNotificationSender
        public: true

Note. We pass on to our service the same arguments as those passed on to the original service because we are going to make a legacy…

namespace MyBundle;

use eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\Core\FieldType\Author\Author;
use EzSystems\EzPlatformFormBuilder\FieldType\Model\Field;
use EzSystems\EzPlatformFormBuilder\FieldType\Model\Form;
use EzSystems\EzPlatformFormBuilder\FieldType\Model\FormSubmission;
use \EzSystems\EzPlatformFormBuilder\FormSubmission\Notification\EmailNotificationSender as EzEmailNotificationSender;
use EzSystems\EzPlatformFormBuilder\FormSubmission\Notification\NotificationSenderInterface;

class EmailNotificationSender extends EzEmailNotificationSender implements NotificationSenderInterface
{
    /** @var \Swift_Mailer */
    private $mailer;

    /** @var \Twig_Environment */
    private $twig;

    /** @var string */
    private $emailTemplate;

    public function __construct(\Swift_Mailer $mailer, \Twig_Environment $twig, $emailTemplate)
    {
        parent::__construct($mailer, $twig, $emailTemplate);
        $this->twig = $twig;
        $this->mailer = $mailer;
        $this->emailTemplate = $emailTemplate;
    }

    public function sendNotification(Content $content, Form $form, FormSubmission $data, Field $field): void
    {
        $recipients = $this->getRecipients($content, $form, $data);
        if ($recipients) {
            $this->doSendEmail($recipients, [
                'content' => $content,
                'form' => $form,
                'data' => $data,
            ]);
        }

        parent::sendNotification($content, $form, $data, $field); // Default ez mail.
    }

    private function getRecipients(Content $content, Form $form, FormSubmission $data)
    {
        // Do What you have to do
        return $recipients;
    }

    /**
     * Je suis obligé de recopier mot pour mot cette fonction car elle est privée. :(
     *
     * @param string[] $recipients
     * @param string[] $parameters
     *
     * @throws \Twig_Error_Loader
     * @throws \Twig_Error_Runtime
     * @throws \Twig_Error_Syntax
     */
    protected function doSendEmail(array $recipients, array $parameters = []): void
    {
        $template = $this->twig->loadTemplate($this->emailTemplate);
        $message = new \Swift_Message();
        $message->setSubject($template->renderBlock('subject', $parameters));
        $message->setTo($recipients);
        $message->setFrom('no-reply@editionsduboisbaudry.fr');
        $message->setBody($template->renderBlock('body', $parameters), 'text/html');
        $this->mailer->send($message);
    }
}

There you go!
When submitting the form we will be able to search for recipients for the notification email in the getRecipients function.
Note: The default behavior is retained.

As far as I’m concerned. I have in my form a subject_dest field which is a copy of the dropdown

ez_platform_form_builder:
    fields:
        subject_dest:
            name: 'Subject'
            thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#dropdown'
            attributes:
                help:
                    name: 'Help'
                    type: 'string'
                options:
                    name: 'Options'
                    type: 'choices'
            validators:
                required: ~

And in my Form ContentType I have an Author field. (form_subject_dest)

And if there is a match between the value entered by the Internet user in the subject_dest field and the name of an author, we have a recipient.

    private function getRecipients(Content $content, Form $form, FormSubmission $data)
    {
        /** @var \Ez\Publish\Core\FieldType\Author\Value $fv */
        $fv = $content->getFieldValue('form_subject_dest');

        $recipients = [];

        $selected_value = null; // La valeur sélectionnées dans le champ de type 'select_value' par l'Internaute.
        foreach ($data->getValues() as $value) {
            if ($value->getIdentifier() === 'subject_dest') {
                $selected_value = $value->getValue();
                if ($selected_value) {
                    break;
                }
            }
        }

        foreach ($fv->authors as $author) {/** @var Author $author */
            if ($author->name === $selected_value) {
                $recipients[] = $author->email;
            }
        }

        return $recipients;
    }

It’s a little bit of DIY, but it works.

The best would be to have a form field that does all this… But now I’m tired…

Nice! Just a note to anyone implementing getRecipients(), don’t read them from the submitted form, because then you’ll have created an engine for anonymous spam sending :wink:

1 Like

Hello,

I’m digging up my subject because I have a problem with multiple sending.

When the form is filled in, the email is sent several times to the recipients.

In fact, my sendNotification() function is called several times until it gets a “504 Gateway Time-out”.

This makes between 12 and 66 mailings depending on the server performance.

A quick reminder of my code:

class EmailNotificationSender extends EzEmailNotificationSender implements NotificationSenderInterface
{
    /** @var \Swift_Mailer */
    private $mailer;
    /** @var \Twig_Environment */
    private $twig;
    /** @var string */
    private $emailTemplate;

    public function __construct(\Swift_Mailer $mailer, \Twig_Environment $twig, $emailTemplate)
    {
        parent::__construct($mailer, $twig, $emailTemplate);
        $this->twig = $twig;
        $this->mailer = $mailer;
        $this->emailTemplate = $emailTemplate;
    }

    // !!!!! This function will be called in loop until a timeout is obtained.  !!!!!
    public function sendNotification(Content $content, Form $form, FormSubmission $data, Field $field): void
    {
        // Custom code
        $recipients = $this->getRecipients($form, $data);
        if ($recipients) {
            $this->doSendEmail($recipients, ['content' => $content, 'form' => $form, 'data' => $data]);
        }

        parent::sendNotification($content, $form, $data, $field); // Default ez mail.
    }
}

At the time I did that there was no event to connect to to send my custom mail. Is this still the case?

If I completely disable my service, I have the same problem.