ssossossosso
Documentation Home »The Oro Book »Working with E-Mails
1.10 version

Working with E-Mails

Communicating with customers is an important part of every business. In OroPlatform, an e-mail address is represented by the EmailAddress class.

E-Mail Templates

When creating e-mails, your users often want to reuse texts they have written some time before 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 e-mail 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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// src/Acme/Bundle/DemoBundle/DataFixtures/ORM/EmailTemplatesFixture.php
namespace Acme\Bundle\DemoBundle\DataFixtures\ORM;

use Oro\Bundle\EmailBundle\Migrations\Data\ORM\AbstractEmailFixture;

class EmailTemplatesFixture extends AbstractEmailFixture
{
    public function getEmailsDir()
    {
        return $this->container
            ->get('kernel')
            ->locateResource('@AcmeDemoBundle/Resources/emails');
    }
}

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.

Template Variables

E-Mail Address Owners

Each e-mail address is owned by exactly one entity. In OroPlatform, User entities and Contact entities can be owners of an e-mail 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 e-mail address to each of them. To let your own entities own an e-mail address, you have to follow a few steps:

  1. Create an entity that is responsible for storing the e-mail address.
  2. Create a new owner of an e-mail address.
  3. Publish a provider that makes it possible to search for the owner of a particular e-mail address.
  4. Update the database schema and clear the cache.

Implementing the E-Mail Entity

Each entity owning an e-mail address must have its own e-mail entity that implements the EmailInterface. This interface defines four methods:

getEmailField()
Returns the name of the database table column that holds the actual e-mail address.
getId()
A unique identifier to find a particular e-mail address entity in the database.
getEmail()
This method returns the actual e-mail address.
getEmailOwner()
The entity that owns a certain e-mail address.

The Email entity then looks something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// src/Acme/Bundle/DemoBundle/Entity/ApplicantEmail.php
namespace Acme\Bundle\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Oro\Bundle\EmailBundle\Entity\EmailInterface;

/**
 * @ORM\Entity()
 */
class ApplicantEmail implements EmailInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer", name="id")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $email;

    /**
     * @ORM\ManyToOne(targetEntity="Applicant", inversedBy="emails")
     */
    private $applicant;

    public function getEmailField()
    {
        return 'email';
    }

    public function getId()
    {
        return $this->id;
    }

    public function getEmail()
    {
        return $this->email;
    }

    public function getEmailOwner()
    {
        return $this->applicant;
    }
}

The E-Mail Owner

The entity that is the owner of the e-mail address has to implement the EmailOwnerInterface:

getClass()
The fully qualified class name of the entity.
getEmailFields()
A list of properties of the entity that represent valid e-mail 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 e-mail address owner. It will be used to build proper recipient names when sending e-mails.
getLastName()
The last name of the e-mail address owner. It will be used to build proper recipient names when sending e-mails.

For your Applicant entity, the implementation should now look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// src/Acme/Bundle/DemoBundle/Entity/Applicant.php
namespace Acme\Bundle\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Oro\Bundle\EmailBundle\Entity\EmailOwnerInterface;

/**
 * @ORM\Entity()
 */
class Applicant implements EmailOwnerInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer", name="id")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="ApplicantEmail", mappedBy="applicant", orphanRemoval=true, cascade={"persist"})
     */
    private $emails;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $firstName;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $lastName;

    public function getClass()
    {
        return 'Acme\Bundle\DemoBundle\Entity\Applicant';
    }

    public function getEmailFields()
    {
        return array('email');
    }

    public function getId()
    {
        return $this->id;
    }

    public function getEmails()
    {
        return $this->emails;
    }

    public function getFirstName()
    {
        return $this->firstName;
    }

    public function getLastName()
    {
        return $this->lastName;
    }
}

Implementing the EmailOwnerProviderInterface

In order to make the application able to find the owner of a certain e-mail address, you have to create a provider that implements the EmailOwnerProviderInterface. This interface contains two methods:

getEmailOwnerClass()
This is the class of the e-mail 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 e-mail 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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// src/Acme/Bundle/DemoBundle/Entity/Provider/EmailOwnerProvider.php
namespace Acme\Bundle\DemoBundle\Entity\Provider;

use Acme\Bundle\DemoBundle\Entity\ApplicantEmail;
use Doctrine\ORM\EntityManager;
use Oro\Bundle\EmailBundle\Entity\Provider\EmailOwnerProviderInterface;

class EmailOwnerProvider implements EmailOwnerProviderInterface
{
    public function getEmailOwnerClass()
    {
        return 'Acme\Bundle\DemoBundle\Entity\Applicant';
    }

    public function findEmailOwner(EntityManager $em, $email)
    {
        $applicantEmailRepo = $em->getRepository('AcmeDemoBundle:ApplicantEmail');
        /** @var ApplicantEmail $applicantEmail */
        $applicantEmail = $applicantEmailRepo->findOneBy(array('email' => $email));

        if (null !== $applicantEmail) {
            return $applicantEmail->getEmailOwner();
        }

        return null;
    }
}

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 e-mail provider:

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

Refreshing the Database Schema

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

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

# warm up the application cache
$ php app/console cache:warmup
Browse maintained versions:
current1.102.02.32.4