3.9.2.4. Отправка email

В данном разделе рассматривается пример использования механизма рассылки email.

Рассмотрим следующую задачу:

  • Имеется сущность NewsItem и экран ее редактирования NewsItemEdit.

  • Сущность NewsItem имеет следующие атрибуты: date, caption, content.

  • Необходимо отсылать электронные письма каждый раз, когда через экран NewsItemEdit создается новый экземпляр сущности. Email должен содержать NewsItem.caption в качестве темы письма, тело письма должно формироваться на основе шаблона, включающего NewsItem.content.

  1. Добавьте следующий код в NewsItemEdit.java:

    @UiController("sample_NewsItem.edit")
    @UiDescriptor("news-item-edit.xml")
    @EditedEntityContainer("newsItemDc")
    @LoadDataBeforeShow
    public class NewsItemEdit extends StandardEditor<NewsItem> {
    
        private boolean justCreated; (1)
    
        @Inject
        protected EmailService emailService;
    
        @Inject
        protected Dialogs dialogs;
    
        @Subscribe
        public void onInitEntity(InitEntityEvent<NewsItem> event) { (2)
            justCreated = true;
        }
    
        @Subscribe(target = Target.DATA_CONTEXT)
        public void onPostCommit(DataContext.PostCommitEvent event) { (3)
            if (justCreated) {
                dialogs.createOptionDialog() (4)
                        .withCaption("Email")
                        .withMessage("Send the news item by email?")
                        .withType(Dialogs.MessageType.CONFIRMATION)
                        .withActions(
                                new DialogAction(DialogAction.Type.YES) {
                                    @Override
                                    public void actionPerform(Component component) {
                                        sendByEmail();
                                    }
                                },
                                new DialogAction(DialogAction.Type.NO)
                        )
                        .show();
            }
        }
    
        private void sendByEmail() { (5)
            NewsItem newsItem = getEditedEntity();
            EmailInfo emailInfo = new EmailInfo(
                    "john.doe@company.com,jane.roe@company.com", (6)
                    newsItem.getCaption(), (7)
                    null, (8)
                    "com/company/demo/templates/news_item.txt", (9)
                    Collections.singletonMap("newsItem", newsItem) (10)
            );
            emailService.sendEmailAsync(emailInfo);
        }
    }
    1 - флаг, указывающий, что в этом редакторе был создан новый экземпляр сущности NewsItem.
    2 - этот метод вызывается при инициализации нового экземпляра сущности.
    3 - этот метод вызывается после коммита в data context.
    4 - если новый экземпляр был сохранен в базе данных, попросить пользователя об отправке сообщения по электронной почте.
    5 - помещает электронное письмо в очередь для асинхронной отправки.
    6 - получатели.
    7 - тема.
    8 - адрес отправителя берется из свойства приложения cuba.email.fromAddress.
    9 - путь до шаблона.
    10 - параметры шаблона.

    Как видно, метод sendByEmail() вызывает сервис EmailService и передает ему экземпляр EmailInfo, описывающий сообщение. Тело сообщений будет создаваться на основе шаблона news_item.txt.

  2. Создайте шаблон тела письма в файле news_item.txt в пакете com.company.demo.templates модуля core:

    The company news:
    ${newsItem.content}

    Это шаблон Freemarker, который использует параметры, переданные в EmailInfo (в данном случае единственный параметр newsItem).

  3. Запустите приложение, откройте браузер сущности NewsItem и нажмите Create. Откроется экран редактирования сущности. Заполните поля и нажмите OK. Появится диалог подтверждения с вопросом об отсылке email. Нажмите Yes.

  4. Перейдите в экран Administration > Email History вашего приложения. Вы увидите две записи (по числу получателей) со статусом Queue. Он означает, что сообщения находятся в очереди и еще не отосланы.

  5. Для обработки очереди необходимо создать назначенное задание. Перейдите в экран Administration > Scheduled Tasks вашего приложения. Создайте новую задачу и установите ей следующие параметры:

    • Bean Name - cuba_Emailer

    • Method Name - processQueuedEmails()

    • Singleton - да (этот параметр важен только при эксплуатации кластера серверов middleware)

    • Period, sec - 10

    Сохраните задачу и нажмите на ней Activate.

    Если вы ранее не настраивали выполнение назначенных заданий для данного приложения ранее, то на данном этапе ничего не произойдет - новая задача не начнет выполняться, пока вы не запустите весь механизм назначенных заданий.

  6. Откройте файл modules/core/src/app.properties и добавьте в него следующее свойство:

    cuba.schedulingActive = true

    Перезапустите сервер приложения. Механизм выполнения заданий теперь активен и вызывает обработку очереди email.

  7. Перейдите в экран Administration > Email History. Статус сообщений будет либо Sent, если они успешно отосланы, либо, что более вероятно, Sending или Queue, если произошла ошибка отправки. В последнем случае вы можете открыть журнал приложения в файле build/tomcat/logs/app.log и выяснить причину. Механизм отсылки email предпримет несколько (по умолчанию 10) попыток и в случае неудачи переведет сообщения в статус Not sent.

  8. Наиболее очевидной причиной ошибки отправки является то, что вы не настроили параметры SMTP-сервера. Эти параметры могут быть заданы в базе данных с помощью JMX бина app-core.cuba:type=Emailer или в свойствах приложения блока middleware. Рассмотрим второй способ. Откройте файл modules/core/src/app.properties и добавьте в него требуемые параметры:

    cuba.email.fromAddress = do-not-reply@company.com
    cuba.email.smtpHost = mail.company.com

    Перезапустите сервер приложения. Перейдите в экран Administration > JMX Console, найдите JMX бин Emailer и попробуйте послать самому себе тестовое сообщение с помощью операции sendTestEmail().

  9. Теперь механизм отсылки email настроен корректно, однако он не будет отсылать сообщения, уже переведенные в статус Not sent. Поэтому необходимо создать новый экземпляр NewsItem через экран редактирования. Сделайте это и понаблюдайте, как статус новых сообщений в экране Email History изменится на Sent.