eCommerce with Hybris: Sending emails

Any eCommerce application needs to send emails once in a while, e.g. order approval, shipping notification and the like. Enabling the eEmail sending feature in a Hybris application is a multistep process that requires creating a handful of components and custom Java classes. It might look as an overhead for such a trivial task as sending an email, but if you follow the Hybris prescribed procedures, the end users will get a convenient and useful tool. Let’s discuss the advantages of emailing the Hybris-way vs. the standard JavaMail processes.

First, we’d like to create a reusable and easily configurable email template. Since each email is a regular WCMS page you can use Content Slots and Components while composing an email. Email templates can be visually edited by admin either in WCMS cockpit or in hMC. The preparation of the email templates can be assigned to the users, having particular roles, e.g. Marketing Director. The role separation and the use of components smoothly integrates into the Hybris ecosystem, and you get it for free out of the box.

Second, you can have a different template for each locale supported by your storefront. The appropriate template will be automatically chosen based on the site your customer works with. Otherwise you should manually determine which locale to use in each particular case.

With the Hybris-way you get a well-defined business process. It means that sending emails becomes a regular business process like many other workflows in Hybris, e.g. B2B Order Approval process, Order Placement process, Customer Registration email process, etc.

Last, but not least, you can manage the steps of this process in the hMC visually. Creating such visualisation manually wouldn’t be so easy to implement.

By choosing this approach you follow a common pattern that makes the code more maintainable and easy to understand for any Hybris developer. Since each functional piece is represented as a separate component you can reuse them for different business processes. There is no need to go through a multi-step preparation process for each type of the email in your application. Otherwise there would be tens of “simple” implementations that in a long run would complicate things more than if you’d be using the Hybris recommendation.

Enough of a theory, let’s implement a simple scenario – each time a customer makes a purchase over $1 million the application should send him/her a thank-you email:

The Email Process

First of all, we need to create our business process and define which steps it consists of. The process is a regular itemtype, so let’s add it to our-items.xml (Please note that it extends StoreFrontProcess class):

<itemtype code="OneMillionPurchaseProcess"
          extends="StoreFrontProcess"
          autocreate="true"
          generate="true"
          jaloclass="com.bdi.core.jalo.OneMillionPurchaseProcess">
    <description>Sends thank-you email to the customer.</description>
</itemtype>

To define process actions let’s create/resources//processes/OneMillionPurchaseProcess.xml file:

<?xml version="1.0" encoding="utf-8"?>
<process xmlns="http://www.hybris.de/xsd/processdefinition"
         start="generateOneMillionPurchaseEmail"
         name="oneMillionPurchaseProcess"
         processClass="com.project.model.OneMillionPurchaseProcessModel"
         onError="error">

    <action id="generateOneMillionPurchaseEmail" bean="generateOneMillionPurchaseEmail">
        <transition name="OK" to="sendEmail"/>
        <transition name="NOK" to="error"/>
    </action>

    <action id="sendEmail" bean="sendEmail">
        <transition name="OK" to="removeSentEmail"/>
        <transition name="NOK" to="failed"/>
    </action>

    <action id="removeSentEmail" bean="removeSentEmail">
         <transition name="OK" to="success"/>
         <transition name="NOK" to="error"/>
    </action>

    <end id="error" state="ERROR">Something went wrong.</end>
    <end id="failed" state="FAILED">Could not send email.</end>
    <end id="success" state="SUCCEEDED">Sent thank-you email.</end>

</process>

Pay attention to the following in the above process definition file:

1. The start attribute specifies which action will be executed first. It must match exactly one of your action IDs;
2. The name attribute uniquely identifies process;
3. The processClass attribute must reference our process’s model that is generated for itemtype, thus it can be found in com. .model package and class name has the same name as our process suffixed with Model.;
4. The bean attribute of the action element references an object that will generate EmailMessage for us.

In order to add this process definition to our system we need to register it as ProcessDefinitionResource in Spring’s configuration file:

<bean id="bdiCustomerServiceAccountExistsEmailProcessDefinitionResource"
      class="de.hybris.platform.processengine.definition.ProcessDefinitionResource"
      scope="tenant">
    <property name="resource" value="classpath:/project/processes/OneMillionPurchaseProcess.xml"/>
</bean>


Notice here that our bean’s type is ProcessDefinitionResource.

In the previous step we referenced generateOneMillionPurchaseEmail bean, let’s add it to our project’s Spring configuration file (/resources/-spring.xml):

<bean id="generateOneMillionPurchaseEmail"
      class="de.hybris.platform.acceleratorservices.process.email.actions.GenerateEmailAction"
      scope="tenant"
      parent="abstractAction">
    <property name="modelService" ref="modelService"/>
    <property name="frontendTemplateName" value="OneMillionPurchaseEmailTemplate"/>
    <property name="cmsEmailPageService" ref="cmsEmailPageService"/>
    <property name="contextResolutionStrategy" ref="b2bAcceleratorProcessContextResolutionStrategy"/>
    <lookup-method name="getEmailGenerationService" bean="emailGenerationService"/>
</bean>


Pay attention to the following in the above Spring configuration file :
1. The id attribute matches bean name that we referenced in OneMillionPurchaseProcess.xml;
2. The bean is an instance of Hybris built-in GenerateEmailAction class;
3. value of frontendTemplateName is unique ID of the template that must be registered in ImpEx file. We won’t cover creating template in this article because it’s nearly identical to regular WCMS page. Actually EmailPageTemplate extends regular PageTemplate, can have the same content slots as regular page can, and provides several additional attributes.

Email Context Object

The context object keeps the data that is required to generate an email. Here is the code for our context object (the code is simplified for brevity):

 
public class OneMillionPurchaseEmailContext extends AbstractEmailContext
{
    // ...

    @Override
    public void init(final BusinessProcessModel businessProcessModel, final EmailPageModel emailPageModel)
    {
        // ...
        put(FROM_EMAIL, emailPageModel.getFromEmail());
        put(FROM_DISPLAY_NAME, emailPageModel.getFromName());
        put(DISPLAY_NAME, "BDI Customer Service");
        put(EMAIL, getCustomerEmailResolutionService().getEmailForCustomer(getCustomer()));
        // ...
    }

    @Override
    protected BaseSiteModel getSite(final BusinessProcessModel businessProcessModel)
    {
        return ((StoreFrontProcessModel) businessProcessModel).getSite();
    }

    @Override
    protected CustomerModel getCustomer(final BusinessProcessModel businessProcessModel)
    {
        return ((StoreFrontCustomerProcessModel) businessProcessModel).getCustomer();
    }
}

The above Java class extends AbstractEmailContext class. The init method does most of the work here. It defines the model and its attributes that will be accessible from the email template and also sets the email address of the recipient. You can see how we use the Email Resolution Service (see the next section) to specify the recipient’s email.

The context object must be registered in Spring configuration file (/resources/-spring.xml):

<bean id="oneMillionPurchaseEmailContext"
      class="com.project.facades.process.email.context.OneMillionPurchaseEmailContext"
      parent="abstractEmailContext"
      scope="prototype">
    <property name="customerEmailResolutionService" ref="oneMillionPurchaseEmailResolutionService"/>
</bean>


Important: the property customerEmailResolutionService references the Email Resolution Service that we are about to put into play.

Email Resolution Service

The resolution service defines an algorithm of determining the email address of the recipient. Here is how it looks like in our case:

 
public class OneMillionPurchaseEmailResolutionService extends DefaultCustomerEmailResolutionService
{
    @Override
    public String getEmailForCustomer(final CustomerModel customerModel)
    {
        return customerModel.getUid();
    }
}

The above class extends DefaultCustomerEmailResolutionService and overrides the ancestor’s getEmailForCustomer implementation. The base class’s algorithm to determine email is almost the same as our custom implementation. The difference is that if it doesn’t find the customer’s email in Uid field, it uses the “default” customer address (demo@example.com) to send the email, which is not the behavior I expect to see, I’d like to receive the explicit error in that case.

You can implement any custom application logic here, for example if it’s a B2B customer, you might want to send the thank-you email to the customer’s boss – it’s completely up to you what to do here.

Now, let’s register the resolution service in the Spring configuration file:

<bean id="oneMillionPurchaseEmailResolutionService"
      class="com.bdi.core.OneMillionPurchaseEmailResolutionService"
      scope="tenant">
    <property name="configurationService" ref="configurationService"/>
</bean>


It’s pretty straightforward, isn’t it? We keep all the default configuration, adding a unique bean name and the full name of the class.

Kicking Off the Email Sending

By this moment we have all the required pieces defined. To kick off the mailing process we use BusinessProcessService, here is the code:

 
final BusinessProcessModel oneMillionPurchaseProcessModel = getBusinessProcessService().createProcess(
        ONE_MILLION_PURCHASE_PROCESS_CODE + System.currentTimeMillis(),
        ONE_MILLION_PURCHASE_PROCESS_CODE);
getBusinessProcessService().startProcess(oneMillionPurchaseProcessModel);

Here you can cast BusinessModelProcess to your custom type and provide any custom data you need within the OneMillionPurchaseEmailContext#init method. Usually this code is wrapped into a Spring’s event listener and is triggered by sending a custom event written by a developer.

Summary

Let’s recap what benefits the Hybris emailing process gives us:

- Configurable email templates. Since each email is a regular WCMS page you can use content slots and components while composing an email.
- Localized versions of the email. You can have different templates for each locale you storefront supports.
- A well-defined business process.
- Reusable components that you can use as building blocks. Since each functional piece is represented as a separate component you can reuse this components for different business processes. You don’t need to reproduce all of these steps for each type of the email you want to have in your application.

Anton Moiseev