Mail System

Introduction

Ontimize Boot is a framework that allows you to simplify the configuration of a project made with Ontimize EE, in a fast and efficient way. The email system allows you to send mail from the server with a simple configuration.

Prerequisites

There are 2 options to follow this tutorial, clone the repository with the initial state and follow the tutorial step by step, or download the final example and see which files are new and which have been updated.

Initial project

/$ git clone https://github.com/ontimize/ontimize-examples
/ontimize-examples$ cd ontimize-examples
/ontimize-examples$ git checkout boot-mail-initial

Final example

/$ git clone https://github.com/ontimize/ontimize-examples
/ontimize-examples$ cd ontimize-examples
/ontimize-examples$ git checkout boot-mail

Configuring email service with Ontimize Boot

In this complete tutorial, we are going to create a backend for an application from scratch, including the database with different tables, configuring the server, creating the necessary DAO files and implementing the service. At the end of the tutorial, we will even be testing that our mailing system is fully operational and functional.

DB configuration

If the configuration table does not exist in the DB, it can be created with the following command:

Sentencia SQL (HSQL)

CREATE TABLE TSETTING(ID_SETTING INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,SETTING_KEY LONGVARCHAR,SETTING_VALUE LONGVARCHAR,SETTING_COMMENTLONGVARCHAR);

We fill in this table with the data that applies to each specific mail server, in this example, we will use the following:

SETTING_KEY SETTING_VALUE SETTING_COMMENT
mail_host localhost Server host
mail_port 2525 Email server port
mail_protocol smtp Mailing protocol
mail_user my.mail@example.com User for sending
mail_password my_password Mail server password
mail_encoding UTF-8 Encoding of mails
mail_properties mail.smtp.auth:true; mail.smtp.starttls.enable:true; Mail properties

Sentencia SQL (HSQL)

INSERT INTO TSETTING (SETTING_KEY, SETTING_VALUE, SETTING_COMMENT) VALUES('mail_host', 'localhost', 'Server host');
INSERT INTO TSETTING (SETTING_KEY, SETTING_VALUE, SETTING_COMMENT) VALUES('mail_port', '2525', 'Email server port');
INSERT INTO TSETTING (SETTING_KEY, SETTING_VALUE, SETTING_COMMENT) VALUES('mail_protocol', 'smtp', 'Mailing protocol');
INSERT INTO TSETTING (SETTING_KEY, SETTING_VALUE, SETTING_COMMENT) VALUES('mail_user', 'my.mail@example.com', 'User for sending');
INSERT INTO TSETTING (SETTING_KEY, SETTING_VALUE, SETTING_COMMENT) VALUES('mail_password', 'my_password', 'Mail server password');
INSERT INTO TSETTING (SETTING_KEY, SETTING_VALUE, SETTING_COMMENT) VALUES('mail_encoding', 'UTF-8', 'Encoding of mails');
INSERT INTO TSETTING (SETTING_KEY, SETTING_VALUE, SETTING_COMMENT) VALUES('mail_properties', 'mail.smtp.auth:true;mail.smtp.starttls.enable:true;', 'Mail properties');

The implementation interface contains multiple methods, to which we must give permissions, if our application has permissions:

Sentencia SQL (HSQL)

INSERT INTO TSERVER_PERMISSION (PERMISSION_NAME) VALUES('com.ontimize.jee.server.services.mail.IMailServiceServer/sendMail');
INSERT INTO TSERVER_PERMISSION (PERMISSION_NAME) VALUES('com.ontimize.jee.server.services.mail.IMailServiceServer/sendMailWithoutAttach');
INSERT INTO TROLE_SERVER_PERMISSION (ID_ROLENAME, ID_SERVER_PERMISSION) VALUES((SELECT ID_ROLENAME FROM TROLE WHERE ROLENAME='admin'), (SELECT ID_SERVER_PERMISSION FROM TSERVER_PERMISSION WHERE PERMISSION_NAME='com.ontimize.jee.server.services.mail.IMailServiceServer/sendMail'));
INSERT INTO TROLE_SERVER_PERMISSION (ID_ROLENAME, ID_SERVER_PERMISSION) VALUES((SELECT ID_ROLENAME FROM TROLE WHERE ROLENAME='admin'), (SELECT ID_SERVER_PERMISSION FROM TSERVER_PERMISSION WHERE PERMISSION_NAME='com.ontimize.jee.server.services.mail.IMailServiceServer/sendMailWithoutAttach'));

Adding dependencies

Now we need to add the correct dependency in the correct pom.xml:

...
<dependencies>
...	
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
  </dependency>
...
</dependencies>
...

Server Configuration

To configure this service, a new configuration fragment shall be added to the application.yml file.

ontimize:
   mail:
      ref-repository: OCSettingsDao
      filter-column-name: SETTING_KEY
      value-column-name: SETTING_VALUE
      query-id: default
      filter-column-value-encoding: mail_encoding
      filter-column-value-host: mail_host
      filter-column-value-port: mail_port
      filter-column-value-protocol: mail_protocol
      filter-column-value-user: mail_user
      filter-column-value-password: mail_password
      filter-column-value-java-mail-properties: mail_properties
      engine: default

This configuration indicates the keys and values to be stored in the database. The database table is the one corresponding to the bean described in the refRepository: OCSettingsDao attribute (in this case, OCSettingsDao), which can be seen in the table TSETTING attribute (for this example, TSETTING) of the *.xml configuration file of the bean (OCSettingsDao.xml). The keys would be stored in the SETTING_KEY column, the values in the SETTING_VALUE column and the rest of the attributes map the keys that exist in the database.

In addition, the packet that will be scanned to look for the implementation of the email service is indicated.

Creation of DAO files

Let’s create a DAO (Data Access Object) in the projectwiki-model module to use as a model of this database table. The DAO is composed by 2 files, a file with extension *.xml and a *.java file.

In our *.xml file we will indicate the database table for which DAO belongs, the data source from which we collect the information (e.g. the database connection that contains this table) and the schema to which the table belongs.

OCSettingsDao.xml

<?xml version="1.0" encoding="UTF-8"?>
<JdbcEntitySetup
    xmlns="http://www.ontimize.com/schema/jdbc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.ontimize.com/schema/jdbc http://www.ontimize.com/schema/jdbc/ontimize-jdbc-dao.xsd"
    catalog="" schema="${mainschema}" table="TSETTING"
    datasource="mainDataSource" sqlhandler="dbSQLStatementHandler">
    <DeleteKeys>
        <Column>ID_SETTING</Column>
    </DeleteKeys>
    <UpdateKeys>
        <Column>ID_SETTING</Column>
    </UpdateKeys>
    <GeneratedKey>ID_SETTING</GeneratedKey>
</JdbcEntitySetup>

In the *.java file we indicate that it is a repository whose name will be OCSettingsDao, through the annotation @Repository. With the annotation @Lazy, we will indicate that the load is delayed until it is completely necessary (improving in that way the performance), and the annotation @ConfigurationFile allows us to configure this DAO using the XML file and an additional file where some common characteristics to several DAOs can be stored. like the scheme to which they belong.

OCSettingsDao.java

package com.ontimize.projectwiki.model.core.dao;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;

import com.ontimize.jee.server.dao.common.ConfigurationFile;
import com.ontimize.jee.server.dao.jdbc.OntimizeJdbcDaoSupport;

@Repository("OCSettingsDao")
@Lazy
@ConfigurationFile(configurationFile = "dao/OCSettingsDao.xml", configurationFilePlaceholder = "dao/placeholders.properties")
public class OCSettingsDao extends OntimizeJdbcDaoSupport {

  public OCSettingsDao() {
    super();
  }

}

Implementation in an existing service

To use this service in another service (e.g. to send a mail when a new record is created), just add a variable of type com.ontimize.jee.common.services.mail.IMailService and annotate it with @Autowired.

For space reasons, the entire files are not included, only the code snippets related to the tutorial. The … in the code snippets indicate that there may be unrelated code before or after them.

...
import com.ontimize.jee.common.services.mail.IMailService;
...
@Service("CandidateService")
@Lazy
public class CandidateService implements ICandidateService {
...
@Autowired
private IMailService mailService;
 ...
@Override
public EntityResult candidateInsert(Map<String, Object> attrMap) throws OntimizeJEERuntimeException {
	EntityResult toRet = this.daoHelper.insert(this.candidateDao, attrMap);

	if ((toRet.getCode() != EntityResult.OPERATION_WRONG)) {

		Runnable runnable = () -> {

		List<String> receiverList = new ArrayList<String>();
		receiverList.add("receiver@example.com");
		StringBuilder builder = new StringBuilder();
		builder.append("Created new user.");
		try {
			this.mailService.sendMailWithoutAttach("my.mail@example.com", receiverList, "New candidate",
				builder.toString());
		} catch (OntimizeJEEException e) {
	}
	};
			
  DelegatingSecurityContextRunnable wrappedRunnable = new DelegatingSecurityContextRunnable(runnable);
	  new Thread(wrappedRunnable).start();
  }

return toRet;
}
 ...
  

Checking the sending of mails

In order to check that the created service is indeed sending mails, we will use an external service called FakeSMTP, is a free Fake SMTP Server with GUI for testing emails in applications easily.

To do this, we enter this link and clone the repository it indicates into the workspace where we have our project.

We launch the DB and the server. Next, open a console and move to the path where FakeSMTP was downloaded:

...\FakeSMTP> mvn package-Dmaven.test.skip
...\FakeSMTP> cd target
...\FakeSMTP\target> java -jar fakeSMTP-2.1-SNAPSHOT.jar -s -p 2525
Command Meaning 34
fakeSMTP-VERSION.jar Downloaded version.  
-s Launch the server.  
- p 2525 Launch the application on the port indicated.  

Now we can use an application like Postman to execute different REST requests to our project.

Use REST request

The requests contains the following structure: localhost:33333/candidates/candidate

Element Meaning
localhost:33333 Indicates the host
/candidates Indicates the service to be queried
/candidate Indicates the DAO that will access that service

The request types can only be GET, POST, PUT, DELETE.

Below are examples of request for candidates (CANDIDATES).

The authorization used for these requests is authorization of the type BASIC.

In both cases, the access must be done with a user and password example:

    User: demo
Password: demouser
Request type Query URL Service method Body request
POST insert localhost:33333/candidates/candidate candidateInsert Example below

Body request:

{
    "data": {
        "PHONE": "555-444-8888",
        "BIRTHDAY": 788224700000,
        "SURNAME": "Wilson",
        "EMAIL": "wwiilsoon@example.org",
        "SPECIALTIES": "C#",
        "NAME": "William",
        "DNI": "88643946Z"
    },
    "sqltypes": {
        "SPECIALTIES": 12,
        "LINKEDIN": 12,
        "PHONE": 12,
        "EXPERIENCE_LEVEL": 4,
        "STATUS": 4,
        "EMAIL": 12,
        "WAGE_LEVEL": 2,
        "DNI": 12,
        "ID": 4,
        "ORIGIN": 4,
        "EDUCATION": 4,
        "COMMENT": 12,
        "PROFILE": 4,
        "SURNAME": 12,
        "NAME": 12,
        "BIRTHDAY": 91
    }
}