diff --git a/javascript/src/constants/statuses.js b/javascript/src/constants/statuses.js
index 64fe340b5b9cbac714070c61ae1a3bceba23af3e..856d7c47f82097c8156b9f08e235e8a50a0a19c2 100644
--- a/javascript/src/constants/statuses.js
+++ b/javascript/src/constants/statuses.js
@@ -1 +1,2 @@
 export const STATUS_DEVICE_REVOKED = "Device revoked";
+export const STATUS_USER_NOT_ACTIVATED = 'User not activated';
diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js
index 04dd65b8cd79c14376d1d9d977cdfc5332b98fae..f82a7e7bc1b6c1896f20cc7703d4c0f16569f5a7 100644
--- a/javascript/src/iframe/viamapi-iframe.js
+++ b/javascript/src/iframe/viamapi-iframe.js
@@ -1,8 +1,5 @@
 import '../lib/textencoder.polyfill';
-import {
-  parseSMIME,
-  prepareVCardParts
-} from "../utilities/emailUtilities";
+import { parseSMIME, prepareVCardParts } from "../utilities/emailUtilities";
 import {
   stringToUtf8ByteArray,
   utf8ByteArrayToString,
@@ -30,15 +27,19 @@ import {
   createOneTimePassportCertificate,
   createPassportCertificate,
   decryptMessage,
-  encryptMessage, parseCertificate,
+  encryptMessage,
+  parseCertificate,
   signEmail,
   verifySMIME
 } from "../utilities/signingUtilities";
 import { signPdf } from "../utilities/pdfUtilities";
 import CryptoData from "../CryptoData";
 import Identity from "../Identity";
-import { STATUS_DEVICE_REVOKED } from "../constants/statuses";
-import generateQrCode from '../utilities/generateQrCode';
+import {
+  STATUS_DEVICE_REVOKED,
+  STATUS_USER_NOT_ACTIVATED
+} from "../constants/statuses";
+import generateQrCode from "../utilities/generateQrCode";
 
 const penpalMethods = require("../../temp/penpal-methods").default;
 const WopiAPI = require("./wopiapi-iframe");
@@ -319,6 +320,20 @@ async function executeRestfulFunction(type, that, fn, config, ...args) {
     return response.data;
   }
 
+  const userNotActivated =
+    type === "private" &&
+    code === "400" &&
+    status === STATUS_USER_NOT_ACTIVATED;
+
+  if (userNotActivated) {
+    destroyIdentity();
+
+    const event = createEvent("", "UserNotActivated");
+    iframeParent.onEvent(event);
+
+    return response.data;
+  }
+
   const badSession =
     type === "private" &&
     identity &&
@@ -538,14 +553,9 @@ const connection = Penpal.connectToParent({
           newIdentity.setPinCode(pinCode);
 
           window.currentlyLoadedIdentity = newIdentity;
-          const {
-            publicKey,
-            x509Certificate
-          } = newIdentity.authentication;
+          const { publicKey, x509Certificate } = newIdentity.authentication;
 
-          window.loadedIdentities[
-            publicKey
-          ] = newIdentity;
+          window.loadedIdentities[publicKey] = newIdentity;
           extendPinCodeTtl(newIdentity.authentication.publicKey, pinCode);
 
           window.viamAnonymousApi.setIdentity(
@@ -1092,7 +1102,7 @@ const connection = Penpal.connectToParent({
         );
       });
     },
-    verifySMIME: async (smimeString) => {
+    verifySMIME: async smimeString => {
       const authenticationPublicKey = localStorage.getItem(
         "authenticatedIdentity"
       );
@@ -1121,10 +1131,16 @@ const connection = Penpal.connectToParent({
       const rootCaPem = rootCaResponse.data;
       const verificationResult = await verifySMIME(smimeString, rootCaPem);
 
-      return encodeResponse("200", verificationResult.verified, verificationResult.message);
+      return encodeResponse(
+        "200",
+        verificationResult.verified,
+        verificationResult.message
+      );
     },
     validateDocument: async (documentUUID, contentType) => {
-      const authenticationPublicKey = localStorage.getItem("authenticatedIdentity");
+      const authenticationPublicKey = localStorage.getItem(
+        "authenticatedIdentity"
+      );
 
       if (
         !authenticationPublicKey ||
@@ -1140,7 +1156,8 @@ const connection = Penpal.connectToParent({
         window.viamApi.documentValidateDocumentByUUID,
         null,
         documentUUID,
-        contentType);
+        contentType
+      );
 
       if (validateDocumentResponse.code !== "200") {
         return encodeResponse("400", "", validateDocumentResponse.status);
@@ -1149,11 +1166,13 @@ const connection = Penpal.connectToParent({
       const signatures = validateDocumentResponse.data;
       if (signatures) {
         for (const signature of signatures) {
-          const certificateChain = signature.certificateChainPEM.map((certificatePEM) => {
-            const certificate = parseCertificate(certificatePEM);
-            const certificateData = new CertificateData(certificate);
-            return certificateData;
-          });
+          const certificateChain = signature.certificateChainPEM.map(
+            certificatePEM => {
+              const certificate = parseCertificate(certificatePEM);
+              const certificateData = new CertificateData(certificate);
+              return certificateData;
+            }
+          );
           signature.certificateChain = certificateChain;
         }
       }
@@ -1352,7 +1371,11 @@ const connection = Penpal.connectToParent({
 
       return encodeResponse("200", "", "Document signed");
     },
-    signDocumentJava: async (passportUUID, documentUUID, documentContentType) => {
+    signDocumentJava: async (
+      passportUUID,
+      documentUUID,
+      documentContentType
+    ) => {
       const authenticationPublicKey = localStorage.getItem(
         "authenticatedIdentity"
       );
@@ -1445,7 +1468,14 @@ const connection = Penpal.connectToParent({
     //   body: String if it is a text part (Content-Type = "text/...") or Uint8Array otherwise; filled for leaf MIME nodes
     //   parts: array of instances of the same object; filled for container MIME nodes (Content-Type = "multipart/...")
     // }
-    signVCard: async (passportUUID, senderEmail, attribs, textBody, htmlBody, parts) => {
+    signVCard: async (
+      passportUUID,
+      senderEmail,
+      attribs,
+      textBody,
+      htmlBody,
+      parts
+    ) => {
       const authenticationPublicKey = localStorage.getItem(
         "authenticatedIdentity"
       );
@@ -1490,15 +1520,17 @@ const connection = Penpal.connectToParent({
       }
 
       let qrCodeImageData;
-      let qrCodeCoordinates = {fromL: -1,
-        fromR: -1,
-        toL: -1,
-        toR: -1};
+      let qrCodeCoordinates = { fromL: -1, fromR: -1, toL: -1, toR: -1 };
 
-      if (vCardImageClaimValue && "state" in vCardImageClaimValue && vCardImageClaimValue.state === "disabled") {
+      if (
+        vCardImageClaimValue &&
+        "state" in vCardImageClaimValue &&
+        vCardImageClaimValue.state === "disabled"
+      ) {
         vCardImageData = new ImageData({
           contentType: "image/png",
-          contentBase64: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel
+          contentBase64:
+            "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" //1x1px transparent pixel
         });
       } else {
         const vCardImageResponse = await executeRestfulFunction(
@@ -1516,17 +1548,21 @@ const connection = Penpal.connectToParent({
         }
         vCardImageData = new ImageData(vCardImageResponse.data.Image);
         if (vCardImageData.contentType !== "image/png") {
-          return encodeResponse("400", "", "Content type of vCard mmust be 'image/png'");
+          return encodeResponse(
+            "400",
+            "",
+            "Content type of vCard mmust be 'image/png'"
+          );
         }
 
         qrCodeCoordinates = vCardImageResponse.data.QRCodeCoordinates;
-        const qrCodeBase64Content = await generateQrCode("https://" + location.host + "/check/" + messageUUID);
-        qrCodeImageData = new ImageData(
-          {
-            contentType: "image/png",
-            content: qrCodeBase64Content
-          }
+        const qrCodeBase64Content = await generateQrCode(
+          "https://" + location.host + "/check/" + messageUUID
         );
+        qrCodeImageData = new ImageData({
+          contentType: "image/png",
+          content: qrCodeBase64Content
+        });
       }
 
       if (typeof parts === "undefined" || parts === null) {
@@ -1545,7 +1581,9 @@ const connection = Penpal.connectToParent({
         };
         parts.unshift(htmlPart);
       } else {
-        console.log("Html body is not passed to signVCard, its value is ", {html: htmlBody});
+        console.log("Html body is not passed to signVCard, its value is ", {
+          html: htmlBody
+        });
       }
 
       if (textBody) {
@@ -1560,10 +1598,12 @@ const connection = Penpal.connectToParent({
         };
         parts.unshift(textPart);
       } else {
-        console.log("Text body is not passed to signVCard, its value is ", {text: textBody});
+        console.log("Text body is not passed to signVCard, its value is ", {
+          text: textBody
+        });
       }
 
-      const count = prepareVCardParts(parts);
+      const count = await prepareVCardParts(parts);
       if (count.textParts === 0) {
         return encodeResponse("400", "", "No text parts passed to signVCard");
       }
@@ -1616,17 +1656,21 @@ const connection = Penpal.connectToParent({
         parts,
         vCardAttribs,
         qrCodeImageData,
-        qrCodeCoordinates,
+        qrCodeCoordinates
       );
       if (signVCardResponse.code !== "200") {
         return encodeResponse("400", "", signVCardResponse.status);
       }
 
       const signedVCardImageData = new ImageData(signVCardResponse.data);
-      return encodeResponse("200", {
-        image: signedVCardImageData,
-        messageUUID
-      }, "vCard signed");
+      return encodeResponse(
+        "200",
+        {
+          image: signedVCardImageData,
+          messageUUID: messageUUID
+        },
+        "vCard signed"
+      );
     },
     // mime - String - the MIME of the email message
     // vCardAttribs - optional attributes for the verification procedure in format
@@ -1660,19 +1704,25 @@ const connection = Penpal.connectToParent({
       }
 
       const validationResult = validateVMimeResponse.data;
-      const {signatures} = validationResult;
+      const { signatures } = validationResult;
       if (signatures) {
         for (const signature of signatures) {
-          const certificateChain = signature.certificateChainPEM.map((certificatePEM) => {
-            const certificate = parseCertificate(certificatePEM);
-            const certificateData = new CertificateData(certificate);
-            return certificateData;
-          });
+          const certificateChain = signature.certificateChainPEM.map(
+            certificatePEM => {
+              const certificate = parseCertificate(certificatePEM);
+              const certificateData = new CertificateData(certificate);
+              return certificateData;
+            }
+          );
           signature.certificateChain = certificateChain;
         }
       }
 
-      return encodeResponse("200", validationResult, "Validation result retrieved");
+      return encodeResponse(
+        "200",
+        validationResult,
+        "Validation result retrieved"
+      );
     },
     generateQrCode,
     documentCreateDocument: async (passportUUID, path, contentType, title) => {
@@ -1980,7 +2030,10 @@ const connection = Penpal.connectToParent({
 
       const resourceID = createDocumentResult.data;
 
-      const accessTokenResponse = await wopiAPI.getAccessToken(passportUUID, resourceID);
+      const accessTokenResponse = await wopiAPI.getAccessToken(
+        passportUUID,
+        resourceID
+      );
 
       if (accessTokenResponse.data.code !== "200") {
         return accessTokenResponse.data;
@@ -2009,7 +2062,11 @@ const connection = Penpal.connectToParent({
         return encodeResponse("400", "", "Identity not authenticated");
       }
 
-      const response = await wopiAPI.getAccessToken(passportUUID, resourceID, contentType);
+      const response = await wopiAPI.getAccessToken(
+        passportUUID,
+        resourceID,
+        contentType
+      );
       return response.data;
     },
 
diff --git a/javascript/src/utilities/emailUtilities.js b/javascript/src/utilities/emailUtilities.js
index 988f879940b4bd1cac8eb118367d6e8f7ff05413..1a696a1b566be6ea55bab5d3788584327c41bd77 100644
--- a/javascript/src/utilities/emailUtilities.js
+++ b/javascript/src/utilities/emailUtilities.js
@@ -17,8 +17,10 @@ import {
 } from "./signingUtilities";
 import {
   byteArrayToBase64,
-  stringToUtf8Base64
+  stringToUtf8Base64,
+  stringToUtf8ByteArray
 } from "./stringUtilities";
+import {getCrypto} from "pkijs";
 
 export const SIGNATURE_CONTENT_TYPE = "application/pkcs7-signature";
 export const DEFAULT_ATTACHMENT_NAME = "attachment";
@@ -150,14 +152,52 @@ const capitalizeFirstLetter = (s) => {
   return s.charAt(0).toUpperCase() + s.slice(1);
 };
 
-export function prepareVCardParts(parts) {
-  if (!parts) {
-    return;
+async function sha256(array) {
+  const cryptoLib = getCrypto();
+  const digestTmpBuf = await cryptoLib.digest({ name: "SHA-256" }, array);
+  const digestTmpArray = new Uint8Array(digestTmpBuf);
+  return digestTmpArray;
+}
+
+async function hashBody(part) {
+  const contentType = part.headers["Content-Type"];
+  const origContentType = part.headers["Original-Content-Type"];
+
+  if (!origContentType &&
+      !part.headers["Content-Type"].startsWith("application/hash") &&
+      !part.headers["Content-Type"].startsWith("text/plain") &&
+      !part.headers["Content-Type"].startsWith("text/html")) {
+    if (part.body) {
+      if (typeof part.body === "string") {
+        part.body = stringToUtf8ByteArray(part.body);
+      }
+      if (part.body instanceof ArrayBuffer) {
+        part.body = byteArrayToBase64(new Uint8Array(part.body));
+      }
+      if (!(part.body instanceof Uint8Array)) {
+        throw new Error('part body is neither string, nor Uint8Array, nor ArrayBuffer'); // should not happen
+      }
+
+      if (contentType) {
+        part.headers["Original-Content-Type"] = contentType;
+      }
+      part.headers["Content-Type"] = "application/hash; algorithm=SHA-256";
+
+      part.body = await sha256(part.body);
+    }
   }
+}
+
+export async function prepareVCardParts(parts) {
   const count = {
     textParts: 0,
     htmlParts: 0
   };
+
+  if (!parts) {
+    return count;
+  }
+
   for (const part of parts) {
     if (!part.headers) {
       part.headers = {
@@ -169,17 +209,18 @@ export function prepareVCardParts(parts) {
         capitalizedHeaders[capitalizeHeaderName(key)] = part.headers[key];
       }
       part.headers = capitalizedHeaders;
-      try {
+      if (!part.headers["Content-Type"]) {
+        part.headers["Content-Type"] = "application/octet-stream";
+      } else {
         if (part.headers["Content-Type"].startsWith("text/plain")) {
           count.textParts++;
         } else if (part.headers["Content-Type"].startsWith("text/html")) {
           count.htmlParts++;
         }
-      } catch (ignore) {
-        //ignore
       }
     }
     if (part.body) {
+      await hashBody(part);
       if (typeof part.body === "string") {
         part.body = stringToUtf8Base64(part.body);
       } else
@@ -193,7 +234,7 @@ export function prepareVCardParts(parts) {
       }
     }
     if (part.parts) {
-      const subcount = prepareVCardParts(part.parts);
+      const subcount = await prepareVCardParts(part.parts);
       count.textParts += subcount.textParts;
       count.htmlParts += subcount.htmlParts;
     }