diff --git a/javascript/src/helpers/mailparser.js b/javascript/src/helpers/mailparser.js
index 9bd873ff9ba1d20c06bd890a4bd525e640c378ec..a6da68a5fb223932afe77acc67fc3d7149711e4e 100644
--- a/javascript/src/helpers/mailparser.js
+++ b/javascript/src/helpers/mailparser.js
@@ -61,7 +61,7 @@ function calculateParts(body, from, to, previousBondary) {
   let boundary = findFirstBoundary(body, from, to);
 
   if (boundary == null) {
-    return [{ indices: { from: from, to: to }, boundary: previousBondary }];
+    return [{ indices: { from: from, to: to }, boundary: previousBondary, leaf: true }];
   }
 
   const realBoundary = boundary;
@@ -78,6 +78,9 @@ function calculateParts(body, from, to, previousBondary) {
   }
 
   let bodies = [];
+  if (previousBondary !== null) {
+    bodies.push({indices: {from: from, to: to}, boundary: previousBondary, leaf: false});
+  }
 
   for (let i = 0; i < boundaryIndicesLength - 1; i++) {
     const firstPair = boundaryPairs[i];
@@ -155,13 +158,14 @@ export function parseMIME(mime) {
   parts.push({
     indices: { from: 0, to: mime.length, headersEnd: headersEnd },
     headers,
-    boundary: "mimemessage"
+    boundary: "mimemessage",
+    leaf: false
   });
 
   return parts;
 }
 
-function getHeaderValue(header, part) {
+export function getHeaderValue(header, part) {
   if (part.headers && part.headers[header] && part.headers[header].length) {
     return part.headers[header];
   }
diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js
index efd6fe262831e165c52e6723ba09232701b48b6a..428d5ea7b0312c7ef7c918c3e3908e6cfebf01d3 100644
--- a/javascript/src/iframe/viamapi-iframe.js
+++ b/javascript/src/iframe/viamapi-iframe.js
@@ -24,7 +24,8 @@ import {
   createPassportCertificate,
   decryptMessage,
   encryptMessage,
-  signEmail
+  signEmail,
+  verifySMIME
 } from "../utilities/signingUtilities";
 import { signPdf } from "../utilities/pdfUtilities";
 import CryptoData from "../CryptoData";
@@ -1051,6 +1052,37 @@ const connection = Penpal.connectToParent({
         );
       });
     },
+    verifySMIME: async (smimeString) => {
+      const authenticationPublicKey = localStorage.getItem(
+        "authenticatedIdentity"
+      );
+
+      if (
+        !authenticationPublicKey ||
+        !window.loadedIdentities[authenticationPublicKey] ||
+        !extendPinCodeTtl(authenticationPublicKey)
+      ) {
+        return encodeResponse("400", "", "Identity not authenticated");
+      }
+
+      //TODO cache (for some time) the root certificate
+      // either as PEM or as certificate object (preferred)
+      const rootCaResponse = await executeRestfulFunction(
+        "private",
+        window.viamApi,
+        window.viamApi.signRetrieveRootCertificate,
+        null
+      );
+
+      if (rootCaResponse.code !== "200") {
+        return encodeResponse("400", "", rootCaResponse.status);
+      }
+
+      const rootCaPem = rootCaResponse.data;
+      const verificationResult = await verifySMIME(smimeString, rootCaPem);
+
+      return encodeResponse("200", verificationResult.verified, verificationResult.message);
+    },
     signEmail: async (passportUUID, emailArg, emailMessage) => {
       const authenticationPublicKey = localStorage.getItem(
         "authenticatedIdentity"
diff --git a/javascript/src/utilities/emailUtilities.js b/javascript/src/utilities/emailUtilities.js
index df59737b20636ffca4b5b5431c024be65ff6668f..70ebc48aa9aab0afb438de858f4d017d6fa5d9d7 100644
--- a/javascript/src/utilities/emailUtilities.js
+++ b/javascript/src/utilities/emailUtilities.js
@@ -11,9 +11,12 @@ import {
   getAttachment,
   getGlobalHeaderValue
 } from "../helpers/mailparser";
-import { getCertificateChain } from "./signingUtilities";
+import {
+  getCertificateChain,
+  parseSignedData
+} from "./signingUtilities";
 
-const SIGNATURE_CONTENT_TYPE = "application/pkcs7-signature";
+export const SIGNATURE_CONTENT_TYPE = "application/pkcs7-signature";
 export const DEFAULT_ATTACHMENT_NAME = "attachment";
 
 const splitParticipants = participantsList => {
@@ -44,7 +47,7 @@ export const parseSMIME = smimeString => {
           rawAttachment
         );
 
-        if (contentType.indexOf(SIGNATURE_CONTENT_TYPE) !== -1) {
+        if (contentType.startsWith(SIGNATURE_CONTENT_TYPE)) {
           signatureBase64 = base64;
         }
 
@@ -58,7 +61,14 @@ export const parseSMIME = smimeString => {
         });
       }
 
-      const certificateChain = getCertificateChain(signatureBase64);
+      let certificateChain;
+      if (signatureBase64) {
+        const signedData = parseSignedData(signatureBase64);
+        if (signedData) {
+          //TODO revise and use signedData's generation of cert chain (per signer)
+          certificateChain = getCertificateChain(signedData);
+        }
+      }
 
       const from = splitParticipants(getGlobalHeaderValue("from", parts));
       const to = splitParticipants(getGlobalHeaderValue("to", parts));
diff --git a/javascript/src/utilities/signingUtilities.js b/javascript/src/utilities/signingUtilities.js
index 27d23e4c4484f13701f2058cc1d4c974d0c507b2..db47ed62ed7c1c3fd455405cd95092a84a7129ff 100644
--- a/javascript/src/utilities/signingUtilities.js
+++ b/javascript/src/utilities/signingUtilities.js
@@ -4,10 +4,28 @@ import {
   getTimeLeftInLocalStorage,
   makeid
 } from "./appUtility";
-import { bufferToHexCodes, stringToArrayBuffer } from "pvutils";
+import {
+  bufferToHexCodes,
+  stringToArrayBuffer,
+  isEqualBuffer
+} from "pvutils";
 import { fromBER } from "asn1js";
 import { ContentInfo, SignedData } from "pkijs";
 import { algomap, rdnmap } from "../constants/certificates";
+import {
+  fixNewLines,
+  getAttachment,
+  getAttachments,
+  getGlobalHeaderValue,
+  getHeaderValue,
+  parseMIME
+} from "../helpers/mailparser";
+import dataUriToBlob from "data-uri-to-blob";
+import {
+  extractHtmlBodyFromString,
+  getFilenameFromHeaders,
+  SIGNATURE_CONTENT_TYPE
+} from "./emailUtilities";
 
 const libmime = require("libmime");
 const pkijs = require("pkijs");
@@ -1006,7 +1024,7 @@ function makeBoundary() {
   return "W0RyLiBEYW15YW4gTWl0ZXZd--" + makeid(len);
 }
 
-export const parseCertificates = signatureBase64 => {
+export const parseSignedData = signatureBase64 => {
   try {
     const certificateDecoded = atob(signatureBase64);
     const buffer = stringToArrayBuffer(certificateDecoded);
@@ -1014,7 +1032,15 @@ export const parseCertificates = signatureBase64 => {
 
     const contentInfo = new ContentInfo({ schema: asn1.result });
     const signedData = new SignedData({ schema: contentInfo.content });
+    return signedData;
+  } catch (e) {
+    console.error("Error parsing signed data:", e);
+    return null;
+  }
+};
 
+export const parseCertificates = signedData => {
+  try {
     return signedData.certificates.map((certificate, index) => {
       const certificateData = { issuer: {}, subject: {}, validity: {} };
       const serialNumber = bufferToHexCodes(
@@ -1064,11 +1090,11 @@ export const parseCertificates = signatureBase64 => {
   }
 };
 
-export const getCertificateChain = signatureBase64 => {
+export const getCertificateChain = signedData => {
   const certificateChain = [];
 
   try {
-    const certificates = parseCertificates(signatureBase64);
+    const certificates = parseCertificates(signedData);
 
     // Add first certificate in the chain
     certificateChain.push(certificates[0]);
@@ -1087,3 +1113,142 @@ export const getCertificateChain = signatureBase64 => {
 
   return certificateChain;
 };
+
+const isVereignSignature = (signerInfo, signerVerificationResult) => {
+  const signerCert = signerVerificationResult.signerCertificate;
+
+  for (const typeAndValue of signerCert.subject.typesAndValues) {
+    try {
+      if (typeAndValue.type === "2.5.4.10" &&
+          typeAndValue.value.valueBlock.value === "Vereign AG"
+      ) {
+        return true;
+      }
+    } catch (ignore) {}
+  }
+
+  return false;
+};
+
+export const verifySMIME = (smimeString, rootCaPem) => {
+  return new Promise(resolve => {
+    setTimeout(async () => {
+      const emailString = fixNewLines(smimeString);
+      const parts = parseMIME(emailString);
+
+      let signatureBase64;
+      let signatureBoundary;
+
+      for (const part of parts) {
+        let contentType = getHeaderValue("content-type", part);
+        if (!contentType) {
+          continue;
+        }
+        contentType = contentType[0];
+
+        if (contentType && contentType.startsWith(SIGNATURE_CONTENT_TYPE)) {
+          signatureBase64 = getAttachment(emailString, part).base64;
+          signatureBoundary = part.boundary;
+          break;
+        }
+      }
+
+      const verificationResult = {
+        verified: false,
+        message: "",
+        vereignSignatures: 0,
+        nonVereignSignatures: 0
+      };
+
+      if (!signatureBase64) {
+        verificationResult.message = "Not a signed MIME";
+        resolve(verificationResult);
+        return;
+      }
+
+      const dataPart = parts[0];
+      if (dataPart.boundary !== signatureBoundary) {
+        verificationResult.message = "Invalid SMIME format: wrong boundary on first MIME part";
+        resolve(verificationResult);
+        return;
+      }
+
+      const data = emailString.slice(
+        dataPart.indices.from,
+        dataPart.indices.to
+      );
+      const dataBuffer = stringToArrayBuffer(data);
+
+      const rootCa = parseCertificate(rootCaPem);
+      if (rootCa.tbs.byteLength === 0) {
+        rootCa.tbs = rootCa.encodeTBS();
+      }
+
+      const signedData = parseSignedData(signatureBase64);
+      if (!signedData) {
+        verificationResult.message = "Corrupt SMIME signature";
+        resolve(verificationResult);
+        return;
+      }
+
+      for (let i = 0; i < signedData.signerInfos.length; i++) {
+        let signerResult;
+        try {
+          signerResult = await signedData.verify({
+            signer: i,
+            data: dataBuffer,
+            trustedCerts: [rootCa],
+            checkDate: new Date(),
+            checkChain: true,
+            extendedMode: true,
+            passedWhenNotRevValues: false
+          });
+        } catch (e) {
+          verificationResult.message = e.message;
+          resolve(verificationResult);
+          return;
+        }
+
+        const signerVerified = !!signerResult.signatureVerified && !!signerResult.signerCertificateVerified;
+
+        if (!signerVerified) {
+          if (signerResult.message) {
+            verificationResult.message = signerResult.message;
+          } else {
+            verificationResult.message = "Message integrity is compromised";
+          }
+          resolve(verificationResult);
+          return;
+        }
+
+        if (isVereignSignature(signedData.signerInfos[i], signerResult)) {
+          const signerPath = signerResult.certificatePath;
+          const signerRoot = signerPath[signerPath.length - 1];
+          if (signerRoot.tbs.byteLength === 0) {
+            signerRoot.tbs = signerRoot.encodeTBS();
+          }
+          if (!isEqualBuffer(signerRoot.tbs, rootCa.tbs)) {
+            verificationResult.message =
+              `Vereign signature ${i} has root certificate, different from Vereign root CA`;
+            resolve(verificationResult);
+            return;
+          }
+          verificationResult.vereignSignatures++;
+        } else {
+          verificationResult.nonVereignSignatures++;
+        }
+      }
+
+      if (signedData.signerInfos.length === 0) {
+        verificationResult.message = "No signatures found";
+      } else
+      if (verificationResult.vereignSignatures === 0) {
+        verificationResult.message = "Verified succesfully, but no Vereign signatures found";
+      } else {
+        verificationResult.message = "Verified succesfully";
+      }
+      verificationResult.verified = true;
+      resolve(verificationResult);
+    }, 50);
+  });
+};