Email notification x-number of days before expiration date

Hi there,

For items in my a screen with an expiration date, i want to create an notification for say 30 days before the actual expiration date. I don’t know how to start to be honest. I’ve gone through the documentation but still i can’t find the right way. I just need a point out in the right direction.

Can anyone please help?

Regards,

LS

Hi,

Did you read about Scheduled Tasks? I think you can create a service that can send notification emails and create scheduled tasks for execution.

I did check that, but i will check again.

Thanks Andrey

Hi,

Yes please. If you bump into a technical difficulty, let us know. But the idea is to create a scheduled task for each subscription(?) created and add this task to a scheduler. The task should invoke an emailing service that you can create and pass subscription ID as a parameter. The service should take this parameter and generate and send an email.

Hi Andrey,

I did a search in the forum and came upon this topic " Scheduling email depending on date attribute", which is exactly what i want to do. I used the code in my project, but i ran into some errors.

This is my code:

package com.company.krs.service;

import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Query;
import com.haulmont.cuba.core.app.EmailService;
import com.haulmont.cuba.core.global.EmailInfo;
import com.haulmont.cuba.security.app.Authenticated;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.util.Iterator;
import java.util.List;

@SuppressWarnings(“ALL”)
@Component(ReminderMailService.NAME)
public class ReminderMailServiceBean implements ReminderMailService {

@Inject
protected EmailService emailService;
@Inject
private Persistence persistence;

@Authenticated
@Transactional
@Override
public void checkReminders(){
    Query query = persistence.getEntityManager().createNativeQuery(
            "select s.fistNames,s.lastName,t.phoneNumber,t.mobileNumber,t.expirationDate\n" +
                    "from REGISTRATIE s\n" +
                    "where CURRENT_DATE=DATE_SUB(CAST(t.expirationDate AS DATE), INTERVAL 30 DAYS)");

    List list = query.getResultList();


    for (Iterator it = list.iterator(); it.hasNext(); ) {
        Object[] row = (Object[]) it.next();
        String lastName = (String) row[0];
        String firstNames = (String) row[1];
        String phoneNumber = (String) row[2];
        String mobileNumber = row[3].toString();
        String expirationDate = row[4].toString();
        sendByEmail(lastName,firstNames,phoneNumber,mobileNumber,expirationDate);
    }
}

// MAIL FUNCTIONALITY
private void sendByEmail(String lastName, String firstNames, String phoneNumber, String mobileNumber, String expirationDate) {

    EmailInfo emailInfo = new EmailInfo(
            lastName,
            "Pasport Expiration Reminder: "+ expirationDate, // subject
            null, // the "from" address will be taken from the "cuba.email.fromAddress" app property

            "Hello "+lastName+",\n\nThis is a reminder that the following passport will be valid until: \n "+expirationDate+"\n" +
                    "Last Name: " +lastName+ "\n" +
                    "Fist Names: " +firstNames+ "\n" +
                    "Phone Number: " +phoneNumber+ "\n" +
                    "Mobile Number: " +mobileNumber+ "\n" +
                    "Expiration Date: " +expirationDate+ "\n\nThis is a no-reply mail\nHave a nice day."// body template
    );
    emailService.sendEmailAsync(emailInfo);
}

}

package com.company.krs.service;

import com.haulmont.cuba.security.app.Authenticated;
import org.springframework.transaction.annotation.Transactional;

public interface ReminderMailService {
String NAME = “krs_ReminderMailService”;

@Authenticated
@Transactional
void checkReminders();

}

In the reminderMailServie i get two errors:

  • failed
  • :crm-global:compileJava
  • modules/global/src/com/company/krs/service/ReminderMailService.java
  • cannot find symbol class Authenticated
  • package org.springframework.transaction.annotation does not exist
  • cannot find symbol class Authenticated
  • cannot find symbol class Transactional

Seems like i’m trying to implement these options in the wrong way.

Thanks for your help Andrey.

Regards,

LS

It looks like you have broken imports for annotations. Please reimport classes @Authenticated and @Transactional and double check that this service is in the core module.

I checked and the service is in the core module. Also reimported the classes but stil the same…

image

You have your annotations set in the service interface, not in the implementation. The interface is in the global module. Please move those annotations to the service implementation a.k.a. ReminderMailServiceBean

I did what you said and now the service is starting up and running. But I get the following error:

java.lang.RuntimeException: javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.3.6-cuba): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: syntax error at or near “30”
Position: 165
Error Code: 0
Call: select s.fistNames,s.lastName,t.phoneNumber,t.mobileNumber,t.expirationDate
from REGISTRATIE s
where CURRENT_DATE=DATE_SUB(CAST(t.expirationDate AS DATE), INTERVAL 30 DAYS)
Query: DataReadQuery(sql=“select s.fistNames,s.lastName,t.phoneNumber,t.mobileNumber,t.expirationDate
from REGISTRATIE s
where CURRENT_DATE=DATE_SUB(CAST(t.expirationDate AS DATE), INTERVAL 30 DAYS)”)
{Executed manually}

I think it has something to do with the “INTERVAL 30 DAYS”. Still looking for a solution.

I think the problem lies in de postgres database i am using. I’m trying to figure out what format to use.

Yes, it looks like your SQL query might not be compatible with PostgreSQL dialect. Hope you’ve found this reference

Thanks Andrey good document, a real eye opener. I did some more research and managed to get the code right, at least it seems like that. But now i’m getting the following error when executing the scheduled task:

java.lang.RuntimeException: com.haulmont.cuba.core.global.RemoteException:

javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.3.6-cuba): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: value too long for type character varying(50)
Error Code: 0
Call: INSERT INTO SYS_SENDING_MESSAGE (ID, ADDRESS_TO, ATTACHMENTS_NAME, ATTEMPTS_COUNT, ATTEMPTS_MADE, ADDRESS_BCC, BODY_CONTENT_TYPE, CAPTION, ADDRESS_CC, CONTENT_TEXT, CREATE_TS, CREATED_BY, DATE_SENT, DEADLINE, DELETE_TS, DELETED_BY, ADDRESS_FROM, EMAIL_HEADERS, STATUS, SYS_TENANT_ID, UPDATE_TS, UPDATED_BY, VERSION, CONTENT_TEXT_FILE_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [fd7f1f2c-4cb6-a7c2-ab54-16dc4d1b991a, l43sedoc@gmail.com, null, null, 0, null, Hello Employee,

This is a reminder that the following passport will be valid until:
2020-08-21
Last Name: Riley Emma
Fist Names: Hippolyte
Phone Number:
Mobile Number: 8862250
Expiration Date: 2020-08-21

This is a no-reply mail
Have a nice day., Pasport Expiration Reminder: 2020-08-21, null, null, 2020-07-21 10:52:12.919, admin, null, null, null, null, l43sedoc@gmail.com, null, 0, null, 2020-07-21 10:52:12.919, null, 1, null]
Query: InsertObjectQuery(com.haulmont.cuba.core.entity.SendingMessage-fd7f1f2c-4cb6-a7c2-ab54-16dc4d1b991a [new,managed])

org.eclipse.persistence.exceptions.DatabaseException:
Internal Exception: org.postgresql.util.PSQLException: ERROR: value too long for type character varying(50)
Error Code: 0
Call: INSERT INTO SYS_SENDING_MESSAGE (ID, ADDRESS_TO, ATTACHMENTS_NAME, ATTEMPTS_COUNT, ATTEMPTS_MADE, ADDRESS_BCC, BODY_CONTENT_TYPE, CAPTION, ADDRESS_CC, CONTENT_TEXT, CREATE_TS, CREATED_BY, DATE_SENT, DEADLINE, DELETE_TS, DELETED_BY, ADDRESS_FROM, EMAIL_HEADERS, STATUS, SYS_TENANT_ID, UPDATE_TS, UPDATED_BY, VERSION, CONTENT_TEXT_FILE_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [fd7f1f2c-4cb6-a7c2-ab54-16dc4d1b991a, l43sedoc@gmail.com, null, null, 0, null, Hello Employee,

This is a reminder that the following passport will be valid until:
2020-08-21
Last Name: Riley Emma
Fist Names: Hippolyte
Phone Number:
Mobile Number: 8862250
Expiration Date: 2020-08-21

This is a no-reply mail
Have a nice day., Pasport Expiration Reminder: 2020-08-21, null, null, 2020-07-21 10:52:12.919, admin, null, null, null, null, l43sedoc@gmail.com, null, 0, null, 2020-07-21 10:52:12.919, null, 1, null]
Query: InsertObjectQuery(com.haulmont.cuba.core.entity.SendingMessage-fd7f1f2c-4cb6-a7c2-ab54-16dc4d1b991a [new])

org.postgresql.util.PSQLException: ERROR: value too long for type character varying(50)
{Executed manually}

The code looks like this:

package com.company.krs.core;

import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Query;
import com.haulmont.cuba.core.app.EmailService;
import com.haulmont.cuba.core.global.EmailInfo;
import com.haulmont.cuba.security.app.Authenticated;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.util.Iterator;
import java.util.List;

@Component(ReminderMailServiceBean.NAME)
public class ReminderMailServiceBean implements ReminderMailService {

public static final String NAME = "krs_ReminderMailServiceBean";
@Inject
protected EmailService emailService;
@Inject
private Persistence persistence;

@Authenticated
@Transactional
@Override
public void checkReminders(){
    Query query = persistence.getEntityManager().createNativeQuery(
            "select s.first_names,s.last_name,s.phone_number,s.mobile_number,s.expiration_date\n" +
                    "from KRS_REGISTRATIE s\n" +
                    "where s.expiration_date = current_date + INTERVAL '1' month");


    List list = query.getResultList();


    for (Iterator it = list.iterator(); it.hasNext(); ) {
        Object[] row = (Object[]) it.next();
        String first_names = (String) row[0];
        String last_name = (String) row[1];
        String phone_number = (String) row[2];
        String mobile_number = (String) row[3];
        String expiration_date = row[4].toString();
        sendByEmail(first_names,last_name,phone_number,mobile_number,expiration_date);
    }
}

// MAIL FUNCTIONALITY
private void sendByEmail(String last_name, String first_names, String phone_number, String mobile_number, String expiration_date) {

    EmailInfo emailInfo = new EmailInfo(
            "l43sedoc@gmail.com", // recipients
            "Pasport Expiration Reminder: "+ expiration_date, // subject
            null, // the "from" address will be taken from the "cuba.email.fromAddress" app property

            "Hello Employee,\n\nThis is a reminder that the following passport will be valid until: \n "+expiration_date+"\n" +
                    "First Names: " +first_names+ "\n" +
                    "Last Name: " +last_name+ "\n" +
                    "Phone Number: " +phone_number+ "\n" +
                    "Mobile Number: " +mobile_number+ "\n" +
                    "Expiration Date: " +expiration_date+ "\n\nThis is a no-reply mail\nHave a nice day."// body template
    );
    emailService.sendEmailAsync(emailInfo);
}

}

It looks like you’re using field BODY_CONTENT_TYPE to store email body. To simplify email info creation I’d recommend injecting EmailInfoBuilder bean to create email in the following way:

EmailInfo emailInfo = EmailInfoBuilder.create()
               .setAddresses(addresses)
               .setCaption("Email subject")
               .setBody("Some email body")
               .build();

Thanks Andrey. I’ve created an email template which i’d like to use for this purpose. I will look into that option.

Regards.

I changed the bean to:

package com.company.krs.core;

import com.haulmont.cuba.core.app.EmailService;
import com.haulmont.cuba.core.global.EmailInfo;
import com.haulmont.cuba.core.global.EmailInfoBuilder;
import com.haulmont.cuba.security.app.Authenticated;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;

@Component(ReminderMailServiceBean.NAME)
public class ReminderMailServiceBean implements ReminderMailService {

public static final String NAME = "krs_ReminderMailServiceBean";
@Inject
protected EmailService emailService;

@Authenticated
@Transactional
@Override
// MAIL FUNCTIONALITY
public void sendByEmail() {
    EmailInfo emailInfo = EmailInfoBuilder.create()
            .setAddresses("l43sedoc@gmail.com")
            .setFrom(null)
            .setTemplatePath("com/company/krs/templates/passports.txt")
            .build();
        emailService.sendEmailAsync(emailInfo);
    }

@Override
public void checkReminders() {
}

}

And:

package com.company.krs.core;

import com.haulmont.cuba.security.app.Authenticated;
import org.springframework.transaction.annotation.Transactional;

public interface ReminderMailService {
void checkReminders();

@Authenticated
@Transactional
    // MAIL FUNCTIONALITY

void sendByEmail();

}
I created a template which i stored here: com/company/krs/templates/passports.txt

When i run the task i get no errors but also no email. In the email history in the application nothing is stored. Can you please help me check what i’m missing?

Regards.

Hi,

Did you try to debug the application, sendEmailAsync method, for instance? And what does log say? Are there any exceptions?

It is quite hard to perform the full diagnostics, the error might happen due to a mail server misconfiguration, mail routing rules, etc. The only thing that you should double check is that the server accepted your email.