Sending emails from core module

Is it possible to send email from the core module? I created entity listener so I want to send emails each time when the entity changes but I’m faced with Security Exception: No security context bound to the current thread
image
Tried setSecurityContext as well as annotation @Authenticated, but nothing helps. Any Ideas?
Here is the listener itself:

package com.company.tenderflow.listener;

import com.company.tenderflow.entity.Mailing;
import com.company.tenderflow.entity.Marketplace;
import com.company.tenderflow.entity.Tender;
import com.company.tenderflow.entity.TenderSearch;
import com.company.tenderflow.managedBeans.TenderSearchBean;
import com.company.tenderflow.managedBeans.TenderBean;
import com.company.tenderflow.managedBeans.DocumentBean;
import com.haulmont.cuba.core.EntityManager;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.app.EmailService;
import com.haulmont.cuba.core.global.EmailAttachment;
import com.haulmont.cuba.core.global.EmailInfo;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.listener.BeforeUpdateEntityListener;
import com.haulmont.cuba.core.sys.AppContext;
import com.company.tenderflow.parser.DataHelper;

import com.haulmont.cuba.core.sys.SecurityContext;
import com.haulmont.cuba.security.app.Authenticated;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import org.springframework.stereotype.Component;

import javax.inject.Inject;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Liya.Azancheeva on 26.06.2018.
 */
@Component("tenderflow_TenderSearchEntityListener")
public class TenderSearchEntityListener implements BeforeUpdateEntityListener<TenderSearch> {

    final SecurityContext securityContext = AppContext.getSecurityContext();

    @Inject
    protected EmailService emailService;

    @Inject
    private DocumentBean documentBean;

    @Inject
    private TenderBean tenderBean;

    @Inject
    private TenderSearchBean tenderSearchBean;

    private DataHelper dh = new DataHelper();

    @Inject
    private Persistence persistence;

    @Override
    @Authenticated
    public void onBeforeUpdate(TenderSearch entity, EntityManager entityManager) {
        System.out.println("@@@!!!!!!!@@@!");
        // If the user's "name" attribute has been changed
        if (persistence.getTools().getDirtyFields(entity).contains("state") && entity.getState()) {
            TimerTask task = new SearchTask(entity);
            java.util.Timer timer = new java.util.Timer();
            int period = Integer.parseInt(entity.getInterval().toString())*86400000 ;
            timer.schedule( task, 0, period);
        }
    }

    @Authenticated
    private int startParse(TenderSearch tenderSearch) {
        ArrayList<Tender> savedTenders = new ArrayList<>();
        String[] keywords = tenderSearch.getKeyword().split("\\s*,\\s*");
        DateFormat df = new SimpleDateFormat("dd.MM.yyyy");
        Date publishDateFrom = tenderSearch.getPublishDateFrom();
        Date updateDateFrom = tenderSearch.getUpdateDateFrom();
        Date lastSearchDate = tenderSearch.getLastSearchDate();
        String lastSearchDateString = tenderSearch.getLastSearchDate() != null ?  df.format(lastSearchDate) : "";
        String publishDateFromString = tenderSearch.getPublishDateFrom() != null ?  df.format(publishDateFrom) : lastSearchDateString;
        String updateDateFromString = tenderSearch.getUpdateDateFrom() != null ? df.format(updateDateFrom) : lastSearchDateString;
        String priceFrom = tenderSearch.getPriceFrom()!= null ? tenderSearch.getPriceFrom().toString() : "";
        String priceTo = tenderSearch.getPriceTo() != null ? tenderSearch.getPriceTo().toString() : "";
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
        try {
            Iterator<Marketplace> i = tenderSearch.getMarketplaces().iterator();
            while (i.hasNext()) {
                engine.eval(i.next().getScript());
                Invocable invocable = (Invocable) engine;
                for (String keyword : keywords) {
                    System.out.println(keyword);
                    invocable.invokeFunction("init", keyword, publishDateFromString, updateDateFromString, priceFrom, priceTo);
                    ArrayList<ScriptObjectMirror> result = (ArrayList<ScriptObjectMirror>) invocable.invokeFunction("searchTenders");
                    ArrayList<Tender> validTenders = dh.getTendersList(result, tenderSearch);
                    savedTenders = tenderBean.saveUnique(validTenders, tenderSearch);
                }
                tenderSearchBean.updateLastSearchDate(tenderSearch);
                System.out.println("найдено новых тендеров: "+ savedTenders.size());
                if (savedTenders.size()>0) {
                    //mailingService.sendByEmail(savedTenders, tenderSearch);
                    sendByEmail(savedTenders, tenderSearch);
                }
            }
        } catch (ScriptException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return savedTenders.size();
    }

    @Authenticated
    public void sendByEmail(List<Tender> tenders, TenderSearch tenderSearch) {
        byte[] xls = documentBean.createXLS(tenders);
        EmailAttachment xlsAttach = new EmailAttachment(xls, tenderSearch.getName()+".xls");
        StringBuilder sb = new StringBuilder();
        sb.append("По проекту \"" + tenderSearch.getName() + "\" найдены новые тендеры. ");
        for (Mailing mail : tenderSearch.getMailings()) {
            EmailInfo emailInfo = new EmailInfo(mail.getEmail(), tenderSearch.getName(), null, sb.toString(), xlsAttach);
            emailService.sendEmailAsync(emailInfo);
        }
    }


    private class SearchTask extends TimerTask {
        TenderSearch tenderSearch;
        public SearchTask (TenderSearch tenderSearch ){
            this.tenderSearch=tenderSearch;
        }

        @Authenticated
        public void run() {
            AppContext.setSecurityContext(securityContext);
            System.out.println("Запущен автоматический поиск тендеров по проекту \"" + tenderSearch.getName() + "\"");
            int changed = startParse(tenderSearch);
            System.out.println("Завершена работа над проектом \"" + tenderSearch.getName() + "\", изменено записей: " + changed);
            tenderSearch.setLastSearchDate(new Date());
        }
    }
}

Hi,
As written in the documentation @Authenticated works in beans. In entity listener you can use authentication.begin();

The following works for me:

@Component("sales_NewEntityListener")
public class NewEntityListener implements BeforeUpdateEntityListener<Order> {

    @Inject
    protected EmailService emailService;

    @Inject
    protected Authentication authentication;


    @Override
    public void onBeforeUpdate(Order entity, EntityManager entityManager) {


        TimerTask task = new SearchTask(entity);
        Timer timer = new Timer();
        int period = 1000;
        timer.schedule( task, 0, period);

    }


    private class SearchTask extends TimerTask {
        Order order;
        public SearchTask (Order order ){
            this.order=order;
        }

        public void run() {

            authentication.begin();

            try {

                System.out.println("Notification sending started");

                EmailInfo emailInfo = new EmailInfo(order.getCustomer().getEmail(), "new order", order.getCustomer().getName() + " " + order.getCustomer().getName());
                try {
                    emailService.sendEmailAsync(emailInfo);
                } catch (Exception e) {
                    this.cancel();
                }

                System.out.println("Order email is send to " + order.getCustomer().getName());
            }
            finally {
                authentication.end();
            }

        }
    }
}

Thank you, this helped!