Skip to Content
Technical Articles
Author's profile photo Aadil Kaleem

Email Process in Hybris

Introduction:

Hi guys,

In multiple e-commerce websites where you receive emails for various functionality like when you forget the password of your account . Once you click on forget password you just have to enter your email id then email is received on your email regarding forget password there you receive a link and using that link you can reset password. Similarly when you do registration at that time you will get registration confirmation email on your email id in the same way once you placed your order on e-commerce you will receive the order confirmation email. In this blog we will learn about Email Process functionality how email are generated and sent to a customer and what are backend step through which emails are generated so we will be learning all these concept in this blog,

Overview:

Email Page Template

The EmailPageTemplate page is an extension of the PageTemplate page type. When the system generates an email, it is based on this page template. The email page template, like the WCMS page template, can have one or more ContentSlotName objects that define the names and positions of the ContentSlot objects along with components that are allowed in the slots.

Email Page

The EmailPage page is an extension of the AbstractPage page type. It represents formatted emails such as Customer Registration or Order Confirmation. The email page uses the masterTemplate template and defines ContentSlotName objects and any predefined content slot objects with components that are specific to that particular email. There are also two localized attributes called fromEmail and fromName and both of these attributes are used for filling in corresponding email message properties during the sending of emails.

Renderer Template

The email subject, email body, and content of the components are generated using Velocity scripts. The RendererTemplate page contains a Velocity script, along with the Content Class name. The Velocity script contains tags which are replaced with the values from the context object provided during the rendering process.

 

Requirement:

We need to send email to registered customer email id if his/her cart total exceeds 100 pounds stating that if you buy an item worth 200 pound you will get 30% discount on your order total

Step 1:

Create a new item type “DiscountEmailProcess” which extend “StoreFrontCustomerProcess” add one attriute “cart” which type is “AbstractOrder”

<itemtype code="DiscountEmail"
                  extends="StoreFrontCustomerProcess"
                  autocreate="true"
                  generate="true">
            <attributes>
                <attribute qualifier="cart" type="AbstractOrder">
                    <persistence type="property"/>
                </attribute>
            </attributes>
        </itemtype>

build the project using ant command.

 

Step 2:

Create a new process.xml in trainingcore.processes “DiscountEmailProcess.xml”

Sending email is a business process containing a sequence of actions and is defined in a process definition XML file. The business process object contains the information required for the actions within the process. With email processes, the following actions are configured:

  1. Generate Email Action: The contents of the email are generated and an EmailMessage object is created. The EmailMessage objects created are attached to the business process so that the next action can act on them. This action depends on the ContextResolutionStrategy routine to impersonate the WCMS site, initialize the session context, and the EmailGenerationService routine to create the EmailMessage objects.
  2. Send Email: All the emails attached to the business process are sent using the EmailService routine. If the emails are sent successfully, the EmailMessage object is updated with the sent details.
  3. Remove Sent Email Action: If an EmailMessage object was sent successfully, it is removed from the system as shown in the following code:
<process xmlns="http://www.hybris.de/xsd/processdefinition" start="generateDiscountEmail" name="DiscountEmailProcess" processClass="org.training.core.model.DiscountEmailProcessModel." onError="error"> 
<action id="generateDiscountEmail" bean="generateDiscountEmailAction">
<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 for Discount.</end> 
<end id="success" state="SUCCEEDED">Sent Discount email .</end> 
</process>

Step 3:

Map the process.xml to corespring.xml file

<bean id="discountEmailProcessDefinitionResource"

class="de.hybris.platform.processengine.definition.ProcessDefinitionResource" >

<property name="resource" value="classpath:/trainingcore/processes/DiscountEmailProcess.xml"/>

</bean>

Map our action bean to spring .xml “generateDiscountEmailAction”

<bean id="generateDiscountEmailAction" parent="abstractGenerateEmailAction">

<property name="frontendTemplateName" value="DiscountEmailTemplate"/>

</bean>

 

Step 4:

Create a Event Class in core.event package which should extends “AbstractCommerceUserEvent”

public class DiscountEmailEvent extends AbstractCommerceUserEvent
{
// provide getter and setter
private AbstractOrder cart;
//Constructor
public DiscountEmailEvent(final AbstractOrderModel cart, final BaseStoreModel baseStore, final BaseSiteModel site, final CurrencyModel ,currency)
 {
    this.cart=cart;
    // this methods are from "AbstractCommerceUserEvent" class
    setBaseStore(baseStore);
    setBaseSite(site);
    setCurrency(currency);
    setLanguage(cart.getUser().getSessionLanguage());
  }
}

 

Step 5:

Create listner class in same package and it should extends “AbstractAcceleratorSiteEventListner” and  override onSiteEvent() methods

public class DiscountEmailEventListener extends AbstractAcceleratorSiteEventListener<DiscountEmailEvent>

{
  private ModelService modelService;//provide getter and setter
  private BusinessProcessService businessProcessService;//provide getter and setter
  protected void onSiteEvent(final DiscountEmailEvent event)
  {
     final DiscountEmailProcessModel discountEmailProcessModel =(DiscountEmailProcessModel) getBusinessProcessService().createProcess("DiscountEmailProcess-" +event.getCart().getCode() + "-" + System.currentTimeMillis(),"DiscountEmailProcess");
discountEmailProcessModel.setCart(event.getCart());
// these methods are from "StoreFrontCustomerProcess" itemtype which we define parent in "DiscountEmailProcess" itemtype

     discountEmailProcessModel.setCurrency(event.getCurrency());
     discountEmailProcessModel.setLanguage(event.getLanguage());
     discountEmailProcessModel.setStore(event.getBaseStore());
     discountEmailProcessModel.setSite(event.getSite());
     getModelService().save(discountEmailProcessModel);
     getBusinessProcessService().startProcess(discountEmailProcessModel);
   }
}

 

Step 6:

Define bean of listener class in spring.xml

<bean id="discountEmailEventListener" class="org.training.core.event.DiscountEmailEventListener"

parent="abstractAcceleratorSiteEventListener">

<property name="modelService" ref="modelService"/>

<property name="businessProcessService" ref="businessProcessService"/>

</bean>

 

Step 7:

Do changes in showCart method in CartPageController to call “DiscountEmailEvent”

public String showCart(final Model model) throws CMSItemNotFoundException
{
   if(!userFacade.isAnonymousUser())
   {
      final CartModel cartModel = cartService.getSessionCart();
      if(cartModel.getTotalPrice()>=Double.valueOf(100))
      {
         eventService.publishEvent(initializeEvent(new DiscountEmailEvent(cartModel,cartModel.getStore(),cartModel.getSite(),cartModel.getCurrency()),cartModel));
      }
   }

   return prepareCartUrl(model);
}
private AbstractEvent initializeEvent(final DiscountEmailEvent discountEmailEvent,final CartModel cartModel)
{
   discountEmailEvent.setCart(cartModel);
   return discountEmailEvent;
}

Add Dependency for userFacade and eventService

 

Step 8 :

Create a context class in facade extension which should extends AbstractEmailContext

An EmailContext is the one that holds the data to be passed to the email template

public class DiscountEmailContext extends AbstractEmailContext<DiscountEmailProcessModel>
{
   public void init(final DiscountEmailProcessModel discountEmailProcessModel, final EmailPageModel emailPageModel)
   {
     super.init(discountEmailProcessModel, emailPageModel);   
     put(Email, getCustomerEmailResolutionService().getEmailForCustomer(getCustomer(discountEmailProcessModel)));
     put(Display_NAME, getCustomer(discountEmailProcessModel).getDislayName())
   }
}

 

Create a bean  for context class

 

<bean id="discountEmailContext" class="org.training.facades.process.email.context.DiscountEmailContext" parent="abstractEmailContext" scope="prototype" >

 

Step 9:

create a vm(velocity) file for subject and body

Step 10:

run the impex

$contentCatalog=apparel-ukContentCatalog
$contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),CatalogVersion.version[default=Online])[default=$contentCatalog:Online]
$wideContent=CMSImageComponent,BannerComponent
# 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
$emailResource=$config-emailResourceValue
$lang=en

INSERT_UPDATE RendererTemplate;code[unique=true];contextClass;rendererType(code)[default='velocity']
;discountEmailBody;$emailPackageName.DiscountEmailContext
;discountEmailSubject;$emailPackageName.DiscountEmailContext

UPDATE RendererTemplate;code[unique=true];description[lang=$lang];templateScript[lang=$lang,translator=de.hybris.platform.commerceservices.impex.impl.FileLoaderValueTranslator]
;discountEmailBody;"Discount Email Body";$emailResource/email-discountEmailBody.vm
;discountEmailSubject;"Discount Email Subject";$emailResource/email-discountEmailSubject.vm

INSERT_UPDATE EmailPageTemplate;$contentCV[unique=true];uid[unique=true];name;active;frontendTemplateName;subject(code);htmlTemplate(code);restrictedPageTypes(code)
;;DiscountEmailTemplate;discount Email Template;true;discountEmail;discountEmailSubject;discountEmailBody;EmailPage

INSERT_UPDATE EmailPage;$contentCV[unique=true];uid[unique=true];name;masterTemplate(uid,$contentCV);defaultPage;approvalStatus(code)[default='approved'];fromEmail[lang=en];fromName[lang=en]
;;discountEmail;Discount Email;DiscountEmailTemplate;true;;aadil.kaleem@signiwis.com;Hybris Training

INSERT_UPDATE ContentSlotName;name[unique=true];template(uid,$contentCV)[unique=true][default='DiscountEmailTemplate'];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='DiscountEmailTemplate'];contentSlot(uid,$contentCV)[unique=true];allowOverwrite
;;SiteLogo-DiscountEmail;SiteLogo;;EmailSiteLogoSlot;true
;;TopContent-DiscountEmail;TopContent;;EmailTopSlot;true
;;BottomContent-DiscountEmail;BottomContent;;EmailBottomSlot;true

 

Step 10:

You have to configure in local.properties for email

 

mail.smtp.server=smtp.gmail.com
mail.smtp.port=587
mail.smtp.user=INSERT_YOUR_GOOGLE_MAIL_ADDRESS
mail.smtp.password=INSERT_YOUR_GOOGLE_MAIL_PASSWORD_HERE
mail.use.tls=true
—————————————————————————————————————————-
Email with Attachment :
For generating email with attachment these are the steps given below

Step 1:

 Create one to many relation between business process and Email Attachment type
 <relation code="BusinessProcess2Attachments" localized="false" generate="true" autocreate="true">
           <sourceElement type="BusinessProcess" qualifier="process" cardinality="one">
           </sourceElement>
            <targetElement type="EmailAttachment" qualifier="attachments" cardinality="many" collectiontype="list">
                <modifiers partof="true"/>
            </targetElement>
  </relation>

Step 2:

Create a new class AttachmentEmailGenrationService and extends DefaultEmailGenrationService and Override genrate() method
public class AttachmentEmailGenerationService extends DefaultEmailGenerationService 
{
   private ModelService modelService; // provide getter and setter
   private static final Logger LOG = Logger.getLogger(AttachmentEmailGenerationService.class);
   @Override
   public EmailMessageModel generate(final BusinessProcessModel businessProcessModel, final EmailPageModel emailPageModel) throws RuntimeException 
   {
        EmailMessageModel emailMessage = super.generate(businessProcessModel, emailPageModel);
        List<EmailAttachmentModel> attachments = businessProcessModel.getAttachments();
        emailMessage.setAttachments(attachments);
        getModelService().saveAll(emailMessage);
        return emailMessage;
    }
}

Step:3

Register the AttachmentEmailGenerationService as a bean in Spring, with the emailGenerationService as an alias.
<alias alias="emailGenerationService" name="attachmentEmailGenerationService"/>
<bean id="attachmentEmailGenerationService"
class="com.stackextend.training.core.email.AttachmentEmailGenerationService"
parent="defaultEmailGenerationService">
</bean>

Step:4

Make changes in Event Listner class

        InputStream input;
        try {
            input=  new FileInputStream("");\\Attachment File Location
            DataInputStream dataInputStream = new DataInputStream(input);
            final String fileName = "Discount_Attachment"+System.currentTimeMillis()+".txt";
            final String mimeType="text";
            EmailAttachmentModel emailAttachment = getEmailService().createEmailAttachment(dataInputStream, fileName, mimeType);
            List<EmailAttachmentModel> attachments = new ArrayList<>();
            attachments.add(emailAttachment);
            discountEmailModel.setAttachments(attachments);
            } 
            catch (FileNotFoundException e)
              {
                 e.printStackTrace();
              }

        getModelService().save(discountEmailModel);
        getBusinessProcessService().startProcess(discountEmailModel);​
Build the project and do the system update,
So whenever condition matches the email will be send to the registered customer

Conclusion:

This is how Email Process works in hybris
If you have any queries feel free to comment

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.