Writing custom email and sending from Hybris is a lengthy process in SAP Hybris. This is because there are multiple things we need to code to send custom email. In this post, I will walk you through how to send custom email from SAP Hybris.

If you are looking for a shorter way to send custom email in Hybris, without customizations, view my other post: “How to send custom email in Hybris (shorter way!)

Additionally, to make this walkthrough concrete, let’s assume that our business requirement is that we have gift cards in our store and whenever a gift card is purchased, we activate the gift card and send out an activation email to the customer. Therefore, we will name our email “GiftCardActivationEmail”.

To create your own custom email, the following needs to be created:

  1. Create process item type that will extend one of the OOTB process types
  2. Create a process
  3. Create an action that the process will start
  4. Create an event
  5. Create an event listener
  6. Create a context file
  7. Create a subject velocity file
  8. Create a body velocity file
  9. Create a message properties file
  10. Create an impex to create the pageTemplates and pages
  11. Testing the email

Create a process item type

Firstly, we will create the process itemType. In our core items.xml file, add the following code:

<itemtype code="GiftCardActivationEmailProcess" autocreate="true" generate="true" jaloclass="com.mySite.core.jalo.custom.GiftCardActivationEmailProcess" extends="StorefrontCustomerProcess">
    <attributes>
	<attribute type="AbstractOrderEntry" qualifier="orderEntry" >				 
            <description>OrderEntry of the gift card</description>
	    <persistence type="property" />
        </attribute>
    </attributes>
</itemtype>

Here, we have created an itemType called “GiftCardActivationEmailProcess” which extends StorefrontCustomerProcess. Also, we added the property AbstractOrderEntry. This is assuming that the gift card purchased is one of the order entries.

After adding the itemType, run ant clean from platform directory. This will create the model class of this item for us to use later on.

Create a process file

Now, we need to create a process file that will be started when we trigger the gift card activation event. In our core’s spring.xml file, create the following bean definition for the process:

<bean id="giftCardActivationEmailProcessDefinitionResource" class="de.hybris.platform.processengine.definition.ProcessDefinitionResource">
	<property name="resource" value="classpath:/<my-core>/processes/giftCardActivationEmailProcess.xml" />
</bean>

Now, we need to define the xml process file that this bean is using. In your core’s process folder under resources, create the following file:

<?xml version="1.0" encoding="utf-8"?>
<process xmlns="http://www.hybris.de/xsd/processdefinition" start="generateGiftCardActivationEmail" name="giftCardActivationEmailProcess"
		processClass="com.mySite.core.model.custom.GiftCardActivationEmailProcessModel" onError="error">

	<action id="generateGiftCardActivationEmail" bean="generateGiftCardActivationEmail">
		<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 gift card activation email.</end>
	<end id="success" state="SUCCEEDED">Sent gift card activation email.</end>

</process>

Over here, we have used our itemType’s model class as the processClass. This is a simple process, in which we start our generateGiftCardActivationEmail action and if that action is OK, then we attempt to send the email.

Creating the action

Since our action uses this bean, we will create this bean in our core’s spring.xml file. The bean definition is as follows:

<bean id="generateGiftCardActivationEmail" parent="abstractGenerateEmailAction">
	<property name="frontendTemplateName" value="GiftCardActivationEmailTemplate" />
</bean>

Here, we are extending from abstractGenerateEmailAction and overriding the property “frontendTemplateName”.

Create the event class

We need to create an event class which we will trigger when we need to send the email. Create the following class inn your core:

package com.mySite.core.event;

import de.hybris.platform.basecommerce.model.site.BaseSiteModel;
import de.hybris.platform.commerceservices.event.AbstractCommerceUserEvent;
import de.hybris.platform.core.model.c2l.CurrencyModel;
import de.hybris.platform.core.model.order.AbstractOrderEntryModel;
import de.hybris.platform.store.BaseStoreModel;

public class GiftCardActivationEvent extends AbstractCommerceUserEvent<BaseSiteModel> {

    private AbstractOrderEntryModel orderEntryModel;

    public GiftCardActivationEvent(final AbstractOrderEntryModel orderEntryModel, final BaseStoreModel baseStore,
                                   final BaseSiteModel site, final CurrencyModel currency) {
        super();

        this.orderEntryModel = orderEntryModel;
        setBaseStore(baseStore);
        setSite(site);
        setCurrency(currency);
    }

    public AbstractOrderEntryModel getOrderEntryModel() {
        return orderEntryModel;
    }
}

Create the event listener class

Now we need to create the event listener class which will listen to our event and start our process for sending out the email.

Define the following bean definition in your core’s spring.xml file:

<bean id="giftAcrdActivationEventListener" class="com.mySite.core.event.GiftCardActivationEventListener" parent="abstractSiteEventListener">
	<property name="modelService" ref="modelService" />
	<property name="businessProcessService" ref="businessProcessService" />
	<property name="processCodeGenerator" ref="processCodeGenerator"/>
</bean>

Now, create the class GiftCardActivationEventListener that this bean defined:

package com.mySite.core.event;

import com.mySite.core.model.custom.GiftCardActivationEmailProcessModel;
import de.hybris.platform.basecommerce.model.site.BaseSiteModel;
import de.hybris.platform.commerceservices.enums.SiteChannel;
import de.hybris.platform.commerceservices.event.AbstractSiteEventListener;
import de.hybris.platform.processengine.BusinessProcessService;
import de.hybris.platform.servicelayer.keygenerator.KeyGenerator;
import de.hybris.platform.servicelayer.model.ModelService;
import de.hybris.platform.servicelayer.util.ServicesUtil;
import org.springframework.beans.factory.annotation.Required;

public class GiftCardActivationEventListener extends AbstractSiteEventListener<GiftCardActivationEvent>
{

	private ModelService modelService;
	private BusinessProcessService businessProcessService;
	private KeyGenerator processCodeGenerator;


	protected BusinessProcessService getBusinessProcessService()
	{
		return businessProcessService;
	}

	@Required
	public void setBusinessProcessService(final BusinessProcessService businessProcessService)
	{
		this.businessProcessService = businessProcessService;
	}

	/**
	 * @return the modelService
	 */
	protected ModelService getModelService()
	{
		return modelService;
	}

	/**
	 * @param modelService
	 *           the modelService to set
	 */
	@Required
	public void setModelService(final ModelService modelService)
	{
		this.modelService = modelService;
	}

	@Override
	protected void onSiteEvent(final GiftCardActivationEvent event)
	{
		final GiftCardActivationEmailProcessModel giftCardActivationEmailProcessModel = (GiftCardActivationEmailProcessModel) getBusinessProcessService()
				.createProcess("generateGiftCardActivation-" + event.getCustomer().getUid() + "-" + processCodeGenerator.generate().toString(),
						"giftCardActivationEmailProcess");
		giftCardActivationEmailProcessModel.setSite(event.getSite());
		giftCardActivationEmailProcessModel.setCustomer(event.getCustomer());
		giftCardActivationEmailProcessModel.setLanguage(event.getLanguage());
		giftCardActivationEmailProcessModel.setCurrency(event.getCurrency());
		giftCardActivationEmailProcessModel.setStore(event.getBaseStore());
		giftCardActivationEmailProcessModel.setOrderEntry(event.getOrderEntryModel());
		getModelService().save(giftCardActivationEmailProcessModel);
		getBusinessProcessService().startProcess(giftCardActivationEmailProcessModel);
	}

	@Override
	protected boolean shouldHandleEvent(final GiftCardActivationEvent event)
	{
		final BaseSiteModel site = event.getSite();
		ServicesUtil.validateParameterNotNullStandardMessage("event.site", site);
		return SiteChannel.B2C.equals(site.getChannel());
	}
	
	public KeyGenerator getProcessCodeGenerator() {
		return processCodeGenerator;
	}
	
	@Required
	public void setProcessCodeGenerator(KeyGenerator processCodeGenerator) {
		this.processCodeGenerator = processCodeGenerator;
	}
}

In this listener class, we are populating the right fields of our process and starting it.

Create the context class

The context class in SAP Hybris is used to provide the velocity email template with dynamic data which the email template can use.

In your facade’s spring.xml file, create the following bean definition:

<bean id="giftCardActivationEmailContext" class="com.mySite.facades.process.email.context.GiftCardActivationEmailContext" parent="abstractEmailContext" scope="prototype">
</bean>

Now, create the context class that we defined:

package com.mySite.facades.process.email.context;

import com.mySite.core.model.custom.GiftCardActivationEmailProcessModel;
import de.hybris.platform.acceleratorservices.model.cms2.pages.EmailPageModel;
import de.hybris.platform.acceleratorservices.process.email.context.AbstractEmailContext;
import de.hybris.platform.basecommerce.model.site.BaseSiteModel;
import de.hybris.platform.core.model.c2l.LanguageModel;
import de.hybris.platform.core.model.user.CustomerModel;

import java.text.DecimalFormat;
import java.util.Collection;


public class GiftCardActivationEmailContext extends AbstractEmailContext<GiftCardActivationEmailProcessModel> {
	
	@Override
	public void init(final GiftCardActivationEmailProcessModel giftCardActivationEmailProcessModel, final EmailPageModel emailPageModel)
	{
		super.init(giftCardActivationEmailProcessModel, emailPageModel);
		
		put(EMAIL, getCustomerEmailResolutionService().getEmailForCustomer(getCustomer(giftCardActivationEmailProcessModel)));
		put(DISPLAY_NAME, getCustomer(giftCardActivationEmailProcessModel).getDisplayName());
		
	}

	@Override
	protected BaseSiteModel getSite(final GiftCardActivationEmailProcessModel giftCardActivationEmailProcessModel)
	{
		return giftCardActivationEmailProcessModel.getOrderEntry().getOrder().getSite();
	}

	@Override
	protected CustomerModel getCustomer(final GiftCardActivationEmailProcessModel giftCardActivationEmailProcessModel)
	{
		return (CustomerModel) giftCardActivationEmailProcessModel.getOrderEntry().getOrder().getUser();
	}

	@Override
	protected LanguageModel getEmailLanguage(final GiftCardActivationEmailProcessModel giftCardActivationEmailProcessModel)
	{
		return giftCardActivationEmailProcessModel.getOrderEntry().getOrder().getUser().getSessionLanguage();
	}

}

In this class, we are only populating email and display name because these are the required attributes. You can send more fields similarly to the velocity template from the context class.

Create the subject velocity file

Create a subject velocity file in <your-core>/import/emails/email-giftCardActivationSubject.vm. The file can be as simple as follows:

Your Gift Card has been activated!

Create the body velocity file

Create the subject file in <your-core>/import/emails/email-giftCardActivationBody.vm. I will not be posting the body file here, but the content of this file dependent on your use-case.

Create the message properties file

The name of this file should match the name that’s in the first line of your body’s velocity file. Assuming your first line of your body velocity file has the following content:

## messageSource=classpath:/<your-core>/messages/email-giftCardActivation_$lang.properties
... 

In this file, we will write all of our localized text.

Create the impex

Now we will create the impex for our custom email in SAP Hybris. Update the following file <your-store>/import/coredata/contentCatalogs/<your-content-catalog>/email-content.impex and add the following impex to it:

$contentCatalog=myContentCatalog
$contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),CatalogVersion.version[default=Staged])[default=$contentCatalog:Staged]
$wideContent=CMSImageComponent,BannerComponent

UPDATE GenericItem[processor=de.hybris.platform.commerceservices.impex.impl.ConfigPropertyImportProcessor];pk[unique=true]
$emailResource=$config-emailResourceValue
# Language
$lang=en

# Import modulegen config properties into impex macros
UPDATE GenericItem[processor=de.hybris.platform.commerceservices.impex.impl.ConfigPropertyImportProcessor];pk[unique=true]
$jarResourceCms=$config-jarResourceCmsValue
$emailPackageName=$config-emailContextPackageName
$jarProjectResourceCms=jar:com.mySite.core.setup.CoreSystemSetup&/<my-site>/import/cockpits/cmscockpit

# Email page Template
INSERT_UPDATE EmailPageTemplate;$contentCV[unique=true];uid[unique=true];name;active;frontendTemplateName;subject(code);htmlTemplate(code);restrictedPageTypes(code)
;;GiftCardActivationEmailTemplate;Gift Card Activation Email Template;true;GiftCardActivationEmail; email_Gift_Card_Activation_Subject;email_Gift_Card_Activation_Body;EmailPage

# Templates for CMS Cockpit Page Edit
UPDATE EmailPageTemplate;$contentCV[unique=true];uid[unique=true];velocityTemplate[translator=de.hybris.platform.commerceservices.impex.impl.FileLoaderValueTranslator]
;;GiftCardActivationEmailTemplate;$jarProjectResourceCms/structure-view/structure_GiftCardActivationEmailTemplate.vm

INSERT_UPDATE ContentSlotName;name[unique=true];template(uid,$contentCV)[unique=true][default='GiftCardActivationEmailTemplate'];validComponentTypes(code)
;SiteLogo;;;logo
;TopContent;;$wideContent;
;BottomContent;;$wideContent;

INSERT_UPDATE ContentSlotForTemplate;$contentCV[unique=true];uid[unique=true];position[unique=true];pageTemplate(uid,$contentCV)[unique=true][default='GiftCardActivationEmailTemplate'];contentSlot(uid,$contentCV)[unique=true];allowOverwrite
;;SiteLogo-GiftCardActivationEmail;SiteLogo;;EmailSiteLogoSlot;true
;;TopContent-GiftCardActivationEmail;TopContent;;EmailTopSlot;true
;;BottomContent-GiftCardActivationEmail;BottomContent;;EmailBottomSlot;true

INSERT_UPDATE EmailPage;$contentCV[unique=true];uid[unique=true];name;masterTemplate(uid,$contentCV);defaultPage;approvalStatus(code)[default='approved'];fromEmail[lang=en];fromName[lang=en]
;;GiftCardActivationEmail; Gift Card Activation Email;GiftCardActivationEmailTemplate;true;;noreply@mySite.com;Gift Card Center

INSERT_UPDATE RendererTemplate;code[unique=true];contextClass;rendererType(code)[default='velocity']
;email_Gift_Card_Activation_Body;$emailPackageName.GiftCardActivationEmailContext
;email_Gift_Card_Activation_Subject;$emailPackageName.GiftCardActivationEmailContext

UPDATE RendererTemplate;code[unique=true];description[lang=$lang];templateScript[lang=$lang,translator=de.hybris.platform.commerceservices.impex.impl.FileLoaderValueTranslator]
;email_Gift_Card_Activation_Body;"Gift Card Activation Email Body";$emailResource/email-giftCardActivationBody.vm
;email_Gift_Card_Activation_Subject;"Gift Card Activation Email Subject";$emailResource/email-giftCardActivationSubject.vm

Note that I am also importing the velocity template for the cms cockpit. If you need to do that, please create the velocity file at that location.

Now, import this impex file in HAC and synchronize your content catalog.

Testing the custom email in Hybris

Now that everything is setup, we will test out our custom email.

From where ever you wish to send the email from, add the following java code to publish the event:

eventService.publishEvent(initializeEvent(new GiftCardActivationEvent(orderEntry, orderEntry.getOrder().getStore(),
                orderEntry.getOrder().getSite(), orderEntry.getOrder().getCurrency()), (CustomerModel) orderEntry.getOrder().getUser()));

We are using a method called initializeEvent. Below is the definition of this method:

private AbstractCommerceUserEvent initializeEvent(final AbstractCommerceUserEvent event, final CustomerModel customer) {

	event.setCustomer(customer);
	return event;
}

Now the event will publish and our event listener will listen to the event and start our process to send the email. Note, the way that it is setup, the email will send to the email of the customer placing the order.

Finally, this concludes our post. For all of our SAP Hybris posts, visit here. And for more information about email, visit the documentation here.

If you are looking for a shorter way to send custom email in Hybris, without customizations, view my other post: “How to send custom email in Hybris (shorter way!)

Categories: Hybris

2 Comments

sunil p · August 6, 2020 at 3:58 am

very helpful…
thank’s waqasaslam.

Geo · September 11, 2020 at 1:08 pm

Thanks .. helpful..

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *