diff --git a/changelog.txt b/changelog.txt
index f728169b67df87917638ebe67519618a598f70b2..6504a0cad0b39437c22ae6775f530373fb972855 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,10 @@
 eDelivery SMP 5.1
 - Added the HTTP parameter 'Resource-Owner' as alternative to ServiceGroup-Owner
+- added new properties:
+    smp.instance.name: The SMP instance name
+    smp.credentials.reset_request.url: The URL to reset the user password
+    smp.credentials.reset_request.url.validMinutes: The time in minutes the reset request is valid
+
 eDelivery SMP 5.0
 - removed: bdmsl.participant.multidomain.enabled
 - environment properties have now 'smp.' prefix
diff --git a/domismp-tests/domismp-docker/compose/domismp-tomcat-mysql/docker-compose.yml b/domismp-tests/domismp-docker/compose/domismp-tomcat-mysql/docker-compose.yml
index eb1cd7d7636f311d90863201473a7cc372a4c82a..503603ba78ec4dd2e343d25d9d5beceaf17e1d1d 100644
--- a/domismp-tests/domismp-docker/compose/domismp-tomcat-mysql/docker-compose.yml
+++ b/domismp-tests/domismp-docker/compose/domismp-tomcat-mysql/docker-compose.yml
@@ -29,9 +29,9 @@ services:
     volumes:
       - ./properties/db-scripts:/tmp/custom-data/
       - ./properties/keystores:/tmp/keystores/
-#    ports:
+    ports:
 #      - "3908:3306"
-#      - "8982:8080"
+      - "8982:8080"
 #      - "6902:6901"
 #      - "8953:53"
 #      - "5005:5005"
@@ -43,11 +43,11 @@ services:
         - ./eulogin/init-data:/resources/ecas-mock-server
 # Map this folder to host to be able to change runtime data for manual testing!
 #       - ./eulogin/ecas-mock-server:/data/ecas-mock-server
-#    ports:
-#      - "7102:7102"
+    ports:
+      - "7102:7102"
 
   mail-service:
     image: inbucket/inbucket:3.0.0
     hostname: mail-server.smp.local
-#    ports:
-#      - "9005:9000"
+    ports:
+      - "9005:9000"
diff --git a/domismp-tests/domismp-docker/functions/common.functions b/domismp-tests/domismp-docker/functions/common.functions
index 9d618f277161db80994c17c0f97298c884035b13..ebaab5ec57df2c791030701e866cbb508a3f297d 100644
--- a/domismp-tests/domismp-docker/functions/common.functions
+++ b/domismp-tests/domismp-docker/functions/common.functions
@@ -4,6 +4,13 @@
 # running Docker images for the integration tests.
 ################################################################
 
+FUNCTION_FOLDER="$(cd -P $( dirname "${BASH_SOURCE[0]}" ) && pwd)"
+SMP_PROJECT_FOLDER=$(readlink -e "${FUNCTION_FOLDER}/../../..")
+SMP_ARTEFACTS="${SMP_PROJECT_FOLDER}/smp-webapp/target"
+SMP_SPRINGBOOT_ARTEFACTS="${SMP_PROJECT_FOLDER}/smp-springboot/target"
+SMP_PLUGIN_EXAMPLE="${SMP_PROJECT_FOLDER}/smp-examples/smp-spi-payload-validation-example/target"
+SMP_ARTEFACTS_CLEAR="false"
+
 ################################################################
 # Function exports the DomiSMP build specific artefact names.
 exportBuildArtefactNames() {
@@ -34,6 +41,7 @@ function exportImageNames() {
 function initializeCommonVariables() {
     echo "initialize common variables"
     exportImageNames
+    discoverApplicationVersion
 
     BUILD_KEY=$(echo "${bamboo_buildResultKey:-test}" | tr '[:upper:]' '[:lower:]')
     PLAN_PREFIX="${COMPOSE_PROJECT_NAME}"-${BUILD_KEY}
diff --git a/domismp-tests/domismp-docker/images/build-docker-images.sh b/domismp-tests/domismp-docker/images/build-docker-images.sh
index 9405a317867c7e7e8e711ce1cda3b4d40285a4a3..ac6a3cb0653b18d75034dd4f45a632d1bae228a2 100755
--- a/domismp-tests/domismp-docker/images/build-docker-images.sh
+++ b/domismp-tests/domismp-docker/images/build-docker-images.sh
@@ -31,7 +31,6 @@ ORA_VERSION="11.2.0.2"
 ORA_EDITION="xe"
 ORA_SERVICE="xe"
 
-SMP_VERSION=
 ORACLE_ARTEFACTS="/CEF/repo"
 
 SMP_PROJECT_FOLDER=$(readlink -e "${WORKDIR}/../../..")
@@ -61,8 +60,6 @@ while getopts v:o:a:s:c:p: option; do
   esac
 done
 
-# discover SMP  version
-discoverApplicationVersion
 
 echo "*****************************************************************"
 echo "* SMP artefact folders: [$SMP_ARTEFACTS], (Clear folder after build: [$SMP_ARTEFACTS_CLEAR] )"
diff --git a/domismp-tests/domismp-docker/images/domismp-tomcat-mysql/build.sh b/domismp-tests/domismp-docker/images/domismp-tomcat-mysql/build.sh
index 57aaae68e0339839ef3e528fa21c3944eb98c450..a8cabf183a21b9f8ea88a9a2173502a3999185d7 100755
--- a/domismp-tests/domismp-docker/images/domismp-tomcat-mysql/build.sh
+++ b/domismp-tests/domismp-docker/images/domismp-tomcat-mysql/build.sh
@@ -4,12 +4,16 @@
 # first it copies external resources to resources folder
 # then it builds the image using docker-compose.build.yml
 # and finally it cleans the external resources
+WORKING_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "${WORKING_DIR}"
+e
+source "${WORKING_DIR}/../../functions/common.functions"
+initializeCommonVariables
+
 : "${SMP_PROJECT_FOLDER:?Need to set SMP project folder non-empty!}"
 : "${SMP_VERSION:?Need to set SMP version non-empty!}"
 : "${SMP_ARTEFACTS:?Need to set SMP_ARTEFACTS non-empty!}"
 
-WORKING_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-cd "${WORKING_DIR}"
 
 copyExternalImageResources() {
 		echo "Copy test project resources ..."
diff --git a/pom.xml b/pom.xml
index f8a3ce98b9efcb4a37517864ee5a0247f998568d..7eacbe9a0bc65d406bb356b141c713d3c3ed5e2f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -83,7 +83,6 @@ See the Licence for the specific language governing permissions and limitations
         <cxf-xjc-runtime.version>3.3.2</cxf-xjc-runtime.version>
         <cxf.version>3.5.7</cxf.version>
         <ehcache.version>2.10.9.2</ehcache.version>
-        <freemarker.version>2.3.32</freemarker.version>
         <h2.version>2.2.224</h2.version>
         <hamcrest-junit.version>2.0.0.0</hamcrest-junit.version>
         <hamcrest.version>2.2</hamcrest.version>
@@ -256,11 +255,6 @@ See the Licence for the specific language governing permissions and limitations
                 <artifactId>httpclient</artifactId>
                 <version>${httpclient.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.freemarker</groupId>
-                <artifactId>freemarker</artifactId>
-                <version>${freemarker.version}</version>
-            </dependency>
             <dependency>
                 <groupId>org.hibernate.javax.persistence</groupId>
                 <artifactId>hibernate-jpa-2.1-api</artifactId>
diff --git a/smp-angular/src/app/app-info/smp-info.model.ts b/smp-angular/src/app/app-info/smp-info.model.ts
index f6818319c8bd32ee64abf6cb79a2be5c93d113b9..e323183eefeba0f13ec893c6d57e737ee757916d 100644
--- a/smp-angular/src/app/app-info/smp-info.model.ts
+++ b/smp-angular/src/app/app-info/smp-info.model.ts
@@ -4,4 +4,7 @@ export interface SmpInfo {
   authTypes?: string[];
   ssoAuthenticationLabel?: string;
   ssoAuthenticationURI?: string;
+  passwordValidationRegExp?: string;
+  passwordValidationRegExpMessage?: string;
+
 }
diff --git a/smp-angular/src/app/app.component.ts b/smp-angular/src/app/app.component.ts
index 21402f2d79faf6f50d8db513be1dd5fdd901562d..76f0c1f77b595bbce4b3a0bf00073ec0f87ac160 100644
--- a/smp-angular/src/app/app.component.ts
+++ b/smp-angular/src/app/app.component.ts
@@ -99,7 +99,7 @@ export class AppComponent {
 
   onDrawerContentScroll(scrollEvent: any){
     let scrollTop = scrollEvent.srcElement.scrollTop;
-    this.alertService.setSticky(scrollTop > 0)
+    this.alertService.setKeepAfterNavigationChange(scrollTop > 0)
   }
 
 }
diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts
index 28e510d58ebbd3c8edab03acb799743c289526a6..3a62f776bc78d83770585bc8e30a9fbac962a989 100644
--- a/smp-angular/src/app/app.module.ts
+++ b/smp-angular/src/app/app.module.ts
@@ -141,6 +141,7 @@ import {
 } from "./system-settings/admin-properties/property-details-dialog/property-details-dialog.component";
 import {UserAlertsComponent} from "./user-settings/user-alerts/user-alerts.component";
 import {SmpEditorComponent} from "./common/components/smp-editor/smp-editor.component";
+import {ResetCredentialComponent} from "./security/reset-credential/reset-credential.component";
 
 
 @NgModule({
@@ -198,6 +199,7 @@ import {SmpEditorComponent} from "./common/components/smp-editor/smp-editor.comp
     PasswordChangeDialogComponent,
     PropertyComponent,
     PropertyDetailsDialogComponent,
+    ResetCredentialComponent,
     ResourceDetailsDialogComponent,
     ResourceDetailsPanelComponent,
     ResourceDialogComponent,
diff --git a/smp-angular/src/app/app.routes.ts b/smp-angular/src/app/app.routes.ts
index 4fa4c22fb38bff1188bc6814fd96aa51a69b21fc..904ef73261435712e1bd3e1321d4b3f6ee674235 100644
--- a/smp-angular/src/app/app.routes.ts
+++ b/smp-angular/src/app/app.routes.ts
@@ -21,6 +21,7 @@ import {authorizeChildSystemAdminGuard} from "./guards/authorize-child-system-ad
 import {activateChildResourceGuard} from "./guards/activate-child-document.guard";
 import {UserAlertsComponent} from "./user-settings/user-alerts/user-alerts.component";
 import {AdminAlertsComponent} from "./system-settings/admin-alerts/admin-alerts.component";
+import {ResetCredentialComponent} from "./security/reset-credential/reset-credential.component";
 
 
 const appRoutes: Routes = [
@@ -28,6 +29,7 @@ const appRoutes: Routes = [
   {path: '', component: ResourceSearchComponent},
   {path: 'search', redirectTo: ''},
   {path: 'login', component: LoginComponent},
+  {path: 'reset-credential/:resetToken', component: ResetCredentialComponent},
   {
     path: 'edit',
     canActivateChild: [authenticationGuard],
diff --git a/smp-angular/src/app/common/alert-message/alert-message.component.html b/smp-angular/src/app/common/alert-message/alert-message.component.html
index f16cb684cf8c90f2f19e10def611fd26cadae4b0..87883c0bf9833afb25c4ea68b1ff378968713f91 100644
--- a/smp-angular/src/app/common/alert-message/alert-message.component.html
+++ b/smp-angular/src/app/common/alert-message/alert-message.component.html
@@ -1,6 +1,8 @@
 <div #alertMessage class="mat-elevation-z8"
   *ngIf="message" [ngClass]="{ 'alert-message': message,
   'alert-success': message.type === 'success',
+  'alert-info': message.type === 'info',
+  'alert-warning': message.type === 'warning',
   'alert-error': message.type === 'error'}"
      id="alertmessage_id">
   <span class="closebtn" (click)="clearAlert(true)">&times;</span>
diff --git a/smp-angular/src/app/common/alert-message/alert-message.component.ts b/smp-angular/src/app/common/alert-message/alert-message.component.ts
index 3c750bea7877d484a3abacadff5f9b994a5952be..35f3e179a773b31f7dbb3d88a92915e12233d3e6 100644
--- a/smp-angular/src/app/common/alert-message/alert-message.component.ts
+++ b/smp-angular/src/app/common/alert-message/alert-message.component.ts
@@ -2,16 +2,21 @@ import {Component, OnDestroy, OnInit} from '@angular/core';
 import {AlertMessageService} from './alert-message.service';
 import {Subscription} from "rxjs";
 
+
+/**
+ * This component is used to display alert messages/notifications on the top of the page in an overlay (growl).
+ * In case of success messages, the message will be displayed for a certain amount of time and it will automatically disappear
+ * unless sticky flat is set to true.
+ *
+ * The messages can be of different types: success, error, info, warning.
+ */
 @Component({
   selector: 'alert',
   templateUrl: './alert-message.component.html',
   styleUrls: ['./alert-message.component.css']
 })
-
 export class AlertMessageComponent implements OnInit, OnDestroy {
 
-  readonly successTimeout: number = 3000;
-
   message: any;
 
   private subscription: Subscription;
@@ -20,23 +25,25 @@ export class AlertMessageComponent implements OnInit, OnDestroy {
   }
 
   ngOnInit() {
-    this.subscription = this.alertService.getMessage().subscribe(message => { this.showMessage(message); });
+    this.subscription = this.alertService.getMessage().subscribe(message => {
+      this.showMessage(message);
+    });
   }
 
   ngOnDestroy(): void {
     this.subscription.unsubscribe();
   }
 
-  clearAlert(force = false):void {
+  clearAlert(force = false): void {
     this.alertService.clearAlert(force);
   }
 
   showMessage(message: any) {
     this.message = message;
-    if (message && message.type && message.type === 'success') {
+    if (message && message.timeoutInSeconds && message.timeoutInSeconds > 0) {
       setTimeout(() => {
         this.clearAlert();
-      }, this.successTimeout);
+      }, this.message.timeoutInSeconds * 1000);
     }
   }
 }
diff --git a/smp-angular/src/app/common/alert-message/alert-message.service.ts b/smp-angular/src/app/common/alert-message/alert-message.service.ts
index 335493add72145eaabc22c5d01ccd4ac5628d629..09e66f237c487b9c52ec8dcb887efb15c5e7d754 100644
--- a/smp-angular/src/app/common/alert-message/alert-message.service.ts
+++ b/smp-angular/src/app/common/alert-message/alert-message.service.ts
@@ -1,30 +1,40 @@
 import {Injectable} from '@angular/core';
 import {NavigationEnd, NavigationStart, Router} from '@angular/router';
 import {Observable, Subject} from 'rxjs';
+import {HttpErrorResponse} from "@angular/common/http";
+
+/**
+ * AlertMessageRO is the object that will be used to display the message in the SMP alert component in overlay.
+ * These messages are not the same to SMP alerts, which are used to display alert the page.
+ * It contains the type of the message (success, error, info, warning), the text of the message and the timeout in seconds.
+ */
+export interface AlertMessageRO {
+  type: string,
+  text: string,
+  timeoutInSeconds?: number
+}
 
 @Injectable()
 export class AlertMessageService {
-  private subject = new Subject<any>();
-
-  private previousRoute = '';
 
-  private sticky = false;
+  // the default timeout duration
+  readonly DEFAULT_TIMEOUT: number = 3;
 
-  private message: { type: string, text: string };
+  private subject = new Subject<any>();
+  private previousRoute:string = '';
+  private keepAfterNavigationChange:boolean = false;
+  private message: AlertMessageRO;
 
-  //TODO move the logic in the ngInit block
-  constructor (private router: Router) {
+  constructor(private router: Router) {
     // clear alert message on route change
     router.events.subscribe(event => {
       if (event instanceof NavigationStart) {
         if (this.isRouteChanged(event.url)) {
           this.clearAlert();
-        } else {
-          console.log('Alert after when navigating from [' + this.previousRoute + '] to [' + event.url + ']');
         }
       } else if (event instanceof NavigationEnd) {
         this.previousRoute = event.url;
-        if (this.sticky) {
+        if (this.keepAfterNavigationChange) {
           this.displayCurrentMessage();
           this.reset();
         }
@@ -32,56 +42,102 @@ export class AlertMessageService {
     });
   }
 
-  private reset () {
-    this.sticky = false;
+  private reset() {
+    this.keepAfterNavigationChange = false;
     this.message = null;
   }
 
-  getPath (url: string): string {
+  getPath(url: string): string {
     const parser = document.createElement('a');
     parser.href = url;
     return parser.pathname;
   }
 
-  isRouteChanged (currentRoute: string): boolean {
+  isRouteChanged(currentRoute: string): boolean {
     let previousRoutePath = this.getPath(this.previousRoute);
     let currentRoutePath = this.getPath(currentRoute);
     return previousRoutePath !== currentRoutePath;
   }
 
-  clearAlert (force = false): void {
-    if (!force && this.sticky) {
+  clearAlert(force = false): void {
+    if (!force && this.keepAfterNavigationChange) {
       return;
     }
     this.subject.next(null);
   }
 
-  setSticky (sticky: boolean) {
-    this.sticky = sticky;
+  setKeepAfterNavigationChange(keepAfterNavigation: boolean) {
+    this.keepAfterNavigationChange = keepAfterNavigation;
   }
 
-  displayCurrentMessage () {
+  displayCurrentMessage() {
     this.subject.next(this.message);
   }
 
-  success (message: string, keepAfterNavigationChange = false) {
-    this.setSticky(keepAfterNavigationChange);
-    this.message = {type: 'success', text: message};
-    this.displayCurrentMessage();
+  /**
+   * Extract the message from the object return it as a string. The object can be a string or an HttpErrorResponse
+   *
+   * @param messageObject
+   */
+  getObjectMessage(messageObject: any): string {
+    let message = 'An error occurred';
+    if (typeof messageObject === 'string') {
+      return messageObject;
+    }
+    if (messageObject instanceof HttpErrorResponse) {
+      return this.getHttpErrorResponseMessage(messageObject);
+    }
   }
 
-  error (message: string, keepAfterNavigationChange = false) {
-    this.setSticky(keepAfterNavigationChange);
-    this.message = {type: 'error', text: message};
+  /**
+   * Extract the message from the HttpErrorResponse and return it as a string
+   * @param httpErrorResponse
+   */
+  getHttpErrorResponseMessage(httpErrorResponse: HttpErrorResponse): string {
+    let message: string;
+    if (httpErrorResponse.error) {
+      if (httpErrorResponse.error.errorDescription) {
+        message = httpErrorResponse.error.errorDescription;
+      } else if (httpErrorResponse.error.message) {
+        message = httpErrorResponse.error.message;
+      }
+    } else {
+      message = httpErrorResponse.statusText + ': ' + httpErrorResponse.message;
+    }
+    return message;
+  }
+
+  /**
+   * Show a message of a given type
+   * @param messageObject The message to display
+   * @param type The type of the message (success, error, info, warning)
+   * @param keepAfterNavigationChange If true, the message will be displayed after a navigation changed
+   */
+  showMessage(messageObject: any, type: string, keepAfterNavigationChange:boolean = false, timeoutInSeconds: number = null) {
+    this.setKeepAfterNavigationChange(keepAfterNavigationChange);
+    this.message = {
+      type: type,
+      text: this.getObjectMessage(messageObject),
+      // if the timeoutInSeconds is not set, we use the default timeout for success messages
+      timeoutInSeconds: !timeoutInSeconds && type =="success" ?this.DEFAULT_TIMEOUT: timeoutInSeconds
+    };
     this.displayCurrentMessage();
   }
 
-  exception (message: string, error: any, keepAfterNavigationChange = false): void {
-    const errMsg = error.message || (error.json ? error.json().message : error );
+  success(message: string, keepAfterNavigationChange = false, timeoutInSeconds: number = null) {
+    this.showMessage(message, 'success', keepAfterNavigationChange, timeoutInSeconds);
+  }
+
+  error(message: any, keepAfterNavigationChange = false, timeoutInSeconds: number = null) {
+    this.showMessage(message, 'error', keepAfterNavigationChange, timeoutInSeconds);
+  }
+
+  exception(message: string, error: any, keepAfterNavigationChange = false): void {
+    const errMsg = error.message || (error.json ? error.json().message : error);
     this.error(message + ' \n' + errMsg, keepAfterNavigationChange);
   }
 
-  getMessage (): Observable<any> {
+  getMessage(): Observable<any> {
     return this.subject.asObservable();
   }
 }
diff --git a/smp-angular/src/app/login/login.component.css b/smp-angular/src/app/login/login.component.css
index bb1da45b6e5c3d2d6c64b0911b4149e3e5346221..a55eafa0c9e28f96d33ac2bc638964dce938cfdf 100644
--- a/smp-angular/src/app/login/login.component.css
+++ b/smp-angular/src/app/login/login.component.css
@@ -3,4 +3,7 @@ a:visited { text-decoration: none; }
 a:hover { text-decoration: none; }
 a:active { text-decoration: none; }
 
-
+.form-control {
+  margin: 10px;
+  padding: 0;
+}
diff --git a/smp-angular/src/app/login/login.component.html b/smp-angular/src/app/login/login.component.html
index 632241d25f489baf026fb09449fde8c045feaaee..22adfe456c3da5b5c2d9bd3ddc8cdc1da2c97f8c 100644
--- a/smp-angular/src/app/login/login.component.html
+++ b/smp-angular/src/app/login/login.component.html
@@ -1,7 +1,8 @@
 <div id="page" class="login-page" [style]="'justify-content:center; align-items:center; height:100%'">
   <div fxLayout="row" [style]="'justify-content:center; align-items:center; height:100%'">
-    <mat-card *ngIf="isUserAuthSSOEnabled()  == true" fxFlex="400px" [style]="'width:400px;height:300px;margin:10px'">
-      <mat-card-title class="title-panel"  >SSO Login: {{lookups.cachedApplicationInfo.ssoAuthenticationLabel}}</mat-card-title>
+    <mat-card *ngIf="isUserAuthSSOEnabled()  == true" fxFlex="400px" [style]="'width:400px;height:240px;margin:10px'">
+      <mat-card-title class="title-panel">SSO Login: {{ lookups.cachedApplicationInfo.ssoAuthenticationLabel }}
+      </mat-card-title>
       <mat-card-content style="align-items: center;justify-content: center;display: flex;height: 200px;">
         <a mat-raised-button color="primary" href="{{lookups.cachedApplicationInfo.ssoAuthenticationURI}}"
            [style]="'width:150px'">
@@ -10,32 +11,62 @@
         </a>
       </mat-card-content>
     </mat-card>
-    <mat-card *ngIf="isUserAuthPasswdEnabled() == true" fxFlex="400px" [style]="'width:400px;height:300px;margin:10px;'">
+    <mat-card *ngIf="isUserAuthPasswdEnabled() == true">
       <mat-card-title class="title-panel">SMP Login</mat-card-title>
-      <mat-card-content style="align-items: center;justify-content: center;display: flex;flex-direction:column; height: 200px;">
-        <form name="loginForm" #loginForm="ngForm" (ngSubmit)="login()">
-                <mat-form-field style="width: 100%">
-                  <mat-label>Username</mat-label>
-                  <input matInput placeholder="Username" name="username" [(ngModel)]="model.username"
-                         #username="ngModel"
-                         id="username_id"
-                         auto-focus-directive
-                         required>
-                </mat-form-field>
-                <mat-form-field style="width: 100%">
-                  <mat-label>Password</mat-label>
-                  <input type="password" matInput placeholder="Password" name="password" [(ngModel)]="model.password"
-                         #password="ngModel" required id="password_id">
-                </mat-form-field>
-
-                <button mat-raised-button color="primary" [disabled]="!loginForm.form.valid" id="loginbutton_id"
-                        [style]="'width:150px'">
-                  <mat-icon>input</mat-icon>
-                  <span> Login</span>
-                </button>
-        </form>
+      <mat-card-content style="width:380px; height: 260px;margin: 15px">
+        <mat-tab-group>
+          <mat-tab label="Login">
+            <ng-container *ngTemplateOutlet="loginFormContainer"></ng-container>
+          </mat-tab>
+          <mat-tab label="Request password reset">
+            <ng-container *ngTemplateOutlet="requestResetContainer"></ng-container>
+          </mat-tab>
+        </mat-tab-group>
       </mat-card-content>
     </mat-card>
   </div>
   <footer></footer>
 </div>
+
+
+<ng-template #loginFormContainer>
+  <div [formGroup]="loginForm" class="form-control">
+    <mat-form-field style="width: 100%">
+      <mat-label>Username</mat-label>
+      <input matInput id="username_id"
+             formControlName="username"
+             auto-focus-directive
+             required>
+    </mat-form-field>
+    <mat-form-field style="width: 100%">
+      <mat-label>Password</mat-label>
+      <input matInput id="password_id" type="password"
+             formControlName="password" required>
+    </mat-form-field>
+    <button mat-raised-button color="primary" id="loginbutton_id" [disabled]="!loginForm.valid"
+            (click)="login()"
+            [style]="'width:250px'">
+      <mat-icon>input</mat-icon>
+      <span> Login</span>
+    </button>
+  </div>
+</ng-template>
+
+<ng-template #requestResetContainer>
+  <div [formGroup]="resetForm" class="form-control">
+    <mat-form-field style="width: 100%">
+      <mat-label>Username</mat-label>
+      <input matInput id="reset_username_id"
+             formControlName="resetUsername"
+             auto-focus-directive
+             required>
+    </mat-form-field>
+    <button mat-raised-button color="primary" id="resetbutton_id" [disabled]="!resetForm.valid"
+            [style]="'width:250px'"
+            (click)="requestCredentialReset()"
+    >
+      <mat-icon>input</mat-icon>
+      <span> Request reset password</span>
+    </button>
+    </div>
+</ng-template>
diff --git a/smp-angular/src/app/login/login.component.ts b/smp-angular/src/app/login/login.component.ts
index 9755a5313c6464a6761cf85b1b0ff41973a6a786..8d654d359f03a5b6a3a7e800424ffb62d26814a5 100644
--- a/smp-angular/src/app/login/login.component.ts
+++ b/smp-angular/src/app/login/login.component.ts
@@ -1,5 +1,5 @@
 import {Component, OnDestroy, OnInit} from '@angular/core';
-import {Router, ActivatedRoute} from '@angular/router';
+import {ActivatedRoute, Router} from '@angular/router';
 import {SecurityService} from '../security/security.service';
 import {AlertMessageService} from '../common/alert-message/alert-message.service';
 import {SecurityEventService} from '../security/security-event.service';
@@ -7,12 +7,15 @@ import {User} from '../security/user.model';
 import {MatDialog} from '@angular/material/dialog';
 import {DefaultPasswordDialogComponent} from 'app/security/default-password-dialog/default-password-dialog.component';
 import {Subscription} from 'rxjs';
-import {ExpiredPasswordDialogComponent} from '../common/dialogs/expired-password-dialog/expired-password-dialog.component';
+import {
+  ExpiredPasswordDialogComponent
+} from '../common/dialogs/expired-password-dialog/expired-password-dialog.component';
 import {GlobalLookups} from "../common/global-lookups";
 import {PasswordChangeDialogComponent} from "../common/dialogs/password-change-dialog/password-change-dialog.component";
 import {InformationDialogComponent} from "../common/dialogs/information-dialog/information-dialog.component";
 import {formatDate} from "@angular/common";
 import {EntityStatus} from "../common/enums/entity-status.enum";
+import {FormControl, FormGroup, Validators} from "@angular/forms";
 
 @Component({
   templateUrl: './login.component.html',
@@ -20,7 +23,8 @@ import {EntityStatus} from "../common/enums/entity-status.enum";
 })
 export class LoginComponent implements OnInit, OnDestroy {
 
-  model: any = {};
+  loginForm: FormGroup;
+  resetForm: FormGroup;
   loading = false;
   returnUrl: string;
   sub: Subscription;
@@ -35,14 +39,21 @@ export class LoginComponent implements OnInit, OnDestroy {
               private dialog: MatDialog) {
   }
 
+
   ngOnInit() {
+    this.initForm();
     this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
 
     this.sub = this.securityEventService.onLoginSuccessEvent().subscribe(
       user => {
         if (user && user.passwordExpired) {
           if (user.forceChangeExpiredPassword) {
-            this.dialog.open(PasswordChangeDialogComponent, {data: {user:user,adminUser:false}}).afterClosed().subscribe(res =>
+            this.dialog.open(PasswordChangeDialogComponent, {
+              data: {
+                user: user,
+                adminUser: false
+              }
+            }).afterClosed().subscribe(res =>
               this.securityService.finalizeLogout(res)
             );
           } else {
@@ -66,7 +77,7 @@ export class LoginComponent implements OnInit, OnDestroy {
         switch (error.status) {
           case HTTP_UNAUTHORIZED:
             message = error.error.errorDescription;
-            this.model.password = '';
+            this.loginForm['password'].setValue('');
             break;
           case HTTP_FORBIDDEN:
             const forbiddenCode = error.message;
@@ -77,7 +88,7 @@ export class LoginComponent implements OnInit, OnDestroy {
               default:
                 message = error.status + ' The username/password combination you provided are not valid. Please try again or contact your administrator.';
                 // clear the password
-                this.model.password = '';
+                this.loginForm['password'].setValue('');
                 break;
             }
             break;
@@ -93,40 +104,50 @@ export class LoginComponent implements OnInit, OnDestroy {
       });
   }
 
+  private initForm() {
+    this.loginForm = new FormGroup({
+      username: new FormControl('', Validators.required),
+      password: new FormControl('', Validators.required),
+    });
+
+    this.resetForm = new FormGroup({
+      resetUsername: new FormControl('', Validators.required),
+    });
+
+  }
+
   login() {
-    // clear alerts
     this.alertService.clearAlert();
-    this.securityService.login(this.model.username, this.model.password);
+    if (this.loginForm.valid) {
+      this.securityService.login(
+        this.loginForm.get('username').value,
+        this.loginForm.get('password').value
+      );
+    } else {
+      this.alertService.error('Please enter a valid username and password.');
+    }
+  }
+
+  requestCredentialReset() {
+    this.alertService.clearAlert();
+    if (this.resetForm.valid) {
+      this.securityService.requestCredentialReset(
+        this.resetForm.get('resetUsername').value
+      );
+    } else {
+      this.alertService.error('Please enter a valid username.');
+    }
   }
 
   showWarningBeforeExpire(user: User) {
     this.dialog.open(InformationDialogComponent, {
       data: {
         title: "Warning! Your password is about to expire",
-        description: "Your password is about to expire on " + formatDate(user.passwordExpireOn,"longDate","en-US")+"! Please change the password before the expiration date!"
+        description: "Your password is about to expire on " + formatDate(user.passwordExpireOn, "longDate", "en-US") + "! Please change the password before the expiration date!"
       }
     }).afterClosed().subscribe(() => this.router.navigate([this.returnUrl]));
   }
 
-  verifyDefaultLoginUsed() {
-    const currentUser: User = this.securityService.getCurrentUser();
-    if (currentUser.defaultPasswordUsed) {
-      this.dialog.open(DefaultPasswordDialogComponent);
-    }
-  }
-
-  private convertWithMode(config) {
-    return (config && config.data)
-      ? {
-        ...config,
-        data: {
-          ...config.data,
-          mode: config.data.mode || (config.data.edit ? EntityStatus.PERSISTED :EntityStatus.NEW)
-        }
-      }
-      : config;
-  }
-
   ngOnDestroy(): void {
     this.sub.unsubscribe();
   }
diff --git a/smp-angular/src/app/security/reset-credential/reset-credential.component.css b/smp-angular/src/app/security/reset-credential/reset-credential.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..a55eafa0c9e28f96d33ac2bc638964dce938cfdf
--- /dev/null
+++ b/smp-angular/src/app/security/reset-credential/reset-credential.component.css
@@ -0,0 +1,9 @@
+a:link { text-decoration: none; }
+a:visited { text-decoration: none; }
+a:hover { text-decoration: none; }
+a:active { text-decoration: none; }
+
+.form-control {
+  margin: 10px;
+  padding: 0;
+}
diff --git a/smp-angular/src/app/security/reset-credential/reset-credential.component.html b/smp-angular/src/app/security/reset-credential/reset-credential.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..6ca111f0e3a0eebfd80e0ccfabb67153987393a0
--- /dev/null
+++ b/smp-angular/src/app/security/reset-credential/reset-credential.component.html
@@ -0,0 +1,56 @@
+<div id="page" class="login-page" [style]="'justify-content:center; align-items:center; height:100%'">
+  <div fxLayout="row" [style]="'justify-content:center; align-items:center; height:100%'">
+    <div [formGroup]="resetForm" class="form-control">
+
+      <div style="display:flex;flex-direction: column;">
+        <mat-form-field style="width:100%">
+          <mat-label>Enter Username</mat-label>
+          <input matInput formControlName="resetUsername" id="reset_username_id" required auto-focus-directive>
+        </mat-form-field>
+
+        <mat-form-field style="width:100%">
+          <mat-label>New Password</mat-label>
+          <input matInput [type]="hideNewPwdFiled ? 'password' : 'text'"
+                 formControlName="new-password" id="np_id" required>
+          <mat-icon matSuffix
+                    (click)="hideNewPwdFiled = !hideNewPwdFiled">{{ hideNewPwdFiled ? 'visibility_off' : 'visibility' }}
+          </mat-icon>
+          <smp-field-error *ngIf="passwordError('new-password', 'error')">New password must not be equal than old
+            current
+            password!
+          </smp-field-error>
+          <smp-field-error *ngIf="passwordError('new-password', 'pattern')">{{ passwordValidationMessage }}
+          </smp-field-error>
+        </mat-form-field>
+        <mat-form-field style="width:100%">
+          <mat-label>Confirm New Password</mat-label>
+          <input matInput [type]="hideConfPwdFiled ? 'password' : 'text'"
+                 formControlName="confirm-new-password" id="cnp_id" required>
+          <mat-icon matSuffix
+                    (click)="hideConfPwdFiled = !hideConfPwdFiled">{{ hideConfPwdFiled ? 'visibility_off' : 'visibility' }}
+          </mat-icon>
+          <smp-field-error *ngIf="passwordError('confirm-new-password', 'error')">Confirm valued does not match new
+            password!
+          </smp-field-error>
+        </mat-form-field>
+
+        <div class="required-fields">* required fields</div>
+      </div>
+      <mat-toolbar-row>
+        <button id="changeCurrentUserPasswordButton" mat-raised-button color="primary"
+                (click)="resetPassword()"
+                [disabled]="!resetForm.valid ">
+          <mat-icon>check_circle</mat-icon>
+          <span>Set/change password</span>
+        </button>
+        <button id="closeDialogButton" mat-raised-button color="primary"
+                (click)="cancel()"
+                mat-dialog-close>
+          <mat-icon>cancel</mat-icon>
+          <span>Cancel</span>
+        </button>
+      </mat-toolbar-row>
+    </div>
+  </div>
+  <footer></footer>
+</div>
diff --git a/smp-angular/src/app/security/reset-credential/reset-credential.component.ts b/smp-angular/src/app/security/reset-credential/reset-credential.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0cc71994349c489660301ad59cc7a2e1907c255b
--- /dev/null
+++ b/smp-angular/src/app/security/reset-credential/reset-credential.component.ts
@@ -0,0 +1,72 @@
+import {Component, OnInit} from '@angular/core';
+import {ActivatedRoute, Router} from '@angular/router';
+import {FormGroup, UntypedFormControl, Validators} from "@angular/forms";
+import {GlobalLookups} from "../../common/global-lookups";
+import {equal} from "../../common/dialogs/password-change-dialog/password-change-dialog.component";
+import {SecurityService} from "../security.service";
+
+@Component({
+  templateUrl: './reset-credential.component.html',
+  styleUrls: ['./reset-credential.component.css']
+})
+export class ResetCredentialComponent implements OnInit {
+
+  resetForm: FormGroup;
+  resetToken: string
+
+  hideNewPwdFiled: boolean = true;
+  hideConfPwdFiled: boolean = true;
+
+  constructor(private router: Router,
+              private activatedRoute: ActivatedRoute,
+              private lookups: GlobalLookups,
+              private securityService: SecurityService) {
+  }
+
+
+  ngOnInit() {
+    this.initForm();
+    this.resetToken = this.activatedRoute.snapshot.params['resetToken'];
+  }
+
+  private initForm() {
+
+    let newPasswdFormControl: UntypedFormControl = new UntypedFormControl({value: null, readonly: false},
+      [Validators.required, Validators.pattern(this.passwordValidationRegExp)]);
+    let confirmNewPasswdFormControl: UntypedFormControl = new UntypedFormControl({value: null, readonly: false},
+      [Validators.required, equal(newPasswdFormControl, true)]);
+
+    this.resetForm = new FormGroup({
+      'resetUsername': new UntypedFormControl({value: null, readonly: true}, null),
+      'new-password': newPasswdFormControl,
+      'confirm-new-password': confirmNewPasswdFormControl
+    });
+
+    this.resetForm.controls['resetUsername'].setValue("");
+    this.resetForm.controls['new-password'].setValue("");
+    this.resetForm.controls['confirm-new-password'].setValue("");
+  }
+
+  public passwordError = (controlName: string, errorName: string) => {
+    return this.resetForm.controls[controlName].hasError(errorName);
+  }
+
+  get passwordValidationMessage() {
+    return this.lookups.cachedApplicationInfo?.passwordValidationRegExpMessage;
+  }
+
+
+  get passwordValidationRegExp() {
+    return this.lookups.cachedApplicationInfo?.passwordValidationRegExp;
+  }
+
+  public resetPassword() {
+    this.securityService.credentialReset(this.resetForm.controls['resetUsername'].value,
+      this.resetToken,
+      this.resetForm.controls['new-password'].value,);
+  }
+
+  public cancel() {
+    this.router.navigate(['/search']);
+  }
+}
diff --git a/smp-angular/src/app/security/security.service.ts b/smp-angular/src/app/security/security.service.ts
index e96b7d035082c4cd563ea8bc3a865f4e2c13c115..1357e43d2e8f343e0cc48f7d437b378e88cb533e 100644
--- a/smp-angular/src/app/security/security.service.ts
+++ b/smp-angular/src/app/security/security.service.ts
@@ -33,13 +33,51 @@ export class SecurityService {
         password: password
       }),
       {headers})
-      .subscribe((response: User) => {
+      .subscribe({
+        next: (response: User) => {
           this.updateUserDetails(response);
           this.securityEventService.notifyLoginSuccessEvent(response);
         },
-        (error: any) => {
+        error: (error: any) => {
+          this.alertService.error(error.error?.errorDescription)
           this.securityEventService.notifyLoginErrorEvent(error);
-        });
+        }
+      });
+  }
+
+  requestCredentialReset(userid: string) {
+    let headers: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
+    return this.http.post<User>(SmpConstants.REST_PUBLIC_SECURITY_RESET_CREDENTIALS_REQUEST,
+      JSON.stringify({
+        credentialName: userid,
+        credentialType: 'USERNAME_PASSWORD',
+      }),
+      {headers})
+      .subscribe({
+        complete: () => {  }, // completeHandler
+        error: (error: any) => {this.alertService.error(error) },    // errorHandler
+        next: () => { this.alertService.success("A confirmation email has been sent to your registered email address for user ["+userid+"]. " +
+          "Please follow the instructions in the email to complete the account reset process. " +
+          "If you did not receive mail try later or contact administrator  ", true, -1);
+          this.router.navigate(['/search']);}
+      });
+  }
+
+  credentialReset(userid: string, token: string, newPassword: string) {
+    let headers: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
+    return this.http.post<User>(SmpConstants.REST_PUBLIC_SECURITY_RESET_CREDENTIALS,
+      JSON.stringify({
+        credentialName: userid,
+        credentialValue: newPassword,
+        credentialType: 'USERNAME_PASSWORD',
+        resetToken: token,
+      }),
+      {headers})
+      .subscribe({
+        complete: () => { this.router.navigate(['/login']); }, // completeHandler
+        error: (error: any) => {this.alertService.error(error);this.router.navigate(['/login']); },    // errorHandler
+        next: () => { this.alertService.success("Password has been reset successfully. Please login with new password", true, -1);}
+      });
   }
 
   refreshLoggedUserFromServer() {
diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts
index 4b5364f18acba3c8067b030220f859bad397b1bb..23e75fb4bd6a59c1cd3d31be991de18acd08f2bc 100644
--- a/smp-angular/src/app/smp.constants.ts
+++ b/smp-angular/src/app/smp.constants.ts
@@ -149,7 +149,10 @@ export class SmpConstants {
 
   // public authentication services
   public static readonly REST_PUBLIC_SECURITY = SmpConstants.REST_PUBLIC + 'security/';
-  public static readonly REST_PUBLIC_SECURITY_AUTHENTICATION = SmpConstants.REST_PUBLIC_SECURITY + 'authentication';
+  public static readonly REST_PUBLIC_SECURITY_AUTHENTICATION = SmpConstants.REST_PUBLIC_SECURITY + 'authentication'
+  public static readonly REST_PUBLIC_SECURITY_RESET_CREDENTIALS_REQUEST = SmpConstants.REST_PUBLIC_SECURITY + 'request-reset-credential';
+  public static readonly REST_PUBLIC_SECURITY_RESET_CREDENTIALS = SmpConstants.REST_PUBLIC_SECURITY + 'reset-credential';
+
   public static readonly REST_PUBLIC_SECURITY_USER = SmpConstants.REST_PUBLIC_SECURITY + 'user';
 
   //------------------------------
diff --git a/smp-angular/src/index.html b/smp-angular/src/index.html
index 3e795761c8c839b6c21c0062fe5013d55df1065d..f85af98deaed4b3574f8813d6c0c9d9fb3f87bf2 100644
--- a/smp-angular/src/index.html
+++ b/smp-angular/src/index.html
@@ -11,7 +11,6 @@
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
   <link href="assets/stylesheets/angularMaterial2Icons.css" rel="stylesheet">
-  <link href="assets/stylesheets/codeMirror.css" rel="stylesheet">
 </head>
   <body class="mat-app-background">
     <app-root>Loading...</app-root>
diff --git a/smp-server-library/pom.xml b/smp-server-library/pom.xml
index 59a9b583d9effe34e32ea465b25779752c09ceae..a0702d784661dfc71322c4f920d6d062273b6cc3 100644
--- a/smp-server-library/pom.xml
+++ b/smp-server-library/pom.xml
@@ -80,10 +80,6 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-context-support</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.freemarker</groupId>
-            <artifactId>freemarker</artifactId>
-        </dependency>
         <dependency>
             <groupId>com.sun.mail</groupId>
             <artifactId>javax.mail</artifactId>
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/ServicesBeansConfiguration.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/ServicesBeansConfiguration.java
index b96effa60e6af288675fdc120ec0e3f780c89aad..360849ee0e1100c64a4c741506276c0017442d0d 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/ServicesBeansConfiguration.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/ServicesBeansConfiguration.java
@@ -8,9 +8,9 @@
  * versions of the EUPL (the "Licence");
  * You may not use this work except in compliance with the Licence.
  * You may obtain a copy of the Licence at:
- * 
+ *
  * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
  * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the Licence for the specific language governing permissions and limitations under the Licence.
@@ -18,12 +18,10 @@
  */
 package eu.europa.ec.edelivery.smp.config;
 
-import freemarker.cache.ClassTemplateLoader;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.mail.javamail.JavaMailSenderImpl;
-import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
 
 @Configuration
 @ComponentScan(basePackages = {
@@ -40,11 +38,4 @@ public class ServicesBeansConfiguration {
         return new JavaMailSenderImpl();
     }
 
-    @Bean
-    public FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean() {
-        final FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean =
-                new FreeMarkerConfigurationFactoryBean();
-        freeMarkerConfigurationFactoryBean.setPreTemplateLoaders(new ClassTemplateLoader(ServicesBeansConfiguration.class, "/alert-mail-templates"));
-        return freeMarkerConfigurationFactoryBean;
-    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java
index beefba86ee3d740251b61f3ce61ba09c2b5cbc30..7a8bec80e9b843ce110d499a62e295374be661a7 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java
@@ -383,10 +383,20 @@ public enum SMPPropertyEnum {
             OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, INTEGER),
     SMP_ALERT_MAIL_FROM("smp.alert.mail.from", "test@alert-send-mail.eu", "Alert send mail",
             OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, EMAIL),
+
+
+    SMP_INSTANCE_NAME("smp.instance.name", "Test DomiSMP Instance", "The name of the SMP instance",
+            OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, STRING),
+
+    CREDENTIALS_RESET_URL("smp.credentials.reset_request.url", null, "If null then the reset url is created using the the proxy headers.",
+            OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, URL),
+
+    CREDENTIALS_RESET_POLICY_VALID_DAYS("smp.credentials.reset_request.url.validMinutes", "90", "Number of minutes token is valid",
+            OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, INTEGER),
+
     // deprecated properties
     CLIENT_CERT_HEADER_ENABLED_DEPRECATED("authentication.blueCoat.enabled", "false", "Property was replaced by property: smp.automation.authentication.external.tls.clientCert.enabled",
             OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, BOOLEAN),
-
     PARTC_EBCOREPARTYID_CONCATENATE("identifiersBehaviour.ParticipantIdentifierScheme.ebCoreId.concatenate", "false",
             "Concatenate ebCore party id in XML responses <ParticipantIdentifier>urn:oasis:names:tc:ebcore:partyid-type:unregistered:test-ebcore-id</ParticipantIdentifier>",
             OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, BOOLEAN),
@@ -394,16 +404,15 @@ public enum SMPPropertyEnum {
     ;
 
 
-    String property;
-    String defValue;
-    String desc;
-    Pattern valuePattern;
-    String errorValueMessage;
-
-    boolean isEncrypted;
-    boolean isMandatory;
-    boolean restartNeeded;
-    SMPPropertyTypeEnum propertyType;
+    private final String property;
+    private final String defValue;
+    private final String desc;
+    private final Pattern valuePattern;
+    private final String errorValueMessage;
+    private final boolean isEncrypted;
+    private final boolean isMandatory;
+    private final boolean restartNeeded;
+    private final SMPPropertyTypeEnum propertyType;
 
     SMPPropertyEnum(String property, String defValue, String desc, boolean isMandatory, boolean isEncrypted, boolean restartNeeded,
                     SMPPropertyTypeEnum propertyType, String valuePattern, String errorValueMessage) {
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java
index faf5a831d4b16a302c7292ff5610f3485f88f962..ef9a8bc00f46b757b80f331f1e0a57a1fbed404f 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java
@@ -24,6 +24,7 @@ import eu.europa.ec.edelivery.smp.exceptions.SMPTestIsALiveException;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.springframework.core.GenericTypeResolver;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -190,7 +191,6 @@ public abstract class BaseDao<E extends BaseEntity> {
             }
         }
 
-
         // set order by
         if (searchParams != null) {
             List<Predicate> lstPredicate = createPredicates(searchParams, om, cb);
@@ -250,7 +250,8 @@ public abstract class BaseDao<E extends BaseEntity> {
                         cls.getMethod("set" + fieldName, m.getReturnType());
                     } catch (NoSuchMethodException | SecurityException ex) {
                         // method does not have setter // ignore other methods
-                        LOG.error("Field '" + fieldName + "' does not have a setter!", ex);
+                        LOG.warn("Can not set value [{}] to entity [{}]! Search parameter is ignored!. Root cause: [{}]",
+                                fieldName, om.getModel(), ExceptionUtils.getRootCauseMessage(ex));
                         continue;
                     }
 
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBCredential.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBCredential.java
index 401a280a0ad378a1f55643d8b40c5affcb4f7ff4..26676e46d4ed69133a0d0993e97ab7b3d77595fb 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBCredential.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBCredential.java
@@ -130,18 +130,20 @@ public class DBCredential extends BaseEntity {
     @Column(name = "LAST_FAILED_LOGIN_ON")
     @ColumnDescription(comment = "Last failed login attempt")
     private OffsetDateTime lastFailedLoginAttempt;
-
     @Enumerated(EnumType.STRING)
     @Column(name = "CREDENTIAL_TYPE", nullable = false)
     @ColumnDescription(comment = "Credential type:  USERNAME, ACCESS_TOKEN, CERTIFICATE, CAS")
     private CredentialType credentialType = CredentialType.USERNAME_PASSWORD;
-
-
     @Enumerated(EnumType.STRING)
     @Column(name = "CREDENTIAL_TARGET", nullable = false)
     @ColumnDescription(comment = "Credential target UI, API")
     private CredentialTargetType credentialTarget = CredentialTargetType.UI;
-
+    @Column(name = "RESET_TOKEN", length = CommonColumnsLengths.MAX_PASSWORD_LENGTH)
+    @ColumnDescription(comment = "Reset token for credential reset")
+    private String resetToken;
+    @Column(name = "RESET_EXPIRE_ON")
+    @ColumnDescription(comment = "Date time when reset token will expire")
+    private OffsetDateTime resetExpireOn;
 
     @OneToOne(mappedBy = "credential",
             cascade = CascadeType.ALL,
@@ -262,6 +264,22 @@ public class DBCredential extends BaseEntity {
         this.credentialTarget = credentialTarget;
     }
 
+    public String getResetToken() {
+        return resetToken;
+    }
+
+    public void setResetToken(String resetToken) {
+        this.resetToken = resetToken;
+    }
+
+    public OffsetDateTime getResetExpireOn() {
+        return resetExpireOn;
+    }
+
+    public void setResetExpireOn(OffsetDateTime resetExpireOn) {
+        this.resetExpireOn = resetExpireOn;
+    }
+
     public DBCertificate getCertificate() {
         return certificate;
     }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialRequestResetRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialRequestResetRO.java
new file mode 100644
index 0000000000000000000000000000000000000000..1082b4f441def5d43e80a8f8fac08568c0792ffb
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialRequestResetRO.java
@@ -0,0 +1,62 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.data.ui;
+
+import eu.europa.ec.edelivery.smp.data.enums.CredentialType;
+
+import java.util.StringJoiner;
+
+
+/**
+ * Credential request reset object
+ *
+ * @author Joze Rihtarsic
+ * @since 5.1
+ */
+public class CredentialRequestResetRO extends BaseRO {
+
+    private static final long serialVersionUID = 9008583888835630030L;
+
+    String credentialName;
+    CredentialType credentialType;
+
+    public String getCredentialName() {
+        return credentialName;
+    }
+
+    public void setCredentialName(String credentialName) {
+        this.credentialName = credentialName;
+    }
+
+    public CredentialType getCredentialType() {
+        return credentialType;
+    }
+
+    public void setCredentialType(CredentialType credentialType) {
+        this.credentialType = credentialType;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", CredentialRequestResetRO.class.getSimpleName() + "[", "]")
+                .add("credentialName=[" + credentialName + "],")
+                .add("credentialType=[" + credentialType + "]")
+                .toString();
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialResetRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialResetRO.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d85e8a40fc5ccb835ef611567467943c926b654
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialResetRO.java
@@ -0,0 +1,81 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * 
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ * 
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.data.ui;
+
+import eu.europa.ec.edelivery.smp.data.enums.CredentialType;
+
+import java.util.StringJoiner;
+
+
+/**
+ * Credential request reset object
+ * @author Joze Rihtarsic
+ * @since 5.1
+ */
+public class CredentialResetRO extends BaseRO {
+
+    private static final long serialVersionUID = 9008583888835630030L;
+
+    String credentialName;
+    String credentialValue;
+    CredentialType credentialType;
+    String resetToken;
+
+
+    public String getCredentialName() {
+        return credentialName;
+    }
+
+    public void setCredentialName(String credentialName) {
+        this.credentialName = credentialName;
+    }
+
+    public CredentialType getCredentialType() {
+        return credentialType;
+    }
+
+    public void setCredentialType(CredentialType credentialType) {
+        this.credentialType = credentialType;
+    }
+
+    public String getCredentialValue() {
+        return credentialValue;
+    }
+
+    public void setCredentialValue(String credentialValue) {
+        this.credentialValue = credentialValue;
+    }
+
+    public String getResetToken() {
+        return resetToken;
+    }
+
+    public void setResetToken(String resetToken) {
+        this.resetToken = resetToken;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", CredentialResetRO.class.getSimpleName() + "[", "]")
+                .add("credentialName='" + credentialName + "'")
+                .add("credentialValue='" + credentialValue + "'")
+                .add("credentialType='" + credentialType + "'")
+                .toString();
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/SmpInfoRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/SmpInfoRO.java
index a04b632e4d39973078be00debc9fcf4457002697..1fcb6fc51f2f0e455ad1c18c4132aaaca4e7ccf5 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/SmpInfoRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/SmpInfoRO.java
@@ -34,6 +34,10 @@ public class SmpInfoRO implements Serializable {
     private String ssoAuthenticationLabel;
     private String ssoAuthenticationURI;
     private String contextPath;
+
+    private String passwordValidationRegExp;
+    private String passwordValidationRegExpMessage;
+
     private final List<String> authTypes = new ArrayList<>();
 
     public String getVersion() {
@@ -75,4 +79,20 @@ public class SmpInfoRO implements Serializable {
     public void addAuthTypes(List<String> authTypes) {
         this.authTypes.addAll(authTypes);
     }
+
+    public String getPasswordValidationRegExp() {
+        return passwordValidationRegExp;
+    }
+
+    public void setPasswordValidationRegExp(String passwordValidationRegExp) {
+        this.passwordValidationRegExp = passwordValidationRegExp;
+    }
+
+    public String getPasswordValidationRegExpMessage() {
+        return passwordValidationRegExpMessage;
+    }
+
+    public void setPasswordValidationRegExpMessage(String passwordValidationRegExpMessage) {
+        this.passwordValidationRegExpMessage = passwordValidationRegExpMessage;
+    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertTypeEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertTypeEnum.java
index 90f8f350696ff4d5056d20db5b7ceff20c05faae..98e89bb92bb51ca37101af1d839e05f77827650a 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertTypeEnum.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertTypeEnum.java
@@ -25,11 +25,13 @@ package eu.europa.ec.edelivery.smp.data.ui.enums;
  * @since 4.2
  */
 public enum AlertTypeEnum {
-    TEST_ALERT("test_mail.ftl"),
-    CREDENTIAL_IMMINENT_EXPIRATION("credential_imminent_expiration.ftl"),
-    CREDENTIAL_EXPIRED("credential_expired.ftl"),
-    CREDENTIAL_SUSPENDED("credential_suspended.ftl"),
-    CREDENTIAL_VERIFICATION_FAILED("credential_verification_failed.ftl"),
+    TEST_ALERT("test_mail"),
+    CREDENTIAL_IMMINENT_EXPIRATION("credential_imminent_expiration"),
+    CREDENTIAL_EXPIRED("credential_expired"),
+    CREDENTIAL_SUSPENDED("credential_suspended"),
+    CREDENTIAL_VERIFICATION_FAILED("credential_verification_failed"),
+    CREDENTIAL_REQUEST_RESET("credential_request_reset"),
+    CREDENTIAL_CHANGED("credential_changed"),
     ;
 
     private final String template;
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java
index d6028ec4c6d6220ef1604f6e3208bf419a9af7b4..edf8c4ba6881d93902e68faf3d11d5c7de7082f2 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java
@@ -564,6 +564,17 @@ public class ConfigurationService {
         return configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_EXPIRED_MAIL_SUBJECT);
     }
 
+    public String getSMPInstanceName() {
+        return configurationDAO.getCachedPropertyValue(SMP_INSTANCE_NAME);
+    }
+    // ----
+    public java.net.URL getCredentialsResetUrl() {
+        return configurationDAO.getCachedPropertyValue(CREDENTIALS_RESET_URL);
+    }
+
+    public Integer getCredentialsResetPolicyValidMinutes() {
+        return configurationDAO.getCachedPropertyValue(CREDENTIALS_RESET_POLICY_VALID_DAYS);
+    }
 
     public Integer getAlertCredentialsBatchSize() {
         return configurationDAO.getCachedPropertyValue(SMP_ALERT_BATCH_SIZE);
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CredentialService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CredentialService.java
index a8e2107a6edd798ab4f86bd937b70aa93447b82e..f789b670cfb7570a08876a96d2f3e256ccaf76b2 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CredentialService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CredentialService.java
@@ -8,9 +8,9 @@
  * versions of the EUPL (the "Licence");
  * You may not use this work except in compliance with the Licence.
  * You may obtain a copy of the Licence at:
- * 
+ *
  * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
  * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the Licence for the specific language governing permissions and limitations under the Licence.
@@ -59,13 +59,20 @@ import java.util.*;
 
 import static java.util.Locale.US;
 
+/**
+ * The CredentialService class is a service that provides methods for user authentication and credential management.
+ * The service is intended for stateful service calls to validate credentials with audit logs, credential reset.
+ *
+ * @author Joze Rihtarsic
+ * @since 5.0
+ */
 @Service
 public class CredentialService {
     protected static final SMPLogger LOG = SMPLoggerFactory.getLogger(CredentialService.class);
     protected static final BadCredentialsException BAD_CREDENTIALS_EXCEPTION = new BadCredentialsException(ErrorCode.UNAUTHORIZED_INVALID_USERNAME_PASSWORD.getMessage());
     protected static final BadCredentialsException SUSPENDED_CREDENTIALS_EXCEPTION = new BadCredentialsException(ErrorCode.UNAUTHORIZED_CREDENTIAL_SUSPENDED.getMessage());
-    final UserDao mUserDao;
-    final CredentialDao mCredentialDao;
+    final UserDao userDao;
+    final CredentialDao credentialDao;
     final ConversionService conversionService;
     final CRLVerifierService crlVerifierService;
     final UITruststoreService truststoreService;
@@ -78,9 +85,9 @@ public class CredentialService {
     private static final ThreadLocal<DateFormat> dateFormatLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("MMM d hh:mm:ss yyyy zzz", US));
 
 
-    public CredentialService(UserDao mUserDao, CredentialDao mCredentialDao, ConversionService conversionService, CRLVerifierService crlVerifierService, UITruststoreService truststoreService, ConfigurationService configurationService, CredentialsAlertService alertService) {
-        this.mUserDao = mUserDao;
-        this.mCredentialDao = mCredentialDao;
+    public CredentialService(UserDao mUserDao, CredentialDao credentialDao, ConversionService conversionService, CRLVerifierService crlVerifierService, UITruststoreService truststoreService, ConfigurationService configurationService, CredentialsAlertService alertService) {
+        this.userDao = mUserDao;
+        this.credentialDao = credentialDao;
         this.conversionService = conversionService;
         this.crlVerifierService = crlVerifierService;
         this.truststoreService = truststoreService;
@@ -96,9 +103,9 @@ public class CredentialService {
         LOG.debug("authenticateByUsernamePassword: start [{}]", username);
         DBCredential credential;
         try {
-            Optional<DBCredential> dbCredential = mCredentialDao.findUsernamePasswordCredentialForUsernameAndUI(username);
+            Optional<DBCredential> dbCredential = credentialDao.findUsernamePasswordCredentialForUsernameAndUI(username);
             if (!dbCredential.isPresent() || isNotValidCredential(dbCredential.get())) {
-                LOG.debug("User with username does not exists [{}], continue with next authentication provider");
+                LOG.debug("User with username does not exists [{}], continue with next authentication provider", username);
                 LOG.securityWarn(SMPMessageCode.SEC_INVALID_USER_CREDENTIALS, "Username does not exits", username);
                 delayResponse(CredentialType.USERNAME_PASSWORD, startTime);
                 throw BAD_CREDENTIALS_EXCEPTION;
@@ -150,7 +157,7 @@ public class CredentialService {
 
         DBCredential credential;
         try {
-            Optional<DBCredential> dbCredential = mCredentialDao.findAccessTokenCredentialForAPI(authenticationTokenId);
+            Optional<DBCredential> dbCredential = credentialDao.findAccessTokenCredentialForAPI(authenticationTokenId);
 
             if (!dbCredential.isPresent() || isNotValidCredential(dbCredential.get())) {
                 LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_EXISTS, authenticationTokenId);
@@ -177,7 +184,7 @@ public class CredentialService {
             }
             credential.setSequentialLoginFailureCount(0);
             credential.setLastFailedLoginAttempt(null);
-            mCredentialDao.update(credential);
+            credentialDao.update(credential);
         } catch (java.lang.IllegalArgumentException ex) {
             // password is not hashed
             loginAttemptFailedAndThrowError(credential, true, startTime);
@@ -237,7 +244,7 @@ public class CredentialService {
         }
         DBCredential credential;
         try {
-            Optional<DBCredential> optCredential = mCredentialDao.findUserByCertificateId(certificateIdentifier, true);
+            Optional<DBCredential> optCredential = credentialDao.findUserByCertificateId(certificateIdentifier, true);
             if (!optCredential.isPresent() || isNotValidCredential(optCredential.get())) {
                 LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_EXISTS, certificateIdentifier);
                 //https://www.owasp.org/index.php/Authentication_Cheat_Sheet
@@ -317,6 +324,111 @@ public class CredentialService {
         return smpAuthenticationToken;
     }
 
+    /**
+     * Method retrieves user credentials by username. First it validates if credentials have already active reset token
+     * and if not it creates new one.
+     *
+     * @param username
+     */
+    @Transactional
+    public void requestResetUsername(String username) {
+        LOG.debug("requestResetUsername [{}]", username);
+        // retrieve user Optional credentials by username
+        Optional<DBCredential> optCredential = getActiveCredentialsForUsernameToReset(username, true);
+        if (!optCredential.isPresent()) {
+            LOG.info("Skip generating reset token for username [{}]!", username);
+            return;
+        }
+        DBCredential dbCredential = optCredential.get();
+        generateResetTokenAndSubmitMail(dbCredential);
+    }
+
+    @Transactional
+    public void resetUsernamePassword(String username, String resetToken, String newPassword) {
+        // retrieve user Optional credentials by username
+        LOG.debug("resetUsernamePassword [{}]", username);
+        // retrieve user Optional credentials by username
+        Optional<DBCredential> optCredential = getActiveCredentialsForUsernameToReset(username, false);
+        if (!optCredential.isPresent()) {
+            LOG.info("Skip generating reset token for username [{}]!", username);
+            return;
+        }
+        DBCredential dbCredential = optCredential.get();
+
+        if (!resetToken.equals(dbCredential.getResetToken())) {
+            LOG.warn("User [{}] reset token does not match the active reset token! The request is ignored", username);
+            return;
+        }
+
+        OffsetDateTime now = OffsetDateTime.now();
+        dbCredential.setValue(BCrypt.hashpw(newPassword, BCrypt.gensalt()));
+        dbCredential.setResetToken(null);
+        dbCredential.setResetExpireOn(null);
+        dbCredential.setExpireAlertOn(null);
+        dbCredential.setSequentialLoginFailureCount(0);
+        dbCredential.setLastFailedLoginAttempt(null);
+        dbCredential.setChangedOn(now);
+        dbCredential.setExpireOn(now.plusDays(configurationService.getPasswordPolicyValidDays()));
+        // submit mail with reset token
+        alertService.alertCredentialChanged(dbCredential);
+    }
+
+    /**
+     * Method gets credentials for active user and validates if not expired reset token exists .
+     *
+     * @param username
+     * @return
+     */
+    private Optional<DBCredential> getActiveCredentialsForUsernameToReset(String username, boolean toGenerateResetToken) {
+        // retrieve user Optional credentials by username
+        Optional<DBCredential> optCredential = credentialDao.findUsernamePasswordCredentialForUsernameAndUI(username);
+        if (!optCredential.isPresent()) {
+            LOG.warn("There is not credentials for User [{}]!", username);
+            return optCredential;
+        }
+        DBCredential dbCredential = optCredential.get();
+
+        if (!dbCredential.getUser().isActive() || !dbCredential.isActive()) {
+            LOG.info("User [{}] or credentials are not active. Skip reset password request!", username);
+            return Optional.empty();
+        }
+
+        // When toGenerateResetToken check if the user has already active reset token
+        boolean hasValidResetToken = hasValidResetToken(dbCredential);
+        if (toGenerateResetToken && hasValidResetToken) {
+            LOG.info("User [{}] has already active reset token. Skip generating new reset token!", username);
+            return Optional.empty();
+        }
+        // If action is reset then check if the user has active reset token
+        if (!toGenerateResetToken && !hasValidResetToken) {
+            LOG.warn("User [{}] does not have active reset token. The reset token is expired or does not exists!", username);
+            throw new AuthenticationServiceException("User [" + username
+                    + "] does not have active reset token. Please request new reset token for the user!");
+        }
+
+        return optCredential;
+    }
+
+    private boolean hasValidResetToken(DBCredential dbCredential) {
+        return StringUtils.isNotBlank(dbCredential.getResetToken())
+                && dbCredential.getResetExpireOn() != null
+                && dbCredential.getResetExpireOn().isAfter(OffsetDateTime.now());
+    }
+
+    /**
+     * Method generates reset token and submit mail with reset token. The method must be invoked from a transactional
+     * parent method.
+     *
+     * @param dbCredential credential for which the reset token is generated.
+     */
+    private void generateResetTokenAndSubmitMail(DBCredential dbCredential) {
+        dbCredential.setResetToken(UUID.randomUUID().toString());
+        dbCredential.setResetExpireOn(OffsetDateTime.now().plusMinutes(configurationService.getCredentialsResetPolicyValidMinutes()));
+        // submit mail with reset token
+        dbCredential.getUser().getEmailAddress();
+        alertService.alertCredentialRequestReset(dbCredential);
+    }
+
     /**
      * Method validates if the certificate contains one of allowed Certificate policy. At the moment it does not validates
      * the whole chain. Because in some configuration cases does not use the truststore
@@ -348,7 +460,7 @@ public class CredentialService {
     }
 
 
-    protected void delayResponse(CredentialType credentialType, long startTime) {
+    public void delayResponse(CredentialType credentialType, long startTime) {
         int delayInMS = getLoginFailDelayInMilliSeconds(credentialType) - (int) (Calendar.getInstance().getTimeInMillis() - startTime);
         if (delayInMS > 0) {
             try {
@@ -366,7 +478,7 @@ public class CredentialService {
         CredentialType credentialType = credential.getCredentialType();
         credential.setSequentialLoginFailureCount(credential.getSequentialLoginFailureCount() != null ? credential.getSequentialLoginFailureCount() + 1 : 1);
         credential.setLastFailedLoginAttempt(OffsetDateTime.now());
-        mCredentialDao.update(credential);
+        credentialDao.update(credential);
         String username = credential.getUser().getUsername();
         LOG.securityWarn(SMPMessageCode.SEC_INVALID_USER_CREDENTIALS, username,
                 credential.getName(),
@@ -428,7 +540,7 @@ public class CredentialService {
             LOG.warn("User [{}] for credential [{}:{}] suspension is expired! Clear failed login attempts and last failed login attempt", credential.getName(), credentialType, credential.getName());
             credential.setLastFailedLoginAttempt(null);
             credential.setSequentialLoginFailureCount(0);
-            mCredentialDao.update(credential);
+            credentialDao.update(credential);
             return;
         }
 
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CredentialsAlertService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CredentialsAlertService.java
index 680dd8c44040745d71650200e7766b98263686f1..847d4b3ca7b02add5ee7c9ca21389d6f2c20be7c 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CredentialsAlertService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CredentialsAlertService.java
@@ -8,9 +8,9 @@
  * versions of the EUPL (the "Licence");
  * You may not use this work except in compliance with the Licence.
  * You may obtain a copy of the Licence at:
- * 
+ *
  * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
  * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the Licence for the specific language governing permissions and limitations under the Licence.
@@ -31,21 +31,23 @@ import eu.europa.ec.edelivery.smp.data.ui.enums.AlertStatusEnum;
 import eu.europa.ec.edelivery.smp.data.ui.enums.AlertTypeEnum;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.edelivery.smp.services.mail.MailDataModel;
 import eu.europa.ec.edelivery.smp.services.mail.MailService;
-import eu.europa.ec.edelivery.smp.services.mail.PropertiesMailModel;
-import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialSuspendedProperties;
-import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialVerificationFailedProperties;
-import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialsExpirationProperties;
+import eu.europa.ec.edelivery.smp.services.mail.prop.*;
 import eu.europa.ec.edelivery.smp.utils.HttpUtils;
+import eu.europa.ec.edelivery.smp.utils.SmpUrlBuilder;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.time.OffsetDateTime;
 import java.util.Date;
 
 import static eu.europa.ec.edelivery.smp.cron.CronTriggerConfig.TRIGGER_BEAN_CREDENTIAL_ALERTS;
+import static java.time.format.DateTimeFormatter.ISO_DATE_TIME;
 import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME;
 
 /**
@@ -64,12 +66,14 @@ public class CredentialsAlertService {
     final UserDao userDao;
     final CredentialDao credentialDao;
     final SMPDynamicCronTrigger alertCronTrigger;
+    final SmpUrlBuilder smpUrlBuilder;
 
     public CredentialsAlertService(AlertDao alertDao,
                                    MailService mailService,
                                    ConfigurationService configurationService,
                                    UserDao userDao,
                                    CredentialDao credentialDao,
+                                   SmpUrlBuilder smpUrlBuilder,
                                    @Qualifier(TRIGGER_BEAN_CREDENTIAL_ALERTS) SMPDynamicCronTrigger alertCronTrigger) {
         this.alertDao = alertDao;
         this.mailService = mailService;
@@ -77,6 +81,7 @@ public class CredentialsAlertService {
         this.userDao = userDao;
         this.credentialDao = credentialDao;
         this.alertCronTrigger = alertCronTrigger;
+        this.smpUrlBuilder = smpUrlBuilder;
     }
 
     public void alertBeforeCredentialExpire(DBCredential userCredential) {
@@ -243,7 +248,7 @@ public class CredentialsAlertService {
         alert.addProperty(CredentialsExpirationProperties.SERVER_NAME.name(), serverName);
         alertDao.persistFlushDetach(alert);
         // submit alerts
-        submitAlertMail(alert);
+        submitAlertMail(alert, credential.getUser());
         // when alert about to expire - check if the next cron execution is expired
         // and set date sent tp null to ensure alert submission in next cron execution
         credentialDao.updateAlertSentForUserCredentials(credential,
@@ -259,7 +264,7 @@ public class CredentialsAlertService {
                                                   Integer failedLoginCount,
                                                   OffsetDateTime lastFailedLoginDate
     ) {
-        LOG.info("Prepare alert for credentials [{}] ", credentialId );
+        LOG.info("Prepare alert for credentials [{}] ", credentialId);
         String serverName = HttpUtils.getServerAddress();
         // add alert properties
         alert.addProperty(CredentialVerificationFailedProperties.CREDENTIAL_TYPE.name(), credentialType.name());
@@ -271,7 +276,7 @@ public class CredentialsAlertService {
         alert.addProperty(CredentialVerificationFailedProperties.SERVER_NAME.name(), serverName);
         alertDao.persistFlushDetach(alert);
         // submit alerts
-        submitAlertMail(alert);
+        submitAlertMail(alert, user);
     }
 
     public void alertCredentialSuspended(DBUser user,
@@ -294,7 +299,95 @@ public class CredentialsAlertService {
         alert.addProperty(CredentialSuspendedProperties.SERVER_NAME.name(), serverName);
         alertDao.persistFlushDetach(alert);
         // submit alerts
-        submitAlertMail(alert);
+        submitAlertMail(alert, user);
+    }
+
+    /**
+     * Method generates request reset alert for credentials and submit mail to the user
+     *
+     * @param credential credential to reset
+     */
+    public void alertCredentialRequestReset(DBCredential credential) {
+
+        DBUser user = credential.getUser();
+        String mailTo = user.getEmailAddress();
+        String mailSubject = configurationService.getAlertUserSuspendedSubject();
+        AlertLevelEnum alertLevel = AlertLevelEnum.HIGH;
+        AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_REQUEST_RESET;
+
+        DBAlert alert = createAlert(user.getUsername(), mailSubject, mailTo, alertLevel, alertType);
+
+        alertCredentialRequestReset(credential.getResetToken(),
+                alert,
+                credential.getCredentialType(),
+                credential.getName(),
+                 user);
+    }
+
+    public void alertCredentialRequestReset(String token,
+                                            DBAlert alert,
+                                            CredentialType credentialType,
+                                            String credentialId,
+                                            DBUser user) {
+
+
+        URL resetUrl = configurationService.getCredentialsResetUrl();
+        if (resetUrl == null) {
+            try {
+                resetUrl = smpUrlBuilder.buildSMPUriForApplication().toURL();
+                LOG.warn("Reset URL is not set! Use default SMP URL [{}]", resetUrl);
+            } catch (MalformedURLException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        String resetUrlPath = StringUtils.appendIfMissing(resetUrl.toString(), "/", "/") + "ui/#/reset-credential/" + token;
+        String serverName = HttpUtils.getServerAddress();
+        // add alert properties
+        alert.addProperty(CredentialsResetRequestProperties.CREDENTIAL_TYPE.name(), credentialType.name());
+        alert.addProperty(CredentialsResetRequestProperties.CREDENTIAL_ID.name(), credentialId);
+        alert.addProperty(CredentialsResetRequestProperties.REPORTING_DATETIME.name(), alert.getReportingTime());
+        alert.addProperty(CredentialsResetRequestProperties.ALERT_LEVEL.name(), alert.getAlertLevel().name());
+        alert.addProperty(CredentialsResetRequestProperties.RESET_URL.name(), resetUrlPath);
+        alert.addProperty(CredentialsResetRequestProperties.SERVER_NAME.name(), serverName);
+        alertDao.persistFlushDetach(alert);
+        // submit alerts
+        submitAlertMail(alert, user);
+    }
+
+
+    /**
+     * Method generates request alert for credentials change and submit mail to the user
+     *
+     * @param credential credential changed
+     */
+    public void alertCredentialChanged(DBCredential credential) {
+
+        DBUser user = credential.getUser();
+        String mailTo = user.getEmailAddress();
+        String mailSubject = configurationService.getAlertUserSuspendedSubject();
+        AlertLevelEnum alertLevel = AlertLevelEnum.HIGH;
+        AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_CHANGED;
+
+        DBAlert alert = createAlert(user.getUsername(), mailSubject, mailTo, alertLevel, alertType);
+
+        alertCredentialChanged(user, alert, credential.getCredentialType(), credential.getName());
+
+    }
+
+    public void alertCredentialChanged(DBUser user, DBAlert alert,
+                                            CredentialType credentialType,
+                                            String credentialId) {
+
+        String serverName = HttpUtils.getServerAddress();
+        // add alert properties
+        alert.addProperty(CredentialsChangedProperties.CREDENTIAL_TYPE.name(), credentialType.name());
+        alert.addProperty(CredentialsChangedProperties.CREDENTIAL_ID.name(), credentialId);
+        alert.addProperty(CredentialsChangedProperties.REPORTING_DATETIME.name(), alert.getReportingTime());
+        alert.addProperty(CredentialsChangedProperties.ALERT_LEVEL.name(), alert.getAlertLevel().name());
+        alert.addProperty(CredentialsChangedProperties.SERVER_NAME.name(), serverName);
+        alertDao.persistFlushDetach(alert);
+        // submit alerts
+        submitAlertMail(alert, user);
     }
 
     /**
@@ -327,7 +420,7 @@ public class CredentialsAlertService {
      *
      * @param alert
      */
-    public void submitAlertMail(DBAlert alert) {
+    public void submitAlertMail(DBAlert alert, DBUser user) {
         String mailTo = alert.getMailTo();
         if (StringUtils.isBlank(mailTo)) {
             LOG.warn("Can not send mail (empty mail) for alert [{}]!", alert);
@@ -335,14 +428,20 @@ public class CredentialsAlertService {
             return;
         }
 
+
         String mailFrom = configurationService.getAlertEmailFrom();
-        PropertiesMailModel props = new PropertiesMailModel(alert);
+        MailDataModel props = new MailDataModel(user.getSmpLocale(), alert);
+        props.getModel().put(MailDataModel.CommonProperties.SMP_INSTANCE_NAME.name(),
+                configurationService.getSMPInstanceName());
+        props.getModel().put(MailDataModel.CommonProperties.CURRENT_DATETIME.name(),
+                OffsetDateTime.now().format(ISO_DATE_TIME));
+
         try {
             mailService.sendMail(props, mailFrom, alert.getMailTo());
             updateAlertStatus(alert, AlertStatusEnum.SUCCESS, null);
         } catch (Throwable exc) {
             LOG.error("Can not send mail [{}] for alert [{}]! Error [{}]",
-                    mailTo,  alert, ExceptionUtils.getRootCauseMessage(exc));
+                    mailTo, alert, ExceptionUtils.getRootCauseMessage(exc));
             updateAlertStatus(alert, AlertStatusEnum.FAILED, ExceptionUtils.getRootCauseMessage(exc));
         }
 
@@ -365,5 +464,4 @@ public class CredentialsAlertService {
         return nextExecutionDate == null || expireOn == null ||
                 expireOn.isBefore(nextExecutionDate.toInstant().atOffset(expireOn.getOffset()));
     }
-
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/PropertiesMailModel.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailDataModel.java
similarity index 51%
rename from smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/PropertiesMailModel.java
rename to smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailDataModel.java
index 8cfbca0504e83a0cd2b8e6527fd856e77c26f9f1..1e35ec651c4fb9260a2d6837cb0176586bf9e2c0 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/PropertiesMailModel.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailDataModel.java
@@ -8,9 +8,9 @@
  * versions of the EUPL (the "Licence");
  * You may not use this work except in compliance with the Licence.
  * You may obtain a copy of the Licence at:
- * 
+ *
  * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
  * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the Licence for the specific language governing permissions and limitations under the Licence.
@@ -19,47 +19,42 @@
 package eu.europa.ec.edelivery.smp.services.mail;
 
 import eu.europa.ec.edelivery.smp.data.model.DBAlert;
+import eu.europa.ec.edelivery.smp.data.ui.enums.AlertTypeEnum;
 
-import java.util.Properties;
+import java.util.HashMap;
+import java.util.Map;
 
-public class PropertiesMailModel implements MailModel<Properties> {
-
-    private final Properties model = new Properties();
-
-    private final String templatePath;
-
-    private final String subject;
-
-
-    public PropertiesMailModel(final String templatePath, final String subject) {
-        this.templatePath = templatePath;
-        this.subject = subject;
+public class MailDataModel {
+    public enum CommonProperties {
+        CURRENT_DATETIME,
+        SMP_INSTANCE_NAME,
     }
+    private final String language;
+    private final AlertTypeEnum alertType;
+    Map<String, String> model = new HashMap<>();
 
-    public PropertiesMailModel(final DBAlert alert) {
-        this.templatePath = alert.getAlertType().getTemplate();
-        this.subject = alert.getMailSubject();
-        alert.getProperties().forEach((key, prop) -> setProperty(key, prop.getValue())
-        );
-    }
 
-    @Override
-    public Properties getModel() {
-        return model;
+    public MailDataModel(String language, AlertTypeEnum alertType, Map<String, String> model) {
+        this.language = language;
+        this.alertType = alertType;
+        this.model.putAll(model);
     }
 
+    public MailDataModel(String language, final DBAlert alert) {
+        this.language = language;
+        this.alertType = alert.getAlertType();
+        alert.getProperties().forEach((key, prop) ->  this.model.put(key, prop.getValue()));
+    }
 
-    public void setProperty(String key, String value) {
-        model.setProperty(key, value);
+    public String getLanguage() {
+        return language;
     }
 
-    @Override
-    public String getTemplatePath() {
-        return templatePath;
+    public AlertTypeEnum getMailType() {
+        return alertType;
     }
 
-    @Override
-    public String getSubject() {
-        return subject;
+    public Map<String, String> getModel() {
+        return model;
     }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailService.java
index b7a745a515858f9eb6bcf35f12da55298843b44c..3200c82de8579d57314a3492eebd89d488cadeeb 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailService.java
@@ -8,9 +8,9 @@
  * versions of the EUPL (the "Licence");
  * You may not use this work except in compliance with the Licence.
  * You may obtain a copy of the Licence at:
- * 
+ *
  * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
  * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the Licence for the specific language governing permissions and limitations under the Licence.
@@ -22,22 +22,16 @@ import eu.europa.ec.edelivery.smp.exceptions.ErrorCode;
 import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.springframework.mail.MailException;
 import org.springframework.mail.javamail.JavaMailSenderImpl;
 import org.springframework.mail.javamail.MimeMessageHelper;
 import org.springframework.stereotype.Component;
-import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
 
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
-import java.io.IOException;
 import java.nio.charset.StandardCharsets;
-import java.util.Properties;
 
 
 /**
@@ -53,16 +47,16 @@ public class MailService {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(MailService.class);
 
-    private final Configuration freemarkerConfig;
     private final JavaMailSenderImpl javaMailSender;
+    private final MailTemplateService mailTemplateService;
 
-    public MailService(Configuration freemarkerConfig, JavaMailSenderImpl javaMailSender) {
-        this.freemarkerConfig = freemarkerConfig;
+    public MailService(JavaMailSenderImpl javaMailSender, MailTemplateService mailTemplateService) {
         this.javaMailSender = javaMailSender;
+        this.mailTemplateService = mailTemplateService;
     }
 
 
-    public <T extends MailModel<Properties>> void sendMail(final T model, final String from, final String to) {
+    public void sendMail(final MailDataModel model, final String from, final String to) {
         if (StringUtils.isBlank(to)) {
             throw new IllegalArgumentException("The 'to' property cannot be null");
         }
@@ -70,25 +64,27 @@ public class MailService {
             throw new IllegalArgumentException("The 'from' property cannot be null");
         }
 
+
         MimeMessage message = javaMailSender.createMimeMessage();
         try {
+
             MimeMessageHelper helper = getMimeMessageHelper(message);
-            Template template = freemarkerConfig.getTemplate(model.getTemplatePath());
-            final Object mailData = model.getModel();
-            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, mailData);
+            String subject = mailTemplateService.getMailTitle(model);
+            String html = mailTemplateService.getMailHtmlContent(model);
 
+            // if to contains multiple emails, split them and send as anonymously as BCC
             if (to.contains(";")) {
                 helper.setBcc(to.split(";"));
             } else {
                 helper.setTo(to);
             }
             helper.setText(html, true);
-            helper.setSubject(model.getSubject());
+            helper.setSubject(subject);
             helper.setFrom(from);
-            LOG.info("Send mail to : [{}:{}]",javaMailSender.getHost(),javaMailSender.getPort());
+            LOG.info("Send mail to : [{}:{}]", javaMailSender.getHost(), javaMailSender.getPort());
 
             javaMailSender.send(message);
-        } catch (IOException | MessagingException | TemplateException | MailException e) {
+        } catch (MessagingException | MailException e) {
             LOG.error("Exception while sending mail from [{}] to [{}]", from, to, e);
             throw new SMPRuntimeException(ErrorCode.MAIL_SUBMISSION_ERROR, e, ExceptionUtils.getRootCauseMessage(e));
         }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailTemplateService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailTemplateService.java
new file mode 100644
index 0000000000000000000000000000000000000000..f5e3d0c9cfc28f7296b82a188b876bd4de6adc2a
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailTemplateService.java
@@ -0,0 +1,111 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.services.mail;
+
+import eu.europa.ec.edelivery.smp.utils.StringNamedSubstitutor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Mail template for mail content. The class is used to create mail messages from templates and message
+ * translations.
+ *
+ * @author Joze Rihtarsic
+ * @since 5.1
+ */
+@Component
+public class MailTemplateService {
+    private static final String DEFAULT_LANGUAGE = "en";
+    private static final String MAIL_TEMPLATE = "/mail-messages/mail-template.htm";
+
+    private static final String MAIL_HEADER = "MAIL_HEADER";
+    private static final String MAIL_FOOTER = "MAIL_FOOTER";
+    private static final String MAIL_TITLE = "MAIL_TITLE";
+    private static final String MAIL_CONTENT = "MAIL_CONTENT";
+
+
+    public String getMailHtmlContent(MailDataModel model) {
+        InputStream templateIS = MailTemplateService.class.getResourceAsStream(MAIL_TEMPLATE);
+        try {
+            Map<String, String> modelData = new HashMap<>();
+            modelData.put(MAIL_HEADER, getMailHeader(model));
+            modelData.put(MAIL_FOOTER, getMailFooter(model));
+            modelData.put(MAIL_TITLE, getMailTitle(model));
+            modelData.put(MAIL_CONTENT, getMailBody(model));
+            return StringNamedSubstitutor.resolve(templateIS, modelData);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public String getMailHeader(MailDataModel model) {
+        return getMailData(model, "mail.header");
+    }
+
+    public String getMailFooter(MailDataModel model) {
+        return getMailData(model, "mail.footer");
+    }
+
+    public String getMailTitle(MailDataModel model) {
+        return getMailData(model, "mail." + model.getMailType().getTemplate() + ".title");
+    }
+
+    public String getMailBody(MailDataModel model) {
+        return getMailData(model, "mail." + model.getMailType().getTemplate() + ".content");
+    }
+
+    public String getMailData(MailDataModel model, String key) {
+        Properties translations = getMessageTranslations(model.getLanguage());
+        String dataTemplate = translations.getProperty(key);
+        return StringUtils.isBlank(dataTemplate) ? dataTemplate : StringNamedSubstitutor.resolve(dataTemplate, model.getModel());
+    }
+
+    public Properties getMessageTranslations(String language) {
+
+        Properties translations = loadTranslations(language);
+        if (translations != null) {
+            return translations;
+        }
+        return loadTranslations(DEFAULT_LANGUAGE);
+    }
+
+    @Cacheable("mail-templates-translations")
+    public Properties loadTranslations(String language) {
+        String langResource = "/mail-messages/mail-messages_" + language + ".properties";
+        InputStream isLanguage = MailTemplateService.class.getResourceAsStream(langResource);
+        if (isLanguage != null) {
+            try {
+                Properties translations = new Properties();
+                translations.load(isLanguage);
+                return translations;
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return null;
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailModel.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialsChangedProperties.java
similarity index 69%
rename from smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailModel.java
rename to smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialsChangedProperties.java
index 9801b09d2d4b63697fa2d59cb965872b07073a62..668205c9ed727bfa69c5a3423465aa600a3ba44e 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/MailModel.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialsChangedProperties.java
@@ -16,23 +16,12 @@
  * See the Licence for the specific language governing permissions and limitations under the Licence.
  * #END_LICENSE#
  */
-package eu.europa.ec.edelivery.smp.services.mail;
+package eu.europa.ec.edelivery.smp.services.mail.prop;
 
-/**
- * Mail model for constitution of the mail content using freemaker template. The class was heavily inspired by Domibus
- * mail implementation
- *
- * @author Thomas Dussart
- * @author Joze Rihtarsic
- *
- * @since 4.2
- */
-public interface MailModel<T> {
-
-    T getModel();
-
-    String getTemplatePath();
-
-    String getSubject();
+public enum CredentialsChangedProperties {
+    CREDENTIAL_TYPE,
+    CREDENTIAL_ID,
+    REPORTING_DATETIME,
+    ALERT_LEVEL,
+    SERVER_NAME,
 }
-
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialsResetRequestProperties.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialsResetRequestProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..1535e1982244ef2d2d4b6eb433053013e7ddce63
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialsResetRequestProperties.java
@@ -0,0 +1,28 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * 
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ * 
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.services.mail.prop;
+
+public enum CredentialsResetRequestProperties {
+    CREDENTIAL_TYPE,
+    CREDENTIAL_ID,
+    RESET_URL,
+    REPORTING_DATETIME,
+    ALERT_LEVEL,
+    SERVER_NAME,
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
index 3d84a66044b7db087d97efa4e7a7366cebaf6b82..cb8116ae6f2e95c045ef1b9001146d94dec2791d 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
@@ -39,6 +39,7 @@ import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import eu.europa.ec.edelivery.smp.services.ConfigurationService;
+import eu.europa.ec.edelivery.smp.services.CredentialsAlertService;
 import eu.europa.ec.edelivery.smp.utils.BCryptPasswordHash;
 import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -71,19 +72,21 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
     CredentialDao credentialDao;
     private final ConfigurationService configurationService;
     private final ConversionService conversionService;
-
+    private final CredentialsAlertService alertService;
     private final UITruststoreService truststoreService;
 
     public UIUserService(UserDao userDao,
                          CredentialDao credentialDao,
                          ConfigurationService configurationService,
                          ConversionService conversionService,
-                         UITruststoreService truststoreService) {
+                         UITruststoreService truststoreService,
+                         CredentialsAlertService alertService) {
         this.userDao = userDao;
         this.credentialDao = credentialDao;
         this.configurationService = configurationService;
         this.conversionService = conversionService;
         this.truststoreService = truststoreService;
+        this.alertService = alertService;
     }
 
     @Override
@@ -258,6 +261,8 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
         if (dbCredential.getId() == null) {
             credentialDao.persist(dbCredential);
         }
+        // submit mail with reset token
+        alertService.alertCredentialChanged(dbCredential);
         return dbCredential.getUser();
     }
 
@@ -492,6 +497,8 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
         }
         credentialResultRO.setStatus(EntityROStatus.UPDATED.getStatusNumber());
 
+        alertService.alertCredentialChanged(credential);
+
         return credentialResultRO;
     }
 
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SmpUrlBuilder.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SmpUrlBuilder.java
index c3db71cc095a0e81bfcd08c34dc5907eb9319a5b..3d7ac3c1b32f876002bea175bc37697fa9ee88df 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SmpUrlBuilder.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SmpUrlBuilder.java
@@ -8,9 +8,9 @@
  * versions of the EUPL (the "Licence");
  * You may not use this work except in compliance with the Licence.
  * You may obtain a copy of the Licence at:
- * 
+ *
  * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
  * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the Licence for the specific language governing permissions and limitations under the Licence.
@@ -33,6 +33,7 @@ import org.springframework.web.util.UriComponentsBuilder;
 import org.springframework.web.util.UrlPathHelper;
 
 import javax.servlet.http.HttpServletRequest;
+import java.net.URI;
 
 /**
  * This class provides tools to generate SMP's URL in responses. The client can use provided URL for another call to the SMP.
@@ -61,7 +62,7 @@ public class SmpUrlBuilder {
         this.configurationService = configurationService;
     }
 
-    public String buildSMPUrlForApplication() {
+    public URI buildSMPUriForApplication() {
         HttpServletRequest req = getCurrentRequest();
         HttpForwardedHeaders fh = new HttpForwardedHeaders(req);
         LOG.debug("Generate response uri with headers data: [{}]", fh);
@@ -80,8 +81,11 @@ public class SmpUrlBuilder {
         } else {
             LOG.info("Ignore settings header because host is null!");
         }
-        return uriBuilder.build().toUriString();
+        return uriBuilder.build().toUri();
+    }
 
+    public String buildSMPUrlForApplication() {
+        return buildSMPUriForApplication().toString();
     }
 
     /**
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/StringNamedSubstitutor.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/StringNamedSubstitutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..42f8c4b5e81cdc89ed4654ea1e6ab41d3c2807de
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/StringNamedSubstitutor.java
@@ -0,0 +1,138 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.*;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * This class is used to substitute named variables in the string with key value pairs from the map.
+ * The variables are in the form of ${name} and are case-insensitive and can contain only letters, digits, and chars
+ * '_' and '.'.
+ *
+ * @author Joze Rihtarsic
+ * @since 4.2
+ */
+public class StringNamedSubstitutor {
+    private static final String START_NAME = "${";
+    private static final char END_NAME = '}';
+
+    /**
+     * Substitute named variables in the string with key value pairs from the map.
+     * The variables are in the form of ${name} and are case-insensitive and can contain only letters, digits, _ and .
+     *
+     * @param templateIS the InputStream to resolve
+     * @param config     the config to use
+     * @return the resolved string
+     */
+    public static String resolve(InputStream templateIS, Map<String, String> config) throws IOException {
+        Map<String, String> lowerCase = config.entrySet().stream()
+                .collect(Collectors.toMap(e -> StringUtils.lowerCase(e.getKey()), Map.Entry::getValue));
+        StringBuilder builder = new StringBuilder();
+
+        BufferedReader template = new BufferedReader(new InputStreamReader(templateIS));
+        int read;
+        while ((read = template.read()) != -1) {
+            if (read == START_NAME.charAt(0) && isStartSequence(template)) {
+                template.skip(START_NAME.length() - 1);
+                String name = readName(template, END_NAME);
+                if (name == null) {
+                    builder.append(START_NAME);
+                } else {
+                    String key = StringUtils.lowerCase(name);
+                    String value = lowerCase.get(key);
+                    if (value != null) {
+                        builder.append(value);
+                    } else {
+                        builder.append(START_NAME).append(name).append(END_NAME);
+                    }
+                }
+            } else {
+                builder.append((char) read);
+            }
+        }
+
+        return builder.toString();
+    }
+
+    public static boolean isStartSequence(BufferedReader reader) throws IOException {
+        reader.mark(START_NAME.length());
+        int read = reader.read();
+        if (read == -1) {
+            return false;
+        }
+        for (int i = 1; i < START_NAME.length(); i++) {
+            if (read != START_NAME.charAt(i)) {
+                reader.reset();
+                return false;
+            }
+            read = reader.read();
+            if (read == -1) {
+                return false;
+            }
+        }
+        reader.reset();
+        return true;
+    }
+
+    /**
+     * Method reads name until it finds end name char or until the first not letter/digit or
+     * _ or . character is found.
+     *
+     * @param inputStream the string to search index of the character
+     * @param searchChar  the character
+     * @return the index of the character or -1 if not found
+     */
+    private static String readName(BufferedReader inputStream, char searchChar) throws IOException {
+        StringBuilder builder = new StringBuilder();
+        int read;
+        while ((read = inputStream.read()) != -1) {
+            char currChar = (char) read;
+            if (currChar == searchChar) {
+                return builder.toString();
+            } else if (!Character.isLetterOrDigit(currChar)
+                    && currChar != '_'
+                    && currChar != '.') {
+                builder.append(currChar);
+                return builder.toString();
+            }
+            builder.append(currChar);
+        }
+        return null;
+    }
+
+    /**
+     * Substitute named variables in the string with key value pairs from the map.
+     * The variables are in the form of ${name} and are case-insensitive and can contain only letters, digits, _ and .
+     *
+     * @param string the string to resolve
+     * @param config the config to use
+     * @return the resolved string
+     */
+    public static String resolve(String string, Map<String, String> config) {
+        try {
+            return resolve(new ByteArrayInputStream(string.getBytes()), config);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+}
diff --git a/smp-server-library/src/main/resources/alert-mail-templates/credential_expired.ftl b/smp-server-library/src/main/resources/alert-mail-templates/credential_expired.ftl
deleted file mode 100644
index 5240d3f2c01f5f02a5c97147e4b77459c4bff2ff..0000000000000000000000000000000000000000
--- a/smp-server-library/src/main/resources/alert-mail-templates/credential_expired.ftl
+++ /dev/null
@@ -1,115 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title>DomiSMP</title>
-</head>
-<body style="margin:0; padding:0; background-color: #f1f1f1;">
-<center>
-  <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-    <tr>
-      <td><!-- MARGIN TOP -->
-
-        <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-          <tr>
-            <td>&nbsp;</td>
-          </tr>
-        </table>
-
-        <!-- / MARGIN TOP -->
-
-        <table width="540" align="center" border="0" cellspacing="0" cellpadding="0">
-          <tr>
-            <!-- MARGIN LEFT -->
-            <td width="20" valign="top">&nbsp;</td>
-            <!-- / MARGIN LEFT -->
-            <td width="500" valign="top"><!-- WRAPPER -->
-
-              <table width="500" border="0" cellpadding="0" cellspacing="0">
-                <tr>
-                  <td valign="top" style="border:5px solid #4cbdce;"><table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #ffffff;">
-                      <tr>
-                        <!-- COL LEFT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL LEFT -->
-
-                        <!-- CENTER -->
-                        <td width="460" valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 30px; font-family: Arial, Helvetica, sans-serif; color: #000;">DomiSMP<br/></td>
-                            </tr>
-                            <!-- / TITLE -->
-
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="60" height="10" style="border-bottom:3px solid #4cbdce"></td>
-                                    <td width="400" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE -->
-
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 20px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                  Credential type: ${CREDENTIAL_TYPE} is expired</td>
-                            </tr>
-                            <!-- / TITLE -->
-
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="30" height="10" style="border-bottom:3px solid #000000"></td>
-                                    <td width="430" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE -->
-
-                            <!-- MAIN CONTENT -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 13px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                <br/>
-                                  <p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p>
-                                  <p><strong>Credential identifier:</strong> ${CREDENTIAL_ID}</p>
-                                  <p><strong>Expiration date-time: </strong> ${EXPIRATION_DATETIME}</p>
-                                  <p><strong>Reporting date-time:</strong> ${REPORTING_DATETIME}</p>
-                                  <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p>
-                                  <p><strong>Server name:</strong> ${SERVER_NAME}</p>
-								</td>
-                            </tr>
-                            <!-- / MAIN CONTENT -->
-
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-                          </table></td>
-                        <!-- / CENTER -->
-                        <!-- COL RIGHT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL RIGHT -->
-                      </tr>
-                    </table></td>
-                </tr>
-              </table>
-
-              <!-- / WRAPPER --></td>
-            <!-- MARGIN RIGHT -->
-            <td width="20" valign="top"></td>
-            <!-- / MARGIN RIGHT -->
-          </tr>
-        </table>
-        </td>
-    </tr>
-  </table>
-</center>
-</body>
-</html>
diff --git a/smp-server-library/src/main/resources/alert-mail-templates/credential_imminent_expiration.ftl b/smp-server-library/src/main/resources/alert-mail-templates/credential_imminent_expiration.ftl
deleted file mode 100644
index 16783fddd3c417964a013b56eb2907203cdbb377..0000000000000000000000000000000000000000
--- a/smp-server-library/src/main/resources/alert-mail-templates/credential_imminent_expiration.ftl
+++ /dev/null
@@ -1,116 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title>DomiSMP</title>
-</head>
-<body style="margin:0; padding:0; background-color: #f1f1f1;">
-<center>
-  <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-    <tr>
-      <td><!-- MARGIN TOP -->
-
-        <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-          <tr>
-            <td>&nbsp;</td>
-          </tr>
-        </table>
-
-        <!-- / MARGIN TOP -->
-
-        <table width="540" align="center" border="0" cellspacing="0" cellpadding="0">
-          <tr>
-            <!-- MARGIN LEFT -->
-            <td width="20" valign="top">&nbsp;</td>
-            <!-- / MARGIN LEFT -->
-            <td width="500" valign="top"><!-- WRAPPER -->
-
-              <table width="500" border="0" cellpadding="0" cellspacing="0">
-                <tr>
-                  <td valign="top" style="border:5px solid #4cbdce;"><table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #ffffff;">
-                      <tr>
-                        <!-- COL LEFT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL LEFT -->
-
-                        <!-- CENTER -->
-                        <td width="460" valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 30px; font-family: Arial, Helvetica, sans-serif; color: #000;">DomiSMP<br/></td>
-                            </tr>
-                            <!-- / TITLE -->
-
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="60" height="10" style="border-bottom:3px solid #4cbdce"></td>
-                                    <td width="400" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE -->
-
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 20px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                  Credential type: ${CREDENTIAL_TYPE} imminent expiration</td>
-                            </tr>
-                            <!-- / TITLE -->
-
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="30" height="10" style="border-bottom:3px solid #000000"></td>
-                                    <td width="430" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE -->
-
-                            <!-- MAIN CONTENT -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 13px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                <br/>
-                                <p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p>
-                                <p><strong>Credential identifier:</strong> ${CREDENTIAL_ID}</p>
-                                <p><strong>Expiration date-time: </strong> ${EXPIRATION_DATETIME}</p>
-                                <p><strong>Reporting date-time:</strong> ${REPORTING_DATETIME}</p>
-                                <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p>
-								<p><strong>Server name:</strong> ${SERVER_NAME}</p>
-                              </td>
-                            </tr>
-                            <!-- / MAIN CONTENT -->
-
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-                          </table></td>
-                        <!-- / CENTER -->
-                        <!-- COL RIGHT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL RIGHT -->
-                      </tr>
-                    </table></td>
-                </tr>
-              </table>
-
-              <!-- / WRAPPER --></td>
-            <!-- MARGIN RIGHT -->
-            <td width="20" valign="top"></td>
-            <!-- / MARGIN RIGHT -->
-          </tr>
-        </table>
-
-       </td>
-    </tr>
-  </table>
-</center>
-</body>
-</html>
diff --git a/smp-server-library/src/main/resources/alert-mail-templates/credential_suspended.ftl b/smp-server-library/src/main/resources/alert-mail-templates/credential_suspended.ftl
deleted file mode 100644
index 514c228bd358df4042ed33d4921efe83f0410224..0000000000000000000000000000000000000000
--- a/smp-server-library/src/main/resources/alert-mail-templates/credential_suspended.ftl
+++ /dev/null
@@ -1,118 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title>DomiSMP</title>
-</head>
-<body style="margin:0; padding:0; background-color: #f1f1f1;">
-<center>
-  <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-    <tr>
-      <td><!-- MARGIN TOP -->
-        
-        <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-          <tr>
-            <td>&nbsp;</td>
-          </tr>
-        </table>
-        
-        <!-- / MARGIN TOP -->
-        
-        <table width="540" align="center" border="0" cellspacing="0" cellpadding="0">
-          <tr> 
-            <!-- MARGIN LEFT -->
-            <td width="20" valign="top">&nbsp;</td>
-            <!-- / MARGIN LEFT -->
-            <td width="500" valign="top"><!-- WRAPPER -->
-              
-              <table width="500" border="0" cellpadding="0" cellspacing="0">
-                <tr>
-                  <td valign="top" style="border:5px solid #4cbdce;"><table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #ffffff;">
-                      <tr> 
-                        <!-- COL LEFT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL LEFT --> 
-                        
-                        <!-- CENTER -->
-                        <td width="460" valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-                            
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 30px; font-family: Arial, Helvetica, sans-serif; color: #000;">DomiSMP<br/></td>
-                            </tr>
-                            <!-- / TITLE --> 
-                            
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="60" height="10" style="border-bottom:3px solid #4cbdce"></td>
-                                    <td width="400" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE --> 
-                            
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 20px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                  Credential type: ${CREDENTIAL_TYPE} is temporarily suspended</td>
-                            </tr>
-                            <!-- / TITLE --> 
-                            
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="30" height="10" style="border-bottom:3px solid #000000"></td>
-                                    <td width="430" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE --> 
-                            
-                            <!-- MAIN CONTENT -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 13px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                <br/>
-                                  <p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p>
-                                  <p><strong>Credential identifier:</strong> ${CREDENTIAL_ID}</p>
-                                  <p><strong>Failed login attempt count:</strong> ${FAILED_LOGIN_ATTEMPT}</p>
-                                  <p><strong>Last failed login time:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p>
-                                  <p><strong>Suspended util</strong> ${SUSPENDED_UNTIL_DATETIME}</p>
-                                  <p><strong>Reporting time:</strong> ${REPORTING_DATETIME}</p>
-                                  <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p>
-                                  <p><strong>Server name:</strong> ${SERVER_NAME}</p>
-                                </td>
-                            </tr>
-                            <!-- / MAIN CONTENT -->
-                            
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-                          </table></td>
-                        <!-- / CENTER --> 
-                        <!-- COL RIGHT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL RIGHT --> 
-                      </tr>
-                    </table></td>
-                </tr>
-              </table>
-              
-              <!-- / WRAPPER --></td>
-            <!-- MARGIN RIGHT -->
-            <td width="20" valign="top"></td>
-            <!-- / MARGIN RIGHT --> 
-          </tr>
-        </table>
-        
-       </td>
-    </tr>
-  </table>
-</center>
-</body>
-</html>
diff --git a/smp-server-library/src/main/resources/alert-mail-templates/credential_verification_failed.ftl b/smp-server-library/src/main/resources/alert-mail-templates/credential_verification_failed.ftl
deleted file mode 100644
index 08935d815b1fb04abb84d8c8fb51fc763bac3511..0000000000000000000000000000000000000000
--- a/smp-server-library/src/main/resources/alert-mail-templates/credential_verification_failed.ftl
+++ /dev/null
@@ -1,117 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title>DomiSMP</title>
-</head>
-<body style="margin:0; padding:0; background-color: #f1f1f1;">
-<center>
-  <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-    <tr>
-      <td><!-- MARGIN TOP -->
-        
-        <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-          <tr>
-            <td>&nbsp;</td>
-          </tr>
-        </table>
-        
-        <!-- / MARGIN TOP -->
-        
-        <table width="540" align="center" border="0" cellspacing="0" cellpadding="0">
-          <tr> 
-            <!-- MARGIN LEFT -->
-            <td width="20" valign="top">&nbsp;</td>
-            <!-- / MARGIN LEFT -->
-            <td width="500" valign="top"><!-- WRAPPER -->
-              
-              <table width="500" border="0" cellpadding="0" cellspacing="0">
-                <tr>
-                  <td valign="top" style="border:5px solid #4cbdce;"><table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #ffffff;">
-                      <tr> 
-                        <!-- COL LEFT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL LEFT --> 
-                        
-                        <!-- CENTER -->
-                        <td width="460" valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-                            
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 30px; font-family: Arial, Helvetica, sans-serif; color: #000;">DomiSMP<br/></td>
-                            </tr>
-                            <!-- / TITLE --> 
-                            
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="60" height="10" style="border-bottom:3px solid #4cbdce"></td>
-                                    <td width="400" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE --> 
-                            
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 20px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                  Credential type: ${CREDENTIAL_TYPE} verification failed!</td>
-                            </tr>
-                            <!-- / TITLE --> 
-                            
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="30" height="10" style="border-bottom:3px solid #000000"></td>
-                                    <td width="430" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE --> 
-                            
-                            <!-- MAIN CONTENT -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 13px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                <br/>
-                                  <p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p>
-                                  <p><strong>Credential identifier:</strong> ${CREDENTIAL_ID}</p>
-                                  <p><strong>Failed login attempt count:</strong> ${FAILED_LOGIN_ATTEMPT}</p>
-                                  <p><strong>Last failed login time:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p>
-                                  <p><strong>Reporting time:</strong> ${REPORTING_DATETIME}</p>
-                                  <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p>
-                                  <p><strong>Server name:</strong> ${SERVER_NAME}</p>
-                                </td>
-                            </tr>
-                            <!-- / MAIN CONTENT -->
-                            
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-                          </table></td>
-                        <!-- / CENTER --> 
-                        <!-- COL RIGHT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL RIGHT --> 
-                      </tr>
-                    </table></td>
-                </tr>
-              </table>
-              
-              <!-- / WRAPPER --></td>
-            <!-- MARGIN RIGHT -->
-            <td width="20" valign="top"></td>
-            <!-- / MARGIN RIGHT --> 
-          </tr>
-        </table>
-        
-       </td>
-    </tr>
-  </table>
-</center>
-</body>
-</html>
diff --git a/smp-server-library/src/main/resources/alert-mail-templates/test_mail.ftl b/smp-server-library/src/main/resources/alert-mail-templates/test_mail.ftl
deleted file mode 100644
index 5e9fcbbbda16f8b5af73684e590a2a90349d819e..0000000000000000000000000000000000000000
--- a/smp-server-library/src/main/resources/alert-mail-templates/test_mail.ftl
+++ /dev/null
@@ -1,113 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title>SMP test mail</title>
-</head>
-<body style="margin:0; padding:0; background-color: #f1f1f1;">
-<center>
-  <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-    <tr>
-      <td><!-- MARGIN TOP -->
-        
-        <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;">
-          <tr>
-            <td>&nbsp;</td>
-          </tr>
-        </table>
-        
-        <!-- / MARGIN TOP -->
-        
-        <table width="540" align="center" border="0" cellspacing="0" cellpadding="0">
-          <tr> 
-            <!-- MARGIN LEFT -->
-            <td width="20" valign="top">&nbsp;</td>
-            <!-- / MARGIN LEFT -->
-            <td width="500" valign="top"><!-- WRAPPER -->
-              
-              <table width="500" border="0" cellpadding="0" cellspacing="0">
-                <tr>
-                  <td valign="top" style="border:5px solid #4cbdce;"><table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #ffffff;">
-                      <tr> 
-                        <!-- COL LEFT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL LEFT --> 
-                        
-                        <!-- CENTER -->
-                        <td width="460" valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-                            
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 30px; font-family: Arial, Helvetica, sans-serif; color: #000;">SMP<br/></td>
-                            </tr>
-                            <!-- / TITLE --> 
-                            
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="60" height="10" style="border-bottom:3px solid #4cbdce"></td>
-                                    <td width="400" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE --> 
-                            
-                            <!-- TITLE -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 20px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                Test mail submission</td>
-                            </tr>
-                            <!-- / TITLE --> 
-                            
-                            <!-- UNDERLINE -->
-                            <tr>
-                              <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
-                                  <tr>
-                                    <td width="30" height="10" style="border-bottom:3px solid #000000"></td>
-                                    <td width="430" height="5"></td>
-                                  </tr>
-                                </table></td>
-                            </tr>
-                            <!-- / UNDERLINE --> 
-                            
-                            <!-- MAIN CONTENT -->
-                            <tr>
-                              <td valign="top" align="left" style=" font-size: 13px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
-                                <br/>
-                                  <p><strong>User:</strong> ${USERNAME}</p>
-                                  <p><strong>User mail:</strong> ${USER_MAIL}</p>
-                                  <p><strong>Server name:</strong> ${SERVER_NAME}</p>
-                                </td>
-                            </tr>
-                            <!-- / MAIN CONTENT -->
-                            
-                            <tr>
-                              <td height="20" valign="top">&nbsp;</td>
-                            </tr>
-                          </table></td>
-                        <!-- / CENTER --> 
-                        <!-- COL RIGHT -->
-                        <td width="20" valign="top">&nbsp;</td>
-                        <!-- / COL RIGHT --> 
-                      </tr>
-                    </table></td>
-                </tr>
-              </table>
-              
-              <!-- / WRAPPER --></td>
-            <!-- MARGIN RIGHT -->
-            <td width="20" valign="top"></td>
-            <!-- / MARGIN RIGHT --> 
-          </tr>
-        </table>
-        
-       </td>
-    </tr>
-  </table>
-</center>
-</body>
-</html>
\ No newline at end of file
diff --git a/smp-server-library/src/main/resources/mail-messages/mail-messages_en.properties b/smp-server-library/src/main/resources/mail-messages/mail-messages_en.properties
new file mode 100644
index 0000000000000000000000000000000000000000..c25075d8eef1b204c47ece8af950562d0c492049
--- /dev/null
+++ b/smp-server-library/src/main/resources/mail-messages/mail-messages_en.properties
@@ -0,0 +1,64 @@
+# Email translations. Each email has a header, title, content and footer. The texts are can be HTML formatted.
+# The header and footer are common for all emails and should describe instance and purpose of the application.
+# The title and content are specific for each email type.
+
+mail.header=eDelivery DomiSMP sample: ${SMP_INSTANCE_NAME}
+mail.footer=DomiSMP instance: ${SMP_INSTANCE_NAME} (${SERVER_NAME}), ${CURRENT_DATETIME}
+
+# Email texts for password reset
+mail.test_mail.title=Test mail: ${CREDENTIAL_TYPE} on DomiSMP ${SMP_INSTANCE_NAME}
+mail.test_mail.content=This is a test mail from DomiSMP instance: ${SMP_INSTANCE_NAME} for your user account.
+
+
+# Email texts for password reset
+mail.credential_request_reset.title=Request for reset of the Credential type: ${CREDENTIAL_TYPE} on DomiSMP ${SMP_INSTANCE_NAME}
+mail.credential_request_reset.content=You're receiving this e-mail because you requested a credential type: ${CREDENTIAL_TYPE} \
+  reset on DomiSMP ${SMP_INSTANCE_NAME} for your user account. <br/> Please go to the following page and choose a new password: \
+  <br/> <br/> <a href="${RESET_URL}">${RESET_URL}</a> <br/> <br/> The link is valid for a short period of time. If the \
+  link has expired, please request a new one.
+
+
+mail.credential_changed.title=Credential type: ${CREDENTIAL_TYPE} on DomiSMP ${SMP_INSTANCE_NAME} changed!
+mail.credential_changed.content=You're receiving this e-mail because your credential type: ${CREDENTIAL_TYPE} changed  \
+  on DomiSMP ${SMP_INSTANCE_NAME}! <p>If you did not update your credential, please inform DomiSMP administrator \
+  immediately.</p><br>If you are having trouble accessing your account, reset your password. 
+
+# Email texts for credential expired
+mail.credential_expired.title=Credential type: ${CREDENTIAL_TYPE} is expired
+mail.credential_expired.content=<p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p> \
+  <p><strong>Credential identifier:</strong> ${CREDENTIAL_ID}</p> \
+  <p><strong>Expiration date-time: </strong> ${EXPIRATION_DATETIME}</p> \
+  <p><strong>Reporting date-time:</strong> ${REPORTING_DATETIME}</p> \
+  <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p> \
+  <p><strong>SMP instance name:</strong> ${SMP_INSTANCE_NAME}</p>.
+
+# Email texts for credential imminent expiration}
+mail.credential_imminent_expiration.title=Credential type: ${CREDENTIAL_TYPE} imminent expiration
+mail.credential_imminent_expiration.content=<p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p>\
+  <p><strong>Credential identifier:</strong> ${CREDENTIAL_ID}</p>\
+  <p><strong>Expiration date-time: </strong> ${EXPIRATION_DATETIME}</p>\
+  <p><strong>Reporting date-time:</strong> ${REPORTING_DATETIME}</p>\
+  <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p>\
+  <p><strong>SMP instance name:</strong> ${SMP_INSTANCE_NAME}</p>
+
+# Email texts for credential suspended
+mail.credential_suspended.title=Credential type: ${CREDENTIAL_TYPE} is temporarily suspended
+mail.credential_suspended.content=<p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p> \
+  <p><strong>Credential identifier:</strong> ${CREDENTIAL_ID}</p> \
+  <p><strong>Failed login attempt count:</strong> ${FAILED_LOGIN_ATTEMPT}</p> \
+  <p><strong>Last failed login time:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p> \
+  <p><strong>Suspended util</strong> ${SUSPENDED_UNTIL_DATETIME}</p> \
+  <p><strong>Reporting time:</strong> ${REPORTING_DATETIME}</p> \
+  <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p> \
+  <p><strong>SMP instance name:</strong> ${SMP_INSTANCE_NAME}</p>
+
+# Email texts for credential verification failed
+mail.credential_verification_failed.title=Credential type: ${CREDENTIAL_TYPE} verification failed!
+mail.credential_verification_failed.content=<p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p> \
+  <p><strong>Credential identifier:</strong> ${CREDENTIAL_ID}</p> \
+  <p><strong>Failed login attempt count:</strong> ${FAILED_LOGIN_ATTEMPT}</p> \
+  <p><strong>Last failed login time:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p> \
+  <p><strong>Reporting time:</strong> ${REPORTING_DATETIME}</p> \
+  <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p> \
+  <p><strong>SMP instance name:</strong> ${SMP_INSTANCE_NAME}</p>
+
diff --git a/smp-server-library/src/main/resources/mail-messages/mail-messages_ro.properties b/smp-server-library/src/main/resources/mail-messages/mail-messages_ro.properties
new file mode 100644
index 0000000000000000000000000000000000000000..7db7607c94388c2af38a607df549054f149a9939
--- /dev/null
+++ b/smp-server-library/src/main/resources/mail-messages/mail-messages_ro.properties
@@ -0,0 +1,63 @@
+# Traduceri prin e-mail. Fiecare e-mail are un antet, titlu, con?inut ?i subsol. Textele pot fi formatate HTML.
+# Antetul ?i subsolul sunt comune pentru toate e-mailurile ?i ar trebui s? descrie instan?a ?i scopul aplica?iei.
+# Titlul ?i con?inutul sunt specifice fiec?rui tip de e-mail.
+
+mail.header=eDelivery E?antion DomiSMP: ${SMP_INSTANCE_NAME}
+mail.footer=Instan?? DomiSMP: ${SMP_INSTANCE_NAME} (${SERVER_NAME}), ${CURRENT_DATETIME}
+
+# Texte de e-mail pentru resetarea parolei
+mail.test_mail.title=E-mail de testare: ${CREDENTIAL_TYPE} pe DomiSMP ${SMP_INSTANCE_NAME}
+mail.test_mail.content=Acesta este un e-mail de test de la instan?a DomiSMP: ${SMP_INSTANCE_NAME} pentru contul dvs. de utilizator.
+
+# Texte de e-mail pentru resetarea parolei
+mail.credential_request_reset.title=Solicitare de resetare a tipului de autentificare: ${CREDENTIAL_TYPE} pe DomiSMP ${SMP_INSTANCE_NAME}
+mail.credential_request_reset.content=Primi?i acest e-mail deoarece a?i solicitat un tip de autentificare: ${CREDENTIAL_TYPE} \
+   reseta?i pe DomiSMP ${SMP_INSTANCE_NAME} pentru contul dvs. de utilizator. <br/> Accesa?i urm?toarea pagin? ?i alege?i o nou? parol?: \
+   <br/> <br/> <a href="${RESET_URL}">${RESET_URL}</a> <br/> <br/> Linkul este valabil pentru o perioad? scurt? de timp. Dac? \
+   linkul a expirat, v? rug?m s? solicita?i unul nou.
+
+
+mail.credential_changed.title=Tipul de autentificare: ${CREDENTIAL_TYPE} pe DomiSMP ${SMP_INSTANCE_NAME} schimbat!
+mail.credential_changed.content=Primi?i acest e-mail deoarece tipul dvs. de autentificare: ${CREDENTIAL_TYPE} s-a schimbat \
+   pe DomiSMP ${SMP_INSTANCE_NAME}! <p>Dac? nu v-a?i actualizat acredit?rile, v? rug?m s? informa?i administratorul DomiSMP \
+   imediat.</p><br>Dac? întâmpina?i probleme la accesarea contului, reseta?i-v? parola.
+
+# Textele de e-mail pentru acredit?ri au expirat
+mail.credential_expired.title=Tipul acredit?rii: ${CREDENTIAL_TYPE} a expirat
+mail.credential_expired.content=<p><strong>Tipul de autentificare:</strong> ${CREDENTIAL_TYPE}</p> \
+   <p><strong>Identificator de acreditare:</strong> ${CREDENTIAL_ID}</p> \
+   <p><strong>Data-ora expir?rii: </strong> ${EXPIRATION_DATETIME}</p> \
+   <p><strong>Data-ora raport?rii:</strong> ${REPORTING_DATETIME}</p> \
+   <p><strong>Nivel alert?:</strong> ${ALERT_LEVEL}</p> \
+   <p><strong>Numele instan?ei SMP:</strong> ${SMP_INSTANCE_NAME}</p>.
+
+# Texte de e-mail pentru expirarea iminent? a acredit?rii}
+mail.credential_imminent_expiration.title=Tipul acredit?rii: ${CREDENTIAL_TYPE} expirare iminent?
+mail.credential_imminent_expiration.content=<p><strong>Tipul de autentificare:</strong> ${CREDENTIAL_TYPE}</p>\
+   <p><strong>Identificator de acreditare:</strong> ${CREDENTIAL_ID}</p>\
+   <p><strong>Data-ora expir?rii: </strong> ${EXPIRATION_DATETIME}</p>\
+   <p><strong>Data-ora raport?rii:</strong> ${REPORTING_DATETIME}</p>\
+   <p><strong>Nivel alert?:</strong> ${ALERT_LEVEL}</p>\
+   <p><strong>Numele instan?ei SMP:</strong> ${SMP_INSTANCE_NAME}</p>
+
+# Texte de e-mail pentru acredit?ri suspendate
+mail.credential_suspended.title=Tipul de autentificare: ${CREDENTIAL_TYPE} este suspendat temporar
+mail.credential_suspended.content=<p><strong>Tipul de autentificare:</strong> ${CREDENTIAL_TYPE}</p> \
+   <p><strong>Identificator de acreditare:</strong> ${CREDENTIAL_ID}</p> \
+   <p><strong>Num?r de încerc?ri de conectare e?uate:</strong> ${FAILED_LOGIN_ATTEMPT}</p> \
+   <p><strong>Ultima or? de conectare e?uat?:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p> \
+   <p><strong>Util suspendat</strong> ${SUSPENDED_UNTIL_DATETIME}</p> \
+   <p><strong>Timp de raportare:</strong> ${REPORTING_DATETIME}</p> \
+   <p><strong>Nivel alert?:</strong> ${ALERT_LEVEL}</p> \
+   <p><strong>Numele instan?ei SMP:</strong> ${SMP_INSTANCE_NAME}</p>
+
+# Texte prin e-mail pentru verificarea acredit?rilor e?uate
+mail.credential_verification_failed.title=Tipul de autentificare: verificarea ${CREDENTIAL_TYPE} a e?uat!
+mail.credential_verification_failed.content=<p><strong>Tipul de autentificare:</strong> ${CREDENTIAL_TYPE}</p> \
+   <p><strong>Identificator de autentificare:</strong> ${CREDENTIAL_ID}</p> \
+   <p><strong>Num?r de încerc?ri de conectare e?uate:</strong> ${FAILED_LOGIN_ATTEMPT}</p> \
+   <p><strong>Ultima or? de conectare e?uat?:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p> \
+   <p><strong>Timp de raportare:</strong> ${REPORTING_DATETIME}</p> \
+   <p><strong>Nivel alert?:</strong> ${ALERT_LEVEL}</p> \
+   <p><strong>Numele instan?ei SMP:</strong> ${SMP_INSTANCE_NAME}</p>
+
diff --git a/smp-server-library/src/main/resources/mail-messages/mail-messages_sl.properties b/smp-server-library/src/main/resources/mail-messages/mail-messages_sl.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f177e0c5d37b3d3df014267df6473d32c6d64551
--- /dev/null
+++ b/smp-server-library/src/main/resources/mail-messages/mail-messages_sl.properties
@@ -0,0 +1,64 @@
+# Prevodi e-po?te.
+# Vsako e-po?tno sporo?ilo ima glavo, naslov, vsebino in nogo. Besedila so lahko oblikovana v HTML.
+# Glava in noga sta skupni za vsa e-po?tna sporo?ila in bi morali opisovati primerek in namen aplikacije.
+# Naslov in vsebina sta specifi?na za vsako vrsto e-po?te.
+
+mail.header=eDelivery DomiSMP: ${SMP_INSTANCE_NAME}
+mail.footer=PNaziv SMP streznika: ${SMP_INSTANCE_NAME} (${SERVER_NAME}), ${CURRENT_DATETIME}
+
+# E-po?tna besedila za ponastavitev gesla
+mail.test_mail.title=Testno sporo?ilo: ${CREDENTIAL_TYPE} na DomiSMP ${SMP_INSTANCE_NAME}
+mail.test_mail.content=To je testna po?ta DomiSMP sreznika: ${SMP_INSTANCE_NAME} za va? uporabni?ki ra?un.
+
+
+# E-po?tna besedila za ponastavitev gesla
+mail.credential_request_reset.title=Zahteva za ponastavitev vrste poverilnice: ${CREDENTIAL_TYPE} na DomiSMP ${SMP_INSTANCE_NAME}
+mail.credential_request_reset.content=To e-po?to ste prejeli, ker ste zahtevali vrsto poverilnice: ${CREDENTIAL_TYPE} \
+   ponastavite na DomiSMP ${SMP_INSTANCE_NAME} za va? uporabni?ki ra?un. <br/> Pojdite na naslednjo stran in izberite novo geslo: \
+   <br/> <br/> <a href="${RESET_URL}">${RESET_URL}</a> <br/> <br/> Povezava je veljavna kratek ?as. ?e \
+   povezava je potekla, zahtevajte novo.
+
+
+mail.credential_changed.title=Vrsta poverilnice: ${CREDENTIAL_TYPE} na DomiSMP ${SMP_INSTANCE_NAME} spremenjena!
+mail.credential_changed.content=To e-po?to ste prejeli, ker je va?a vrsta poverilnice: ${CREDENTIAL_TYPE} spremenjena \
+   na DomiSMP ${SMP_INSTANCE_NAME}! <p>?e niste posodobili svoje poverilnice, obvestite skrbnika DomiSMP \
+   takoj.</p><br>?e imate te?ave z dostopom do ra?una, ponastavite geslo.
+
+# Besedila e-po?te za poverilnico so potekla
+mail.credential_expired.title=Vrsta poverilnice: ${CREDENTIAL_TYPE} je potekla
+mail.credential_expired.content=<p><strong>Vrsta poverilnice:</strong> ${CREDENTIAL_TYPE}</p> \
+   <p><strong>Identifikator poverilnice:</strong> ${CREDENTIAL_ID}</p> \
+   <p><strong>Datum-?as poteka: </strong> ${EXPIRATION_DATETIME}</p> \
+   <p><strong>Datum in ?as poro?anja:</strong> ${REPORTING_DATETIME}</p> \
+   <p><strong>Raven opozorila:</strong> ${ALERT_LEVEL}</p> \
+   <p><strong>Naziv SMP streznika::</strong> ${SMP_INSTANCE_NAME}</p>.
+
+# Besedila e-po?te za poverilnico pred skoraj?njim iztekom}
+mail.credential_imminent_expiration.title=Vrsta poverilnice: ${CREDENTIAL_TYPE} skoraj?nji potek
+mail.credential_imminent_expiration.content=<p><strong>Vrsta poverilnice:</strong> ${CREDENTIAL_TYPE}</p>\
+   <p><strong>Identifikator poverilnice:</strong> ${CREDENTIAL_ID}</p>\
+   <p><strong>Datum-?as poteka: </strong> ${EXPIRATION_DATETIME}</p>\
+   <p><strong>Datum in ?as poro?anja:</strong> ${REPORTING_DATETIME}</p>\
+   <p><strong>Raven opozorila:</strong> ${ALERT_LEVEL}</p>\
+   <p><strong>Naziv SMP streznika::</strong> ${SMP_INSTANCE_NAME}</p>
+
+# Besedila e-po?te za poverilnice so za?asno ustavljena
+mail.credential_suspended.title=Vrsta poverilnice: ${CREDENTIAL_TYPE} je za?asno onemogo?ena
+mail.credential_suspended.content=<p><strong>Vrsta poverilnice:</strong> ${CREDENTIAL_TYPE}</p> \
+   <p><strong>Identifikator poverilnice:</strong> ${CREDENTIAL_ID}</p> \
+   <p><strong>?tevilo neuspelih poskusov prijave:</strong> ${FAILED_LOGIN_ATTEMPT}</p> \
+   <p><strong>?as zadnje neuspe?ne prijave:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p> \
+   <p><strong>Za?asno ustavljen</strong> ${SUSPENDED_UNTIL_DATETIME}</p> \
+   <p><strong>?as poro?anja:</strong> ${REPORTING_DATETIME}</p> \
+   <p><strong>Raven opozorila:</strong> ${ALERT_LEVEL}</p> \
+   <p><strong>Naziv SMP streznika::</strong> ${SMP_INSTANCE_NAME}</p>
+
+# E-po?tna besedila za preverjanje poverilnice niso uspela
+mail.credential_verification_failed.title=Vrsta poverilnice: ${CREDENTIAL_TYPE} preverjanje ni uspelo!
+mail.credential_verification_failed.content=<p><strong>Vrsta poverilnice:</strong> ${CREDENTIAL_TYPE}</p> \
+   <p><strong>Identifikator poverilnice:</strong> ${CREDENTIAL_ID}</p> \
+   <p><strong>?tevilo neuspelih poskusov prijave:</strong> ${FAILED_LOGIN_ATTEMPT}</p> \
+   <p><strong>?as zadnje neuspe?ne prijave:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p> \
+   <p><strong>?as poro?anja:</strong> ${REPORTING_DATETIME}</p> \
+   <p><strong>Raven opozorila:</strong> ${ALERT_LEVEL}</p> \
+   <p><strong>Naziv SMP streznika::</strong> ${SMP_INSTANCE_NAME}</p>
diff --git a/smp-server-library/src/main/resources/mail-messages/mail-template.htm b/smp-server-library/src/main/resources/mail-messages/mail-template.htm
new file mode 100644
index 0000000000000000000000000000000000000000..e46c7315084b698e237dcf020ef3692d7300cedb
--- /dev/null
+++ b/smp-server-library/src/main/resources/mail-messages/mail-template.htm
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <title>${MAIL_HEADER}</title>
+</head>
+<body style="margin: 0;padding: 0;background-color: #f1f1f1;">
+<div style="display: flex;flex-direction: column;align-items: center;padding: 3em;">
+    <div style="padding: 2em;width: 100%;max-width: 1280px;background-color: white;border: 5px solid #4cbdce;">
+        <div style="font-size: 30px;font-family: Arial, Helvetica, sans-serif;color: black;">
+            ${MAIL_HEADER}
+        </div>
+        <hr style="border: 4px solid #4cbdce;border-radius: 4px;max-width: 150px;margin: 0.2em 0 1.5em 0;">
+        <div style="font-size: 20px;font-family: Arial, Helvetica, sans-serif;color: #000;">
+            ${MAIL_TITLE}
+        </div>
+        <hr style="border: 3px solid black;border-radius: 3px;max-width: 120px;margin: 0.2em 0 1.5em 0;">
+        <div style="margin-top: 2em;font-size: 14px;font-family: Arial, Helvetica, sans-serif;color: #000;">
+            ${MAIL_CONTENT}
+        </div>
+        <div style="border-top: 1px solid black;text-align: center;margin: 4em -3em -3em -3em;padding: 0.5em;font-size: 10px;font-family: Arial, Helvetica, sans-serif;color: #000;">
+            ${MAIL_FOOTER}
+        </div>
+    </div>
+</div>
+
+</body>
+</html>
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AlertServiceTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AlertServiceTest.java
index 2493a8b856a3211b5abafe12b7894b2959a070ac..fce94e65088329e9deb01e6df51ea998d493138b 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AlertServiceTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AlertServiceTest.java
@@ -8,9 +8,9 @@
  * versions of the EUPL (the "Licence");
  * You may not use this work except in compliance with the Licence.
  * You may obtain a copy of the Licence at:
- * 
+ *
  * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
  * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the Licence for the specific language governing permissions and limitations under the Licence.
@@ -28,12 +28,13 @@ import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
 import eu.europa.ec.edelivery.smp.data.ui.enums.AlertLevelEnum;
 import eu.europa.ec.edelivery.smp.data.ui.enums.AlertStatusEnum;
 import eu.europa.ec.edelivery.smp.data.ui.enums.AlertTypeEnum;
-import eu.europa.ec.edelivery.smp.services.mail.MailModel;
+import eu.europa.ec.edelivery.smp.services.mail.MailDataModel;
 import eu.europa.ec.edelivery.smp.services.mail.MailService;
 import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialSuspendedProperties;
 import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialVerificationFailedProperties;
 import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialsExpirationProperties;
 import eu.europa.ec.edelivery.smp.testutil.TestDBUtils;
+import eu.europa.ec.edelivery.smp.utils.SmpUrlBuilder;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
@@ -41,7 +42,6 @@ import org.mockito.Mockito;
 import java.time.OffsetDateTime;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Properties;
 import java.util.stream.Collectors;
 
 import static org.junit.Assert.*;
@@ -54,10 +54,17 @@ public class AlertServiceTest {
     ConfigurationService configurationService = Mockito.mock(ConfigurationService.class);
     UserDao userDao = Mockito.mock(UserDao.class);
     CredentialDao credentialDao = Mockito.mock(CredentialDao.class);
+    SmpUrlBuilder smpUrlBuilder = Mockito.mock(SmpUrlBuilder.class);
     SMPDynamicCronTrigger alertCronTrigger = Mockito.mock(SMPDynamicCronTrigger.class);
 
 
-    CredentialsAlertService testInstance = new CredentialsAlertService(alertDao, mailService, configurationService, userDao, credentialDao, alertCronTrigger);
+    CredentialsAlertService testInstance = new CredentialsAlertService(alertDao,
+            mailService,
+            configurationService,
+            userDao,
+            credentialDao,
+            smpUrlBuilder,
+            alertCronTrigger);
 
     @Test
     public void testCreateAlert() {
@@ -85,8 +92,9 @@ public class AlertServiceTest {
     public void testSubmitAlertMailNoMail() {
 
         DBAlert alert = new DBAlert();
+        DBUser user = Mockito.mock(DBUser.class);
 
-        testInstance.submitAlertMail(alert);
+        testInstance.submitAlertMail(alert, user);
 
         verify(mailService, Mockito.never()).sendMail(Mockito.any(), Mockito.anyString(), Mockito.anyString());
     }
@@ -105,7 +113,7 @@ public class AlertServiceTest {
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
 
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialsExpirationProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialsExpirationProperties.values())
                 .map(CredentialsExpirationProperties::name).collect(Collectors.toList());
         // when
         testInstance.alertBeforeCredentialExpire(credential);
@@ -132,7 +140,7 @@ public class AlertServiceTest {
         doReturn(alertLevel).when(configurationService).getAlertExpiredPasswordLevel();
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_EXPIRED;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialsExpirationProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialsExpirationProperties.values())
                 .map(CredentialsExpirationProperties::name).collect(Collectors.toList());
         // when
         testInstance.alertCredentialExpired(credential);
@@ -159,7 +167,7 @@ public class AlertServiceTest {
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
 
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialsExpirationProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialsExpirationProperties.values())
                 .map(CredentialsExpirationProperties::name).collect(Collectors.toList());
         // when
         testInstance.alertBeforeCredentialExpire(credential);
@@ -185,7 +193,7 @@ public class AlertServiceTest {
         doReturn(alertLevel).when(configurationService).getAlertExpiredAccessTokenLevel();
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_EXPIRED;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialsExpirationProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialsExpirationProperties.values())
                 .map(CredentialsExpirationProperties::name).collect(Collectors.toList());
         // when
         testInstance.alertCredentialExpired(credential);
@@ -210,7 +218,7 @@ public class AlertServiceTest {
         doReturn(alertLevel).when(configurationService).getAlertBeforeExpireCertificateLevel();
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialsExpirationProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialsExpirationProperties.values())
                 .map(CredentialsExpirationProperties::name).collect(Collectors.toList());
         // when
         testInstance.alertBeforeCredentialExpire(credential);
@@ -235,7 +243,7 @@ public class AlertServiceTest {
         doReturn(alertLevel).when(configurationService).getAlertExpiredCertificateLevel();
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_EXPIRED;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialsExpirationProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialsExpirationProperties.values())
                 .map(CredentialsExpirationProperties::name).collect(Collectors.toList());
 
         // when
@@ -254,7 +262,10 @@ public class AlertServiceTest {
         String mailTo = "test.mail@domain.eu";
         String mailFrom = "test.mail@domain.eu";
         String mailSubject = "mailSubject";
+        String language = "en";
         AlertTypeEnum template = AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION;
+        DBUser user = Mockito.mock(DBUser.class);
+        doReturn(language).when(user).getSmpLocale();
         DBAlert alert = new DBAlert();
         alert.setAlertType(template);
         alert.setMailTo(mailTo);
@@ -262,9 +273,9 @@ public class AlertServiceTest {
         alert.addProperty("test", "testValue");
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
 
-        testInstance.submitAlertMail(alert);
+        testInstance.submitAlertMail(alert, user);
 
-        ArgumentCaptor<MailModel<Properties>> argModel = ArgumentCaptor.forClass(MailModel.class);
+        ArgumentCaptor<MailDataModel> argModel = ArgumentCaptor.forClass(MailDataModel.class);
         ArgumentCaptor<String> argMailTo = ArgumentCaptor.forClass(String.class);
         ArgumentCaptor<String> argFrom = ArgumentCaptor.forClass(String.class);
 
@@ -274,9 +285,9 @@ public class AlertServiceTest {
 
         assertEquals(mailTo, argMailTo.getValue());
         assertEquals(mailFrom, argFrom.getValue());
-        assertEquals(mailSubject, argModel.getValue().getSubject());
-        assertEquals(template.getTemplate(), argModel.getValue().getTemplatePath());
-        assertEquals(1, argModel.getValue().getModel().size());
+        assertEquals(AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION, argModel.getValue().getMailType());
+        assertEquals(language, argModel.getValue().getLanguage());
+        assertEquals(3, argModel.getValue().getModel().size());
     }
 
     @Test
@@ -297,7 +308,7 @@ public class AlertServiceTest {
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
 
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_VERIFICATION_FAILED;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialVerificationFailedProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialVerificationFailedProperties.values())
                 .map(CredentialVerificationFailedProperties::name).collect(Collectors.toList());
 
         // when
@@ -329,7 +340,7 @@ public class AlertServiceTest {
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
         //doReturn(123456).when(configurationService).getLoginSuspensionTimeInSeconds();
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_VERIFICATION_FAILED;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialVerificationFailedProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialVerificationFailedProperties.values())
                 .map(CredentialVerificationFailedProperties::name).collect(Collectors.toList());
 
         // when
@@ -361,7 +372,7 @@ public class AlertServiceTest {
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
         doReturn(123456).when(configurationService).getLoginSuspensionTimeInSeconds();
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_SUSPENDED;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialSuspendedProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialSuspendedProperties.values())
                 .map(CredentialSuspendedProperties::name).collect(Collectors.toList());
 
         // when
@@ -394,7 +405,7 @@ public class AlertServiceTest {
         doReturn(mailFrom).when(configurationService).getAlertEmailFrom();
         doReturn(123456).when(configurationService).getLoginSuspensionTimeInSeconds();
         AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_SUSPENDED;
-        List<String> expectedTemplateProperties = Arrays.asList(CredentialSuspendedProperties.values()).stream()
+        List<String> expectedTemplateProperties = Arrays.stream(CredentialSuspendedProperties.values())
                 .map(CredentialSuspendedProperties::name).collect(Collectors.toList());
 
         // when
@@ -412,7 +423,7 @@ public class AlertServiceTest {
     public void assertAlertSend(AlertTypeEnum alertType, String mailTo, String mailFrom, String mailSubject,
                                 List<String> templateProperties) {
 
-        ArgumentCaptor<MailModel<Properties>> argModel = ArgumentCaptor.forClass(MailModel.class);
+        ArgumentCaptor<MailDataModel> argModel = ArgumentCaptor.forClass(MailDataModel.class);
         ArgumentCaptor<String> argMailFrom = ArgumentCaptor.forClass(String.class);
         ArgumentCaptor<String> argMailTo = ArgumentCaptor.forClass(String.class);
         ArgumentCaptor<DBAlert> argAlert = ArgumentCaptor.forClass(DBAlert.class);
@@ -429,16 +440,16 @@ public class AlertServiceTest {
         assertEquals(mailFrom, argMailFrom.getValue());
 
 
-        MailModel<Properties> model = argModel.getValue();
-        assertEquals(alertType.getTemplate(), model.getTemplatePath());
-        assertEquals(mailSubject, model.getSubject());
+        MailDataModel model = argModel.getValue();
+        assertEquals(alertType, model.getMailType());
+        assertEquals("en", model.getLanguage());
 
         // test to contain all properties
         for (String prop : templateProperties) {
-
             assertTrue(prop, model.getModel().containsKey(prop));
         }
-        assertEquals(templateProperties.size(), model.getModel().size());
+        // add two common properties: CURRENT_DATETIME, SMP_INSTANCE_NAME
+        assertEquals(templateProperties.size() + 2, model.getModel().size());
     }
 
 
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/mail/MailServiceTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/mail/MailServiceTest.java
index d2140910022ca3376e10c2fdb7cb0d09f87dab74..6ba282546fb3bf6428359cc74056fa261a3f6d15 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/mail/MailServiceTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/mail/MailServiceTest.java
@@ -30,6 +30,8 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
 import org.springframework.test.context.ContextConfiguration;
 
 import javax.mail.internet.MimeMessage;
+import java.util.HashMap;
+import java.util.Map;
 
 @ContextConfiguration(classes = {MockAlertBeans.class, MailService.class})
 public class MailServiceTest extends AbstractServiceIntegrationTest {
@@ -45,12 +47,15 @@ public class MailServiceTest extends AbstractServiceIntegrationTest {
     public void testSendMail() {
 
         Mockito.doNothing().when(mockJavaMailSender).send((MimeMessage) Mockito.any());
+        Map<String, String> props = new HashMap<>();
 
-        PropertiesMailModel props = new PropertiesMailModel(AlertTypeEnum.TEST_ALERT.getTemplate(), "testMail");
-        props.setProperty(TestMailProperties.SERVER_NAME.name(), "server name");
-        props.setProperty(TestMailProperties.USERNAME.name(), "username");
-        props.setProperty(TestMailProperties.USER_MAIL.name(), "test@test-receiver-mail.eu");
-        testInstance.sendMail(props, "test@test-sender-mail.eu", "test@test-receiver-mail.eu");
+        props.put(TestMailProperties.SERVER_NAME.name(), "server name");
+        props.put(TestMailProperties.USERNAME.name(), "username");
+        props.put(TestMailProperties.USER_MAIL.name(), "test@test-receiver-mail.eu");
+
+        MailDataModel data = new MailDataModel("en", AlertTypeEnum.TEST_ALERT, props);
+
+        testInstance.sendMail(data, "test@test-sender-mail.eu", "test@test-receiver-mail.eu");
 
         Mockito.verify(mockJavaMailSender, Mockito.times(1)).send((MimeMessage) Mockito.any());
     }
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/mail/MailTemplateTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/mail/MailTemplateTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d18d2594e07a6e168e846c2cef806e1b0e4093f
--- /dev/null
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/mail/MailTemplateTest.java
@@ -0,0 +1,56 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.services.mail;
+
+import eu.europa.ec.edelivery.smp.data.ui.enums.AlertTypeEnum;
+import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialsExpirationProperties;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class MailTemplateTest {
+
+
+    MailTemplateService testInstance = new MailTemplateService();
+
+    @Test
+    void getMailContent() {
+
+        Map<String, String> props = new HashMap<>();
+        props.put(CredentialsExpirationProperties.ALERT_LEVEL.name(), "alert level");
+        props.put(CredentialsExpirationProperties.CREDENTIAL_ID.name(), "credential id");
+        props.put(CredentialsExpirationProperties.CREDENTIAL_TYPE.name(), "credential name");
+        props.put(CredentialsExpirationProperties.EXPIRATION_DATETIME.name(), "expiration date");
+        props.put(CredentialsExpirationProperties.REPORTING_DATETIME.name(), "reporting date");
+        props.put(CredentialsExpirationProperties.SERVER_NAME.name(), "server name");
+
+        MailDataModel model = new MailDataModel("en", AlertTypeEnum.CREDENTIAL_EXPIRED, props);
+
+        String result = testInstance.getMailHtmlContent(model);
+        assertNotNull(result);
+        assertTrue(result.contains("alert level"));
+        assertTrue(result.contains("credential id"));
+        assertTrue(result.contains("credential name"));
+
+    }
+}
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java
index a3b78db06d54512f54f6517ad48291def5f6c977..13f490aac2f0ee6df79c88662ecc8598d86d6c2c 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java
@@ -324,6 +324,7 @@ public class TestDBUtils {
     public static DBUser createDBUserByUsername(String userName) {
         DBUser dbuser = new DBUser();
         dbuser.setUsername(userName);
+        dbuser.setSmpLocale("en");
         dbuser.setEmailAddress(userName + "@test.eu");
         dbuser.setActive(true);
         dbuser.setApplicationRole(ApplicationRoleType.USER);
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/StringNamedSubstitutorTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/StringNamedSubstitutorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a0b465c62c1712685f44b0b661006348050e9022
--- /dev/null
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/StringNamedSubstitutorTest.java
@@ -0,0 +1,53 @@
+/*-
+ * #START_LICENSE#
+ * smp-server-library
+ * %%
+ * Copyright (C) 2017 - 2023 European Commission | eDelivery | DomiSMP
+ * %%
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent
+ * versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ *
+ * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ * #END_LICENSE#
+ */
+package eu.europa.ec.edelivery.smp.utils;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class StringNamedSubstitutorTest {
+
+
+    @ParameterizedTest
+    @CsvSource({
+            "'The quick ${FOX_COLOR} fox jumps over the ${DOG_MODE} dog', " +
+                    "'FOX_COLOR=red;DOG_MODE=slow', " +
+                    "'The quick red fox jumps over the slow dog'",
+            "'The quick ${fox_COLOR} fox jumps over the ${dog_MODE} dog', " +
+                    "'FOX_COLOR=red;DOG_MODE=slow', " +
+                    "'The quick red fox jumps over the slow dog'",
+            "'The quick ${FOX_COLOR} fox jumps over the ${DOG_MODE} dog', " +
+                    "'FOX_COLOR=red', " +
+                    "'The quick red fox jumps over the ${DOG_MODE} dog'",
+    })
+    void resolve(String testString, String values, String expected) {
+        Map<String, String> mapVal = Stream.of(values.split("\\s*;\\s*"))
+                .map(s -> s.split("\\s*=\\s*"))
+                .collect(HashMap::new, (m, v) -> m.put(v[0], v[1]), Map::putAll);
+
+        String result = StringNamedSubstitutor.resolve(testString, mapVal);
+        assertEquals(expected, result);
+    }
+}
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationService.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationService.java
index 0de18387029fcb166d789e169391afaeca40d3f2..4ff89507f36b96b12a04f644f3f16dc7cdf21f45 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationService.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationService.java
@@ -8,9 +8,9 @@
  * versions of the EUPL (the "Licence");
  * You may not use this work except in compliance with the Licence.
  * You may obtain a copy of the Licence at:
- * 
+ *
  * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
  * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the Licence for the specific language governing permissions and limitations under the Licence.
@@ -19,8 +19,10 @@
 package eu.europa.ec.edelivery.smp.auth;
 
 import eu.europa.ec.edelivery.smp.config.SMPSecurityConstants;
+import eu.europa.ec.edelivery.smp.data.enums.CredentialType;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.edelivery.smp.services.CredentialService;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.core.Authentication;
@@ -33,6 +35,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.util.Calendar;
 
 import static eu.europa.ec.edelivery.smp.utils.SMPCookieWriter.CSRF_COOKIE_NAME;
 import static eu.europa.ec.edelivery.smp.utils.SMPCookieWriter.SESSION_COOKIE_NAME;
@@ -49,9 +52,12 @@ public class SMPAuthenticationService {
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(SMPAuthenticationService.class);
 
     private final AuthenticationManager authenticationManager;
+    private final CredentialService credentialService;
 
-    public SMPAuthenticationService(@Qualifier(SMPSecurityConstants.SMP_UI_AUTHENTICATION_MANAGER_BEAN) AuthenticationManager authenticationManager) {
+    public SMPAuthenticationService(@Qualifier(SMPSecurityConstants.SMP_UI_AUTHENTICATION_MANAGER_BEAN) AuthenticationManager authenticationManager,
+                                    CredentialService credentialService) {
         this.authenticationManager = authenticationManager;
+        this.credentialService = credentialService;
     }
 
     @Transactional(noRollbackFor = AuthenticationException.class)
@@ -63,6 +69,30 @@ public class SMPAuthenticationService {
         return authentication;
     }
 
+
+    /**
+     * Method retrieves user credentials by username. First it validates if credentials have already active reset token
+     * and if not it creates new one.
+     *
+     * @param username
+     */
+    public void requestResetUsername(String username) {
+        LOG.info("requestResetUsername  [{}]", username);
+        // retrieve user Optional credentials by username
+        long startTime = Calendar.getInstance().getTimeInMillis();
+        credentialService.requestResetUsername(username);
+        // delay response to prevent timing attack
+        credentialService.delayResponse(CredentialType.USERNAME_PASSWORD, startTime);
+    }
+
+    public void resetUsernamePassword(String username, String resetToken, String newPassword) {
+        LOG.info("resetUsernamePassword  [{}]", username);
+        // retrieve user Optional credentials by username
+        long startTime = Calendar.getInstance().getTimeInMillis();
+        credentialService.resetUsernamePassword(username, resetToken, newPassword);
+        credentialService.delayResponse(CredentialType.USERNAME_PASSWORD, startTime);
+    }
+
     public void logout(HttpServletRequest request, HttpServletResponse response) {
         Authentication auth = SecurityContextHolder.getContext().getAuthentication();
         if (auth == null) {
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationController.java
index 2232814ab874a664db554fbfe32593b1ed353782..2f44e4ab6e0a7b9a74d2af18971ad1af40ab26ce 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationController.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationController.java
@@ -23,6 +23,9 @@ import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationService;
 import eu.europa.ec.edelivery.smp.auth.SMPAuthorizationService;
 import eu.europa.ec.edelivery.smp.auth.SMPUserDetails;
 import eu.europa.ec.edelivery.smp.auth.UILoginAuthenticationToken;
+import eu.europa.ec.edelivery.smp.data.enums.CredentialType;
+import eu.europa.ec.edelivery.smp.data.ui.CredentialRequestResetRO;
+import eu.europa.ec.edelivery.smp.data.ui.CredentialResetRO;
 import eu.europa.ec.edelivery.smp.data.ui.LoginRO;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
@@ -47,6 +50,9 @@ import static eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority.S_AUTHORITY_T
 import static eu.europa.ec.edelivery.smp.utils.SMPCookieWriter.SESSION_COOKIE_NAME;
 
 /**
+ * The AuthenticationController class is a REST controller that provides endpoints for user authentication actions as
+ * login, logout, logged user data retrieval, request credential reset.
+ *
  * @author Sebastian-Ion TINCU
  * @since 4.0
  */
@@ -81,7 +87,7 @@ public class AuthenticationController {
         this.csrfTokenRepository = csrfTokenRepository;
     }
 
-    @PostMapping(value = "authentication")
+    @PostMapping(value = ResourceConstants.PATH_ACTION_AUTHENTICATION)
     @Transactional(noRollbackFor = BadCredentialsException.class)
     public UserRO authenticate(@RequestBody LoginRO loginRO, HttpServletRequest request, HttpServletResponse response) {
         LOG.debug("Authenticating user [{}]", loginRO.getUsername());
@@ -98,7 +104,46 @@ public class AuthenticationController {
         return authorizationService.getUserData(user.getUser());
     }
 
-    @DeleteMapping(value = "authentication")
+    /**
+     * Request reset of the credentials. The method generates a reset token and sends an email to the user.
+     *
+     * @param requestResetRO - the request object containing the credential name and type
+     */
+    @PostMapping(value = ResourceConstants.PATH_ACTION_RESET_CREDENTIAL_REQUEST )
+    public void requestResetCredentials(@RequestBody CredentialRequestResetRO requestResetRO) {
+        LOG.debug("credentialRequestResetRO  [{}]", requestResetRO.getCredentialName());
+        if (requestResetRO.getCredentialType() == CredentialType.USERNAME_PASSWORD) {
+            authenticationService.requestResetUsername(requestResetRO.getCredentialName());
+        } else {
+            LOG.warn("Invalid or null credential type [{}] not supported for reset!",
+                    requestResetRO.getCredentialType());
+            throw new IllegalArgumentException("Invalid request!");
+
+        }
+    }
+
+    /**
+     * Reset the credentials. The method validates the reset token and updates the credentials.
+     *
+     * @param resetRO - the reset object containing the credential name, type, reset token and new credential value
+     */
+    @PostMapping(value = ResourceConstants.PATH_ACTION_RESET_CREDENTIAL )
+    public void resetCredentials(@RequestBody CredentialResetRO resetRO) {
+        LOG.debug("credentialResetRO  [{}]", resetRO.getCredentialName());
+        if (resetRO.getCredentialType() == CredentialType.USERNAME_PASSWORD) {
+
+            authenticationService.resetUsernamePassword(resetRO.getCredentialName(),
+                    resetRO.getResetToken(),
+                    resetRO.getCredentialValue());
+        } else {
+            LOG.warn("Invalid or null credential type [{}] not supported for reset!",
+                    resetRO.getCredentialType());
+            throw new IllegalArgumentException("Invalid request!");
+
+        }
+    }
+
+    @DeleteMapping(value = ResourceConstants.PATH_ACTION_AUTHENTICATION)
     public void logout(HttpServletRequest request, HttpServletResponse response) {
         LOG.info("Logging out user for the session");
         authenticationService.logout(request, response);
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
index d972175a2a2c9a587209b234a88151fc8e6072bb..69e900415da0f072f0ec599228f2b2b89aef0300 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
@@ -68,6 +68,9 @@ public class ResourceConstants {
     public static final String PATH_ACTION_PUT = "put";
     public static final String PATH_ACTION_VALIDATE = "validate";
     public static final String PATH_ACTION_GENERATE = "generate";
+    public static final String PATH_ACTION_RESET_CREDENTIAL_REQUEST = "request-reset-credential";
+    public static final String PATH_ACTION_RESET_CREDENTIAL = "reset-credential";
+    public static final String PATH_ACTION_AUTHENTICATION = "authentication";
 
     public static final String PATH_ACTION_RETRIEVE = "retrieve";
     public static final String PATH_ACTION_SEARCH = "search";
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationController.java
index ae839c0a25d099307c3bce9194b5311d39f43331..4e4e7e3898c49ba2a23e7dd135a7512f49e5fd50 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationController.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationController.java
@@ -82,6 +82,9 @@ public class ApplicationController {
             info.setSsoAuthenticationURI(configurationService.getCasSMPLoginRelativePath());
         }
         info.setContextPath(getRootContext());
+        // set additional public info
+        info.setPasswordValidationRegExp(configurationService.getPasswordPolicyRexExpPattern());
+        info.setPasswordValidationRegExpMessage(configurationService.getPasswordPolicyValidationMessage());
         return info;
     }
 
diff --git a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl
index a1ede38f7eedccbbf899acb07ddea25e0044df4b..7d12a7f04a010a51f8c3e199755756352ccf1411 100644
--- a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl
+++ b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl
@@ -125,6 +125,8 @@
         EXPIRE_ON datetime comment 'Date when password will expire',
         LAST_FAILED_LOGIN_ON datetime comment 'Last failed login attempt',
         CREDENTIAL_NAME varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin not null comment 'Unique username identifier. The Username must not be null',
+        RESET_EXPIRE_ON datetime comment 'Date time when reset token will expire',
+        RESET_TOKEN varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin comment 'Reset token for credential reset',
         LOGIN_FAILURE_COUNT integer comment 'Sequential login failure count',
         CREDENTIAL_VALUE varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin comment 'Credential value - it can be encrypted value',
         FK_USER_ID bigint not null,
@@ -147,6 +149,8 @@
         EXPIRE_ON datetime,
         LAST_FAILED_LOGIN_ON datetime,
         CREDENTIAL_NAME varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin,
+        RESET_EXPIRE_ON datetime,
+        RESET_TOKEN varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin,
         LOGIN_FAILURE_COUNT integer,
         CREDENTIAL_VALUE varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin,
         FK_USER_ID bigint,
diff --git a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl
index 97f8608698e1fe81a22f279af95c0926bec61c79..f9bcd64fd4194234675635ccc69c68dfb45b3545 100644
--- a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl
+++ b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl
@@ -194,6 +194,8 @@ create sequence SMP_USER_SEQ start with 1 increment by  1;
         EXPIRE_ON timestamp,
         LAST_FAILED_LOGIN_ON timestamp,
         CREDENTIAL_NAME varchar2(256 char) not null,
+        RESET_EXPIRE_ON timestamp,
+        RESET_TOKEN varchar2(256 char),
         LOGIN_FAILURE_COUNT number(10,0),
         CREDENTIAL_VALUE varchar2(256 char),
         FK_USER_ID number(19,0) not null,
@@ -236,6 +238,12 @@ create sequence SMP_USER_SEQ start with 1 increment by  1;
     comment on column SMP_CREDENTIAL.CREDENTIAL_NAME is
         'Unique username identifier. The Username must not be null';
 
+    comment on column SMP_CREDENTIAL.RESET_EXPIRE_ON is
+        'Date time when reset token will expire';
+
+    comment on column SMP_CREDENTIAL.RESET_TOKEN is
+        'Reset token for credential reset';
+
     comment on column SMP_CREDENTIAL.LOGIN_FAILURE_COUNT is
         'Sequential login failure count';
 
@@ -258,6 +266,8 @@ create sequence SMP_USER_SEQ start with 1 increment by  1;
         EXPIRE_ON timestamp,
         LAST_FAILED_LOGIN_ON timestamp,
         CREDENTIAL_NAME varchar2(256 char),
+        RESET_EXPIRE_ON timestamp,
+        RESET_TOKEN varchar2(256 char),
         LOGIN_FAILURE_COUNT number(10,0),
         CREDENTIAL_VALUE varchar2(256 char),
         FK_USER_ID number(19,0),