Important

You are browsing the documentation for version 3.1 of OroCommerce, OroCRM and OroPlatform, which is no longer maintained. Read version 5.1 (the latest LTS version) of the Oro documentation to get up-to-date information.

See our Release Process documentation for more information on the currently supported and upcoming releases.

Emails

Email Templates

Communicating with customers is an important part of every business. In OroPlatform, an email address is represented by the Oro\Bundle\EmailBundle\Entity\EmailAddress class.

When creating emails, your may reuse the text that is frequently sent for a certain purpose. For this, they can create templates and reuse them as needed. Besides letting the users create and manage templates through the UI, every bundle can provide their own email templates.

Providing e-mail templates is nothing more than creating Twig templates for the desired format (namely HTML or plaintext) in which you can use some pre-defined placeholders to define template metadata. Then you create a data fixture that implements the AbstractEmailFixture class. This class provides a getEmailsDir() method which should return the path of the directory that contains your templates:

 1// src/Acme/Bundle/DemoBundle/DataFixtures/ORM/EmailTemplatesFixture.php
 2namespace Acme\Bundle\DemoBundle\DataFixtures\ORM;
 3
 4use Oro\Bundle\EmailBundle\Migrations\Data\ORM\AbstractEmailFixture;
 5
 6class EmailTemplatesFixture extends AbstractEmailFixture
 7{
 8    public function getEmailsDir()
 9    {
10        return $this->container
11            ->get('kernel')
12            ->locateResource('@AcmeDemoBundle/Resources/emails');
13    }
14}

The format of the email template is determined based on the filename extension you use:

Extension

E-Mail Format

.html.twig, .html

HTML

.txt.twig, .txt

Plaintext

HTML is used as the default format if none could be derived from the filename extension.

Template Metadata

Additionally to the e-mail body, the template must contain some special parameters to add some metadata to the template:

Parameter

Mandatory

Description

@entityName

yes

The fully-qualified class name of the e-mail owner entity (for example Acme\Bundle\DemoBundle\Entity\Applicant).

@subject

yes

The e-mail subject.

@name

no

The template name that is visible in the UI (the filename without the extension is used when this parameter is not set).

@isSystem

no

Set it to 1 to indicate that this is a system template.

@isEditable

no

If set to 1 and @isSystem is 1 too, the template can be edited in the user interface.

Note

The details on template variables are described in details in the relevant documentation .

Sending Emails

Create an Email

An email that is created and sent by OroPlatform is centered around the Oro\Bundle\EmailBundle\Form\Model\Email model class which reflects all the properties of an email.

There are two ways to create a new email:

  1. Manually create an email

  2. Use the email builder class

Create an Email Manually

You can manually create an email by creating a new instance of the Email model class and call the setter methods for all the properties you want to be set:

 1// src/Acme/DemoBundle/Controller/EmailController.php
 2namespace Acme\DemoBundle\Controller;
 3
 4use Oro\Bundle\EmailBundle\Form\Model\Email;
 5use Oro\Bundle\EmailBundle\Form\Model\EmailAttachment;
 6use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 7
 8class EmailController extends Controller
 9{
10    public function sendMailAction()
11    {
12        $email = new Email();
13
14        // the sender
15        $email->setFrom('chris@example.com');
16
17        // recipient(s)
18        $email->setTo(['alice@example.com', 'bob@example.com']);
19
20        // CC recipient(s)
21        $email->setCc(['dave@example.com', 'eric@example.com']);
22
23        // BCC recipient(s)
24        $email->setBcc(['ryan@example.com', 'jonathan@example.com']);
25
26        // the subject
27        $email->setSubject(...);
28
29        // a template to create the email body, the passed template
30        // must be an instance of Oro\Bundle\EmailBundle\Entity\EmailTemplate
31        $email->setTemplate(...);
32
33        // a context that will be passed to the template set with setTemplate()
34        $email->setContexts([...]);
35
36        // the email type (either html or text)
37        $email->setType(...);
38
39        // as an alternative to using a template (see above) you can also
40        // directly set the email body
41        $email->setBody(...);
42
43        // email attachments (instances of  Oro\Bundle\EmailBundle\Form\Model\EmailAttachment
44        $email->addAttachment($attachment);
45
46        // ...
47    }
48}

The EmailModelBuilder Class

An alternative approach to manually creating Email models is to use the EmailModelBuilder helper class which offers several methods to create new emails based on existing data:

createEmailModel

Create a new email or add missing data to an existing email.

createReplyEmailModel

Create an email that is a response to an existing email.

createReplyAllEmailModel

Create an email that is a response to all recipients and the sender of an existing email.

createForwardEmailModel

Create a new email that forwards an existing email.

After emails have been processed (see below), they will be persisted to the database. You can create an email model based on such a persisted entity, by using the useful EmailModelBuilder helper class:

 1// src/Acme/DemoBundle/Controller/EmailController.php
 2namespace Acme\DemoBundle\Controller;
 3
 4use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 5
 6class EmailController extends Controller
 7{
 8    public function sendMailAction()
 9    {
10        // ...
11    }
12}

Send the Email

When you created your email model, you can use the integrated mailer processor which is responsible for sending the email and persisting it to the database (which also creates the needed contexts to customers, users, and so on):

 1// src/Acme/DemoBundle/Controller/EmailController.php
 2namespace Acme\DemoBundle\Controller;
 3
 4// ...
 5
 6class EmailController extends Controller
 7{
 8    public function sendMailAction()
 9    {
10        // ...
11        $email = ...;
12
13        $processor = $this->get('oro_email.mailer.processor');
14        $processor->process($email);
15    }
16}

When calling the Oro\Bundle\EmailBundle\Mailer\Processor::process the mailer processor performs the following steps:

  1. It creates a new \Swift_Message instance and populate it with the data from your Email object.

  2. If you did not pass an EmailOrigin object which should be used to associate the mail in the user interface with, the processor will create on based on the sender address and the selected organization.

  3. The email will be sent based on your application’s SwiftMailer configuration (if the current user configured a custom SMTP server in their settings, the configured server will be used instead).

  4. The sent email is persisted to the database storing all necessary information to be able to view it again in the future through the user interface.

  5. All the persisted data is returned as an instance of the Oro\EmailBundle\Entity\EmailUser.

Receive Email Notifications

Sometimes you want to receive emails when entities of a particular class are written to the database. To achieve this OroPlatform comes with the NotificationBundle. This bundle registers an event listener that is executed whenever a Doctrine entity is created, updated or removed.

To be notified by such an event, you have to create an Oro\Bundle\NotificationBundle\Entity\EmailNotification that contains all the necessary information. The easiest way to register a new EmailNotification is to create data fixtures:

 1// src/Acme/DemoBundle/Migrations/Data/ORM/CreateCommentNotification.php
 2namespace Acme\DemoBundle\Migrations\Data\ORM;
 3
 4use Doctrine\Common\DataFixtures\AbstractFixture;
 5use Doctrine\Common\Persistence\ObjectManager;
 6use Oro\Bundle\NotificationBundle\Entity\EmailNotification;
 7use Oro\Bundle\NotificationBundle\Entity\RecipientList;
 8
 9class CreateCommentNotification extends AbstractFixture
10{
11    public function load(ObjectManager $manager)
12    {
13        $notification = new EmailNotification();
14
15        // the FQCN of the entity
16        $notification->setEntityName('Acme\DemoBundle\Entity\Comment');
17
18        // the event to be notified of, pre-defined event names are
19        // oro.notification.event.entity_post_update, oro.notification.event.entity_post_remove
20        // and oro.notification.event.entity_post_persist
21        $eventRepository = $manager->getRepository('Oro\Bundle\NotificationBundle\Entity\Event');
22        $event = $eventRepository->findOneByName('oro.notification.event.entity_post_persist');
23        $notification->setEvent($event);
24
25        // recipients must be an instance of Oro\Bundle\NotificationBundle\Entity\RecipientList
26        // which represents a collection of recipients, each recipient can either be an email
27        // address, a User object, or a Group object
28        $recipients = new RecipientList();
29        $groupRepository = $manager->getRepository('Oro\Bundle\UserBundle\Entity\Group');
30        $group = $groupRepository->findOneByName('Moderator');
31        $recipients->addGroup($group);
32
33        $notification->setRecipientList($recipients);
34
35        // the EmailTemplate that is used to render the email body
36        $emailTemplateRepository = $manager->getRepository('Oro\Bundle\EmailBundle\Entity\EmailTemplate');
37        $template = $emailTemplateRepository->findByName('comment_created_notification');
38        $notification->setTemplate($template);
39
40        $manager->persist($notification);
41        $manager->flush();
42    }
43}

Email Address Owners

Each email address is owned by exactly one entity. In OroPlatform, User entities and Contact entities can be owners of an email address. Supposed you want to use the CRM to keep track of all people that apply to your company. You will then probably create an Applicant entity and want to associate an email address to each of them. To let your own entities own an email address, you have to follow a few steps:

  1. Create an entity that is responsible for storing the email address.

  2. Create a new owner of an email address.

  3. Publish a provider that makes it possible to search for the owner of a particular email address.

  4. Update the database schema and clear the cache.

Implement the Email Entity

Each entity owning an email address must have its own email entity that implements the Oro\Bundle\EmailBundle\Entity\EmailInterface. This interface defines four methods:

getEmailField()

Returns the name of the database table column that holds the actual email address.

getId()

A unique identifier to find a particular email address entity in the database.

getEmail()

This method returns the actual email address.

getEmailOwner()

The entity that owns a certain email address.

Sample Email entity:

 1// src/Acme/Bundle/DemoBundle/Entity/ApplicantEmail.php
 2namespace Acme\Bundle\DemoBundle\Entity;
 3
 4use Doctrine\ORM\Mapping as ORM;
 5use Oro\Bundle\EmailBundle\Entity\EmailInterface;
 6
 7/**
 8 * @ORM\Entity()
 9 */
10class ApplicantEmail implements EmailInterface
11{
12    /**
13     * @ORM\Id
14     * @ORM\Column(type="integer", name="id")
15     * @ORM\GeneratedValue(strategy="AUTO")
16     */
17    private $id;
18
19    /**
20     * @ORM\Column(type="string", length=255)
21     */
22    private $email;
23
24    /**
25     * @ORM\ManyToOne(targetEntity="Applicant", inversedBy="emails")
26     */
27    private $applicant;
28
29    public function getEmailField()
30    {
31        return 'email';
32    }
33
34    public function getId()
35    {
36        return $this->id;
37    }
38
39    public function getEmail()
40    {
41        return $this->email;
42    }
43
44    public function getEmailOwner()
45    {
46        return $this->applicant;
47    }
48}

An Email Owner

The entity that is the owner of the email address has to implement the Oro\Bundle\EmailBundle\Entity\EmailOwnerInterface:

getClass()

The fully qualified class name of the entity.

getEmailFields()

A list of properties of the entity that represent valid email addresses. You can specify more than one property here.

getId()

A unique identifier to identify a particular owner entity.

getFirstName()

The first name of the email address owner. It will be used to build proper recipient names when sending emails.

getLastName()

The last name of the email address owner. It will be used to build proper recipient names when sending emails.

For Applicant entity, the implementation should be similar to the following:

 1// src/Acme/Bundle/DemoBundle/Entity/Applicant.php
 2namespace Acme\Bundle\DemoBundle\Entity;
 3
 4use Doctrine\ORM\Mapping as ORM;
 5use Oro\Bundle\EmailBundle\Entity\EmailOwnerInterface;
 6
 7/**
 8 * @ORM\Entity()
 9 */
10class Applicant implements EmailOwnerInterface
11{
12    /**
13     * @ORM\Id
14     * @ORM\Column(type="integer", name="id")
15     * @ORM\GeneratedValue(strategy="AUTO")
16     */
17    private $id;
18
19    /**
20     * @ORM\OneToMany(targetEntity="ApplicantEmail", mappedBy="applicant", orphanRemoval=true, cascade={"persist"})
21     */
22    private $emails;
23
24    /**
25     * @ORM\Column(type="string", length=255)
26     */
27    private $firstName;
28
29    /**
30     * @ORM\Column(type="string", length=255)
31     */
32    private $lastName;
33
34    public function getClass()
35    {
36        return 'Acme\Bundle\DemoBundle\Entity\Applicant';
37    }
38
39    public function getEmailFields()
40    {
41        return ['email'];
42    }
43
44    public function getId()
45    {
46        return $this->id;
47    }
48
49    public function getEmails()
50    {
51        return $this->emails;
52    }
53
54    public function getFirstName()
55    {
56        return $this->firstName;
57    }
58
59    public function getLastName()
60    {
61        return $this->lastName;
62    }
63}

Implement EmailOwnerProviderInterface

In order to make the application able to find the owner of a certain email address, you have to create a provider that implements the Oro\Bundle\EmailBundle\Entity\Provider\EmailOwnerProviderInterface. This interface contains two methods:

getEmailOwnerClass()

This is the class of the email owner entity (the class implementing the EmailOwnerInterface which is the Applicant class in the example above).

findEmailOwner()

Returns an entity that is the owner of an email address or null if no such owner exists. The returned object must be an instance of the class specified by getEmailOwnerClass().

The provider class should then look like this:

 1// src/Acme/Bundle/DemoBundle/Entity/Provider/EmailOwnerProvider.php
 2namespace Acme\Bundle\DemoBundle\Entity\Provider;
 3
 4use Acme\Bundle\DemoBundle\Entity\ApplicantEmail;
 5use Doctrine\ORM\EntityManager;
 6use Oro\Bundle\EmailBundle\Entity\Provider\EmailOwnerProviderInterface;
 7
 8class EmailOwnerProvider implements EmailOwnerProviderInterface
 9{
10    public function getEmailOwnerClass()
11    {
12        return 'Acme\Bundle\DemoBundle\Entity\Applicant';
13    }
14
15    public function findEmailOwner(EntityManager $em, $email)
16    {
17        $applicantEmailRepo = $em->getRepository('AcmeDemoBundle:ApplicantEmail');
18        /** @var ApplicantEmail $applicantEmail */
19        $applicantEmail = $applicantEmailRepo->findOneBy(['email' => $email]);
20
21        if (null !== $applicantEmail) {
22            return $applicantEmail->getEmailOwner();
23        }
24
25        return null;
26    }
27}

You then need to create a service for the new EmailOwnerProvider class and tag it with the oro_email.owner.provider tag to make the application aware of the new email provider:

1# src/Acme/Bundle/DemoBundle/Resources/config/services.yml
2services:
3    acme_demo.provider.email_owner_provider:
4        class: Acme\Bundle\DemoBundle\Entity\Provider\EmailOwnerProvider
5        tags:
6            - { name: oro_email.owner.provider, order: 3 }

Refresh the Database Schema

Finally, you have to update the database schema and clear the application cache:

# update the database schema
$ php bin/console doctrine:schema:update --force

# warm up the application cache
$ php bin/console cache:warmup