Tutorial - Sending a Mail

The following tutorial represents a real-world scenario for the customer registration.

A Customer goes through the registration process in your frontend (Yves) and all customer information is sent to Zed. Zed uses the information to register the customer. Once the registration is completed, the customer will receive a confirmation email.

In the model which handles the registration, you will then do something similar to this:

<?php
namespace Pyz\Zed\Customer\Business\Model\Customer;

    ...
    
    // customer registration code
    $this->sendMail($customerTransfer);
    
    ...
    
    protected function sendMail(CustomerTransfer $customerTransfer) 
    {
        // Create a MailTransfer instance which is 
        // used for further processing
        $mailTransfer = new MailTransfer();
        
        // Set the mail type which is used for the 
        // internal mapping e.g. which mail provider
        // should send this mail
        $mailTransfer->setType(CustomerRegistrationMailTypePlugin::MAIL_TYPE);
        
        // Set the CustomerTransfer to the MailTransfer
        // this can be any Transfer object which is 
        // needed in the Mail
        $mailTransfer->setCustomer($customerTransfer);
        
        // Set the LocaleTransfer which should be used 
        // for e.g. translation inside your templates
        $mailTransfer->setLocale($customerTransfer->getLocale());

        // Trigger the mail facade to handle the mail
        $this->mailFacade->handleMail($mailTransfer);
    }

...

All MailTransfers need at least to know which mail type (nothing more than a string) should be used for further internal processing.

A minimalistic example could look like this:

<?php
...
protected function sendMail() 
{
    $mailTransfer = new MailTransfer();
    $mailTransfer->setType(YourMailTypePlugin::MAIL_TYPE);
    $this->mailFacade->handleMail($mailTransfer);
}

Now let’s have a detailed look into the MailType plugin used for this example:

<?php
namespace Pyz\Zed\Customer\Communication\Plugin\Mail;

use Spryker\Zed\Kernel\Communication\AbstractPlugin;
use Spryker\Zed\Mail\Business\Model\Mail\Builder\MailBuilderInterface;
use Spryker\Zed\Mail\Dependency\Plugin\MailTypeInterface;

class CustomerRegistrationMailTypePlugin extends AbstractPlugin implements MailTypePluginInterface
{

    const MAIL_TYPE = 'customer registration mail';
    
    /**
     * @return string
     */
    public function getName()
    {
        return static::MAIL_TYPE;
    }
    
    /**
     * @param \Spryker\Zed\Mail\Business\Model\Mail\Builder\MailBuilderInterface $mailBuilder
     *
     * @return void
     */
    public function build(MailBuilderInterface $mailBuilder)
    {
        $this
            ->setSubject($mailBuilder)
            ->setHtmlTemplate($mailBuilder)
            ->setTextTemplate($mailBuilder)
            ->setSender($mailBuilder)
            ->setRecipient($mailBuilder);
    }
    
    ...
    
    protected function setRecipient(MailBuilderInterface $mailBuilder)
    {
        // Get the CusomterTransfer which was added
        // to the MailTransfer in the sendMail() method
        // of the Customer model
        $customerTransfer = $mailBuilder->getMailTransfer()->getCustomer();
        
        // Use the customer information to add the needed
        // recipient information through the MailBuilder
        // to the MailTransfer
        $mailBuilder->addRecipient(
            $customerTransfer->getEmail(),
            $customerTransfer->getFirstName() . ' ' . $customerTransfer->getLastName()
        );
    }
}

The Mail module's default MailBuilder is already pre-defined to build the MailTransfer. MailBuilder internally adds a new MailRecipientTransfer with the passed information, email and name.

When plugin is created, it should be registered it in MailDependencyProvider:

<?php
        ...
        $container->extend(self::MAIL_TYPE_COLLECTION, function (MailTypeCollectionAddInterface $mailCollection) {
            $mailCollection
                ->add(new CustomerRegistrationMailTypePlugin());

            return $mailCollection
        });
        ...
 ?>

See HowTo - Create and Register a MailTypePlugin for more information on creating a MailTypePlugin. The default MailBuilder also has access to the glossary with the setSubject() method. This is used for translations as follows:

<?php
namespace Pyz\Zed\Customer\Communication\Plugin\Mail;

use Spryker\Zed\Kernel\Communication\AbstractPlugin;
use Spryker\Zed\Mail\Business\Model\Mail\Builder\MailBuilderInterface;
use Spryker\Zed\Mail\Dependency\Plugin\MailTypeInterface;

class CustomerRegistrationMailTypePlugin extends AbstractPlugin implements MailTypePluginInterface
{
    ...
    protected function setSubject(MailBuilderInterface $mailBuilder)
    {
        $mailBuilder->setSubject('mail.customer.registration.subject');
    }
    ...
}

A string is used as a key of the translation. The MailBuilder internally does the translation through GlossaryFacade:

<?php
namespace Spryker\Zed\Mail\Business\Model\Mail\Builder;
    
    ...
    
    protected function setSubject($subject, array $data = [])
    {
        $subject = $this->translate($subject, $data);
        
        $this->getMailTransfer()->setSubject($subject);
        
        return $this;
    }
    ...
    
    protected function translate($keyName, array $data = [])
    {
        $localeTransfer = $this->getLocaleTransfer();

        if ($this->glossaryFacade->hasTranslation($keyName, $localeTransfer)) {
            $keyName = $this->glossaryFacade->translate($keyName, $data, $localeTransfer);
        }

        return $keyName;
    }
}

As you can see above, you can also translate with placeholder. For the mail.order.shipped.subject key we have Your order {orderReference} is on its way as a translation.

In your MailType plugin you can use the orderReference from the given OrderTransfer within the subject:

<?php
...
protected function setSubject(MailBuilderInterface $mailBuilder)
{
    $orderTransfer = $mailBuilder->getMailTransfer()->getOrder();
    
    $mailBuilder->setSubject(
        'mail.order.shipped.subject',
        [
            '{orderReference}' => $orderTransfer->getOrderReference()
        ]
    );
}
...
}

Templates

Usually, you will have a *.twig file which contains the template you want to use for mail. Set the template which should be used in your MailType plugin:

<?php
...
protected function setTextTemplate(MailBuilderInterface $mailBuilder)
{
    $mailBuilder->setTextTemplate('customer/mail/customer_registration.text.twig');
}
...
}

The provider determines the template’s final look. It can contain plain text, HTML, etc. For example, you can even have a template which generates JSON:

{
    ...
    customer: "{{ mail.customer.firstName }} {{ mail.customer.lastName }}",
    ...
}

In our example we have a plain text template with:

{{ 'mail.customer.registration.text' | trans }}

The templates must be placed within the module's Presentation layer. In our example src/Pyz/Zed/Customer/Presentation/Mail/customer_registration.text.twig. You can use the same trans filter as used with Yves and Zed templates.

TwigRenderer is the default renderer, but you can add your own Renderer by implementing the RendererInterface.

We also provide a basic layout file to where you can inject concrete content files. If you want to build your own layout, you need to have the following in your template:

{% for template in mail.templates %}
    {% if not template.isHtml %}
        {% include "@" ~ template.name with {mail: mail} %}
    {% endif %}
{% endfor %}

This one is used for plain text messages, and templates can also be used to generate JSON or a query strings like customer={{ mail.customer.firstName }}&orderReference={{ mail.order.orderReference }} - it’s up to your provider to decide what you need to render.

For HTML messages you need to have this in your layout file:

{% for template in mail.templates %}
    {% if template.isHtml %}
        {% include "@" ~ template.name with {mail: mail} %}
    {% endif %}
{% endfor %}

Once you have completed the steps below, call MailFacade::handleMail() to activate the mail functionality.

 

See also:

HowTo - Create and Register a MailTypePlugin

HowTo - Create and Register a Mail Provider

 

Last review date: Jan. 3rd, 2018