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 |
|
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 |
---|---|---|
|
yes |
The fully-qualified class name of the e-mail owner entity (for example
|
|
yes |
The e-mail subject. |
|
no |
The template name that is visible in the UI (the filename without the extension is used when this parameter is not set). |
|
no |
Set it to |
|
no |
If set to |
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:
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:
It creates a new
\Swift_Message
instance and populate it with the data from yourEmail
object.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.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).
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.
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:
Create an entity that is responsible for storing the email address.
Publish a provider that makes it possible to search for the owner of a particular email address.
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 theApplicant
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 bygetEmailOwnerClass()
.
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